summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2019-03-29 00:00:11 +0100
committerRuben Undheim <ruben.undheim@gmail.com>2019-03-29 00:00:11 +0100
commit6089b1f3dab7b7d60a8ea4bcec47bdec3560c5b4 (patch)
treeccf9fe6e50c78dcfd6e2b1f63b0bdfd8c7ab7d3f
parent865a8002848550990b963870cca74c0a51426047 (diff)
New upstream version 1.4.49
-rw-r--r--Makefile148
-rw-r--r--Makefile.in2
-rw-r--r--README11
-rw-r--r--VERSION2
-rw-r--r--antenna.c1308
-rw-r--r--config.log499
-rwxr-xr-xconfig.status942
-rw-r--r--def.c545
-rw-r--r--def.h5
-rw-r--r--delays.c280
-rw-r--r--graphics.c52
-rw-r--r--lef.c1353
-rw-r--r--lef.h65
-rw-r--r--mask.c105
-rw-r--r--mask.h1
-rw-r--r--maze.c504
-rw-r--r--node.c1165
-rw-r--r--node.h4
-rw-r--r--output.c1443
-rw-r--r--output.h2
-rw-r--r--qconfig.c159
-rw-r--r--qconfig.h25
-rw-r--r--qrouter.c442
-rw-r--r--qrouter.h45
-rw-r--r--[-rwxr-xr-x]qrouter.sh.in0
-rw-r--r--qrouter.tcl.in11
-rw-r--r--tclqrouter.c418
27 files changed, 7680 insertions, 1856 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..01a61f0
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,148 @@
+#
+# qrouter Makefile
+#
+
+# Main compiler arguments
+CFLAGS += -g
+CPPFLAGS = -m64 -fPIC
+DEFS = -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DHAVE_LIBXT=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_SYS_MMAN_H=1 -DTCL_QROUTER=1 -DLINUX=1 -DSYSV=1 -DVERSION=\"1.4\" -DREVISION=\"7\"
+STUB_DEFS = -DUSE_TCL_STUBS -DUSE_TK_STUBS
+LIBS = -lXt
+LDFLAGS +=
+LDDL_FLAGS = -shared -Wl,-soname,$@ -Wl,--version-script=symbol.map
+LD_RUN_PATH =
+SHLIB_CFLAGS = -fPIC
+LIB_SPECS_NOSTUB = -L/usr/lib64 -ltk8.6 -L/usr/lib64 -ltcl8.6
+LIB_SPECS = -L/usr/lib64 -ltkstub8.6 -L/usr/lib64 -ltclstub8.6
+INC_SPECS =
+TCL_LIB_DIR = /usr/lib64
+TK_LIB_DIR = /usr/lib64
+EXTRA_LIB_SPECS = -ldl
+INSTALL = /usr/bin/install -c
+SHDLIB_EXT = .so
+EXEEXT =
+X_LIBS =
+X_EXTRA_LIBS =
+X_PRE_LIBS = -lSM -lICE
+QROUTER_LIB_DIR = share/qrouter
+WISH_EXE = /usr/bin/wish
+VERSION = 1.4
+REVISION = 7
+prefix = /usr/local
+
+INSTALL_TARGET := install-tcl
+ALL_TARGET := tcl
+
+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 antenna.c
+OBJECTS2 := $(patsubst %.c,%.o,$(SOURCES2))
+
+SOURCES3 = qrouterexec.c
+OBJECTS3 := $(patsubst %.c,%.o,$(SOURCES3))
+
+SOURCES4 = qrouternullg.c
+OBJECTS4 := $(patsubst %.c,%.o,$(SOURCES4))
+
+SOURCES5 = main.c
+OBJECTS5 := $(patsubst %.c,%.o,$(SOURCES5))
+
+BININSTALL = ${prefix}/bin
+LIBINSTALL = ${prefix}/${QROUTER_LIB_DIR}
+EXTRA_DEFS = -DQROUTER_PATH=\"${LIBINSTALL}\"
+
+all: $(ALL_TARGET)
+
+install: $(INSTALL_TARGET)
+
+nointerp: qrouter$(EXEEXT)
+
+tcl: qrouter.sh qrouter.tcl qrouter$(SHDLIB_EXT) qrouterexec$(EXEEXT) \
+ qrouternullg$(EXEEXT)
+
+qrouter.tcl: qrouter.tcl.in
+ sed -e '/LIBDIR/s#LIBDIR#${LIBINSTALL}#' \
+ -e '/VERSION/s#VERSION#${VERSION}#' \
+ -e '/REVISION/s#REVISION#${REVISION}#' \
+ qrouter.tcl.in > $@
+
+qrouter.sh: qrouter.sh.in
+ sed -e '/WISH_EXE/s#WISH_EXE#${WISH_EXE}#' \
+ -e '/LIBDIR/s#LIBDIR#${LIBINSTALL}#' \
+ qrouter.sh.in > $@
+ chmod 0755 $@
+
+qrouter$(EXEEXT): $(OBJECTS) $(OBJECTS5)
+ $(CC) $(LDFLAGS) $(OBJECTS) $(OBJECTS5) -o $@ $(LIBS) -lm
+
+qrouter$(SHDLIB_EXT): $(OBJECTS) $(OBJECTS2)
+ $(RM) qrouter$(SHDLIB_EXT)
+ $(CC) ${CFLAGS} ${STUB_DEFS} ${SHLIB_CFLAGS} -o $@ \
+ ${LDDL_FLAGS} $(OBJECTS) $(OBJECTS2) \
+ ${LDFLAGS} -lc ${LIBS} ${X_PRE_LIBS} -lX11 ${X_LIBS} \
+ ${X_EXTRA_LIBS} ${LIB_SPECS} ${EXTRA_LIB_SPECS} -lm
+
+qrouterexec$(EXEEXT): $(OBJECTS3)
+ $(RM) qrouterexec$(EXEEXT)
+ $(CC) ${CFLAGS} ${CPPFLAGS} ${DEFS} ${EXTRA_DEFS} \
+ ${SOURCES3} ${INC_SPECS} -o $@ ${LIB_SPECS_NOSTUB} \
+ ${LD_RUN_PATH} ${LDFLAGS} ${X_PRE_LIBS} -lX11 ${X_LIBS} \
+ ${X_EXTRA_LIBS} ${LIBS} ${EXTRA_LIB_SPECS} -lm
+
+qrouternullg$(EXEEXT): $(OBJECTS4)
+ $(RM) qrouternullg$(EXEEXT)
+ $(CC) ${CFLAGS} ${CPPFLAGS} ${DEFS} ${EXTRA_DEFS} \
+ ${SOURCES4} ${INC_SPECS} -o $@ ${LIB_SPECS_NOSTUB} \
+ ${LD_RUN_PATH} ${LDFLAGS} ${LIBS} ${EXTRA_LIB_SPECS} -lm
+
+install-nointerp:
+ @echo "Installing qrouter"
+ $(INSTALL) -d $(DESTDIR)${BININSTALL}
+ $(INSTALL) qrouter $(DESTDIR)${BININSTALL}
+
+install-tcl: qrouter.sh qrouter.tcl qrouter$(SHDLIB_EXT) \
+ qrouterexec$(EXEEXT) qrouternullg$(EXEEXT)
+ @echo "Installing qrouter"
+ $(INSTALL) -d $(DESTDIR)${BININSTALL}
+ $(INSTALL) -d $(DESTDIR)${LIBINSTALL}
+ $(INSTALL) qrouter.sh $(DESTDIR)${BININSTALL}/qrouter
+ $(INSTALL) qrouter$(SHDLIB_EXT) $(DESTDIR)${LIBINSTALL}
+ $(INSTALL) qrouterexec$(EXEEXT) $(DESTDIR)${LIBINSTALL}
+ $(INSTALL) qrouternullg$(EXEEXT) $(DESTDIR)${LIBINSTALL}
+ $(INSTALL) console.tcl $(DESTDIR)${LIBINSTALL}
+ $(INSTALL) tkcon.tcl $(DESTDIR)${LIBINSTALL}
+ $(INSTALL) qrouter.tcl $(DESTDIR)${LIBINSTALL}
+
+uninstall:
+ $(RM) $(DESTDIR)${BININSTALL}/qrouter
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(OBJECTS2)
+ $(RM) $(OBJECTS3)
+ $(RM) $(OBJECTS4)
+ $(RM) $(OBJECTS5)
+ $(RM) qrouterexec$(EXEEXT)
+ $(RM) qrouternullg$(EXEEXT)
+ $(RM) qrouter$(EXEEXT)
+ $(RM) qrouter$(SHDLIB_EXT)
+ $(RM) qrouter.tcl
+ $(RM) qrouter.sh
+
+veryclean:
+ $(RM) $(OBJECTS)
+ $(RM) $(OBJECTS2)
+ $(RM) $(OBJECTS3)
+ $(RM) $(OBJECTS4)
+ $(RM) $(OBJECTS5)
+ $(RM) qrouterexec$(EXEEXT)
+ $(RM) qrouternullg$(EXEEXT)
+ $(RM) qrouter$(EXEEXT)
+ $(RM) qrouter$(SHDLIB_EXT)
+ $(RM) qrouter.tcl
+ $(RM) qrouter.sh
+
+.c.o:
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(SHLIB_CFLAGS) $(DEFS) $(STUB_DEFS) \
+ $(EXTRA_DEFS) $(INC_SPECS) -c $< -o $@
diff --git a/Makefile.in b/Makefile.in
index 95ed4d4..a86e268 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -36,7 +36,7 @@ ALL_TARGET := @ALL_TARGET@
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
+SOURCES2 = graphics.c tclqrouter.c tkSimple.c delays.c antenna.c
OBJECTS2 := $(patsubst %.c,%.o,$(SOURCES2))
SOURCES3 = qrouterexec.c
diff --git a/README b/README
index f562333..b5afe2d 100644
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
-------------------------------------------------
-Qrouter version 1.3
+Qrouter version 1.4
Detail netlist router for ASICs
(c) 2017 by Tim Edwards
Released under Gnu Public License
@@ -9,6 +9,13 @@ Released under Gnu Public License
Release notes:
----------------------------------------------
+Version 1.4
+------------
+Branch created April 25, 2017 mainly for
+the purpose of making the existing version 1.3
+the stable branch, particularly as version 1.3
+is required for qflow.
+
Version 1.3
------------
Branch created September 16, 2014 and slowly
@@ -111,7 +118,7 @@ the standard compile and install sequence:
Options to configure:
- --with-prefix=<prefix>
+ --prefix=<prefix>
overrides the standard install
location of /usr/local
diff --git a/VERSION b/VERSION
index 81d6db0..ed32bf2 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.3.108
+1.4.49
diff --git a/antenna.c b/antenna.c
new file mode 100644
index 0000000..a3d0ad5
--- /dev/null
+++ b/antenna.c
@@ -0,0 +1,1308 @@
+/*--------------------------------------------------------------*/
+/* antenna.c -- Compute the metal area to gate area for all */
+/* routes and determine where antenna violations occur. Then, */
+/* resolve the violations by routing from each violation to an */
+/* antenna tap. */
+/* */
+/* To be done: If there are no antenna cells placed, or if */
+/* the antenna route fails, or if the antenna violation is */
+/* close to the limit, see if the route can be adjusted by */
+/* moving the route to a higher layer near the gate. */
+/*--------------------------------------------------------------*/
+/* Written by Tim Edwards, May 2018 */
+/*--------------------------------------------------------------*/
+
+#include <ctype.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <regex.h>
+
+/* This entire file is dependent on the Tcl/Tk version */
+#ifdef TCL_QROUTER
+#include <tk.h>
+
+#include "qrouter.h"
+#include "qconfig.h"
+#include "node.h"
+#include "lef.h"
+#include "def.h"
+#include "point.h"
+
+/* Node Hash Table routines taken from delay.c */
+extern GATE FindGateNode(Tcl_HashTable *, NODE, int *);
+extern void FreeNodeTable(Tcl_HashTable *);
+
+extern int TotalRoutes;
+
+/* Structure to hold information about an antenna error. */
+
+typedef struct antennainfo_ *ANTENNAINFO;
+
+struct antennainfo_ {
+ ANTENNAINFO next; /* Next antenna violation in the list. */
+ NET net; /* The net violating an antenna rule */
+ NODE node; /* A gate-end node that is in violation */
+ ROUTE route; /* A route that is part of the antenna */
+ int layer; /* Uppermost metal layer of the antenna */
+};
+
+/* Keep the list as a global variable so it can be accessed */
+/* from doroute() (in qrouter.c) */
+
+ANTENNAINFO AntennaList;
+
+/*--------------------------------------------------------------*/
+/* Regular expression matching of the given string in */
+/* "antennacell" to the string "strtest". If the regular */
+/* expression matches and the result is in the first character */
+/* position of the string, then return TRUE (match), otherwise */
+/* return FALSE (no match). */
+/*--------------------------------------------------------------*/
+
+u_char
+string_match(char *antennacell, char *strtest)
+{
+ regex_t regex;
+ regmatch_t pmatch;
+ int reti;
+
+ /* Compile regular expression */
+ reti = regcomp(&regex, antennacell, 0);
+ if (reti) {
+ /* Assume this is not a regular expression and just run */
+ /* a straight string match. */
+ if (!strcasecmp(antennacell, strtest))
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ /* Execute regular expression */
+ reti = regexec(&regex, strtest, 1, &pmatch, 0);
+ regfree(&regex);
+
+ if (!reti) {
+ if (pmatch.rm_so == 0) /* Must match beginning of string */
+ return TRUE;
+ else
+ return FALSE;
+ }
+ else
+ return FALSE;
+}
+
+/*--------------------------------------------------------------*/
+/* Find free antenna cells, and collect all the antenna taps */
+/* into a single net, much like VDD_NET or GND_NET. */
+/* */
+/* Return the number of free antenna taps available in the */
+/* layout. */
+/* */
+/* If the name of the antennacell ends in '*', then assume a */
+/* wildcard character and match to any string beginning with */
+/* the substring of antennacell. */
+/*--------------------------------------------------------------*/
+
+void
+find_free_antenna_taps(char *antennacell)
+{
+ int numtaps;
+ GATE ginst;
+ GATE gateginfo;
+ NODE noderec;
+ int netnum, i;
+
+ if (antennacell == NULL) {
+ Fprintf(stderr, "No antenna cell defined!\n");
+ return;
+ }
+ numtaps = 0;
+ for (ginst = Nlgates; ginst; ginst = ginst->next) {
+ gateginfo = ginst->gatetype;
+
+ if (string_match(antennacell, gateginfo->gatename)) {
+ /* Find an unassigned node. If there is not one, */
+ /* this is probably a routed (not free) cell. */
+ for (i = 0; i < ginst->nodes; i++) {
+ netnum = ginst->netnum[i];
+ noderec = ginst->noderec[i];
+ if ((netnum == 0) && (noderec == NULL)) {
+ ginst->netnum[i] = ANTENNA_NET;
+ ginst->noderec[i] = (NODE)calloc(1, sizeof(struct node_));
+ ginst->noderec[i]->netnum = ANTENNA_NET;
+ }
+ }
+ }
+ }
+}
+
+/*--------------------------------------------------------------*/
+/* Similar to the routine above, but just count the free taps. */
+/*--------------------------------------------------------------*/
+
+int
+count_free_antenna_taps(char *antennacell)
+{
+ int numtaps;
+ GATE ginst;
+ GATE gateginfo;
+ int netnum, i;
+
+ numtaps = 0;
+ for (ginst = Nlgates; ginst; ginst = ginst->next) {
+ gateginfo = ginst->gatetype;
+
+ if (string_match(antennacell, gateginfo->gatename)) {
+ /* Find an unassigned node. If there is not one, */
+ /* this is probably a routed (not free) cell. */
+ for (i = 0; i < ginst->nodes; i++) {
+ netnum = ginst->netnum[i];
+ if (netnum == ANTENNA_NET)
+ numtaps++;
+ }
+ }
+ }
+ return numtaps;
+}
+
+/*--------------------------------------------------------------*/
+/* After routing, the free antenna taps are all marked with the */
+/* net number of the net just routed. To make them free again, */
+/* change all but the one that was routed back to ANTENNA_NET. */
+/* Identify the unused taps by finding the OBSVAL record with */
+/* net set to netnum but not connected to the same node. */
+/*--------------------------------------------------------------*/
+
+void revert_antenna_taps(int netnum, NODE node)
+{
+ int x, y, lay;
+ PROUTE *Pr;
+ NODEINFO lnode = NULL;
+
+ /* Clear all targets except for the one just routed */
+
+ for (lay = 0; lay < Num_layers; lay++)
+ for (x = 0; x < NumChannelsX; x++)
+ for (y = 0; y < NumChannelsY; y++)
+ if ((OBSVAL(x, y, lay) & NETNUM_MASK) == netnum) {
+ Pr = &OBS2VAL(x, y, lay);
+ if (Pr->flags & PR_TARGET) {
+ lnode = NODEIPTR(x, y, lay);
+ if ((lnode == NULL) || (lnode->nodesav != node)) {
+ OBSVAL(x, y, lay) &= ~(NETNUM_MASK | ROUTED_NET);
+ OBSVAL(x, y, lay) |= ANTENNA_NET;
+ }
+ }
+ }
+}
+
+/*--------------------------------------------------------------*/
+/* States to track nodes as they are processed: */
+/* */
+/* NOT_VISITED : Node has not yet been processed. */
+/* VISITED : Node was counted on this pass. */
+/* PROCESSED : Node was counted on a previous pass. */
+/* ANCHOR : Node is a source/drain connection. */
+/*--------------------------------------------------------------*/
+
+enum visit_states {NOT_VISITED = 0, VISITED, PROCESSED, ANCHOR};
+
+/* Forward declarations */
+float get_route_area_reverse(NET, ROUTE, int, u_char *, u_char,
+ Tcl_HashTable *, struct routeinfo_ *);
+float get_route_area_forward(NET, ROUTE, int, u_char *, u_char,
+ Tcl_HashTable *, struct routeinfo_ *);
+float get_route_area_reverse_fromseg(NET, ROUTE, SEG, int, u_char *, u_char,
+ Tcl_HashTable *, struct routeinfo_ *);
+
+/*--------------------------------------------------------------*/
+/* Determine the amount of metal in the route, starting at the */
+/* route start point, and not moving past any point that is */
+/* above "layer". Check all other unvisited routes in net to */
+/* see if any connect to "rt". If so, check if they connect */
+/* to a point that is part of the subnet below or at "layer". */
+/* If they do, recursively run get_route_area_forward on that */
+/* route. When done, return the total area of the subnet. */
+/*--------------------------------------------------------------*/
+
+float
+get_route_area_forward_fromseg(NET net, ROUTE rt, SEG nseg, int layer,
+ u_char *visited, u_char method, Tcl_HashTable *NodeTable,
+ struct routeinfo_ *iroute)
+{
+ float area, length, width, thick;
+ int x, y, l, compat;
+ SEG seg, iseg, chkseg;
+ ROUTE rt2;
+ u_char found;
+
+ if (rt->flags & RT_VISITED) return 0.0;
+ rt->flags |= RT_VISITED;
+ area = 0.0;
+
+ /* If nseg is NULL then check from the beginning. */
+ if (nseg == NULL) nseg = rt->segments;
+
+ /* Check if the route beginning is a node */
+ if (nseg == rt->segments) {
+ if (rt->flags & RT_START_NODE) {
+ NODE node;
+ GATE g;
+ int i;
+
+ node = rt->start.node;
+
+ if (visited) {
+
+ /* If more than one route is connected to the node, */
+ /* then this node may have been visited already. */
+
+ if (visited[node->nodenum] == NOT_VISITED) {
+ g = FindGateNode(NodeTable, node, &i);
+ if (g->area[i] == 0.0) {
+ /* There's a diffusion diode here! */
+ visited[node->nodenum] = ANCHOR;
+ return 0.0;
+ } else {
+ /* Add this node to the list of nodes with gates */
+ /* attached to this antenna area. */
+ visited[node->nodenum] = VISITED;
+ }
+ }
+ }
+ else if ((method == ANTENNA_ROUTE) && (iroute != NULL)) {
+ set_node_to_net(node, PR_SOURCE, iroute->glist[0], iroute->bbox, 0);
+ }
+
+ /* Walk all other routes that start or end on this node */
+
+ for (rt2 = net->routes; rt2; rt2 = rt2->next) {
+ if (rt2->flags & RT_VISITED) continue;
+
+ if ((rt2->flags & RT_START_NODE) && (rt2->start.node == node)) {
+ /* The start point of rt2 connects to the same node */
+ area += get_route_area_forward(net, rt2, layer, visited,
+ method, NodeTable, NULL);
+ }
+ else if ((rt2->flags & RT_END_NODE) && (rt2->end.node == node)) {
+ /* The end point of rt2 connects to the same node */
+ for (iseg = rt2->segments; iseg && iseg->next; iseg = iseg->next);
+ area += get_route_area_reverse(net, rt2, layer, visited,
+ method, NodeTable, NULL);
+ }
+ }
+ }
+ }
+
+ for (seg = rt->segments; seg && (seg != nseg); seg = seg->next);
+ if (seg == NULL) return 0.0;
+
+ for (; seg; seg = seg->next) {
+
+ /* Once the layer goes above the current check layer, the search stops. */
+ if (method != ANTENNA_DISABLE)
+ if (seg->layer > layer) break;
+
+ /* Vias don't contribute to area, at least for now. */
+ if (seg->segtype & ST_VIA) continue;
+
+ /* For non-cumulative methods, only count area for */
+ /* those segments which are on the given check layer. */
+
+ if ((method == CALC_AREA) || (method == CALC_SIDEAREA))
+ if (seg->layer != layer)
+ continue;
+
+ /* method ANTENNA_ROUTE indicates that this routine was */
+ /* called as part of antenna routing. So set up this */
+ /* part of the route in a manner similar to the */
+ /* set_route_to_net() routine. */
+
+ if ((method == ANTENNA_ROUTE) && (iroute != NULL)) {
+ PROUTE *Pr;
+ POINT gpoint;
+
+ l = seg->layer;
+ x = seg->x1;
+ y = seg->y1;
+ while (1) {
+ Pr = &OBS2VAL(x, y, l);
+ Pr->flags = PR_SOURCE;
+ Pr->prdata.cost = 0;
+
+ if (~(Pr->flags & PR_ON_STACK)) {
+ Pr->flags |= PR_ON_STACK;
+ gpoint = allocPOINT();
+ gpoint->x1 = x;
+ gpoint->y1 = y;
+ gpoint->layer = l;
+ gpoint->next = iroute->glist[0];
+ iroute->glist[0] = gpoint;
+ }
+
+ if (x < iroute->bbox.x1) iroute->bbox.x1 = x;
+ if (x > iroute->bbox.x2) iroute->bbox.x2 = x;
+ if (y < iroute->bbox.y1) iroute->bbox.y1 = y;
+ if (y > iroute->bbox.y2) iroute->bbox.y2 = y;
+
+ // Move to next grid position in the segment
+ if (x == seg->x2 && y == seg->y2) break;
+ if (seg->x2 > seg->x1) x++;
+ else if (seg->x2 < seg->x1) x--;
+ if (seg->y2 > seg->y1) y++;
+ else if (seg->y2 < seg->y1) y--;
+ }
+ }
+ else if (method == ANTENNA_DISABLE) {
+ PROUTE *Pr;
+
+ l = seg->layer;
+ x = seg->x1;
+ y = seg->y1;
+ while (1) {
+ Pr = &OBS2VAL(x, y, l);
+ Pr->prdata.net = MAXNETNUM;
+ Pr->flags &= ~(PR_SOURCE | PR_TARGET | PR_COST);
+
+ // Move to next grid position in the segment
+ if (x == seg->x2 && y == seg->y2) break;
+ if (seg->x2 > seg->x1) x++;
+ else if (seg->x2 < seg->x1) x--;
+ if (seg->y2 > seg->y1) y++;
+ else if (seg->y2 < seg->y1) y--;
+ }
+ }
+ if ((method != ANTENNA_ROUTE) && (method != ANTENNA_DISABLE)) {
+
+ /* Note that one of x or y is zero, depending on segment orientation */
+ x = (seg->x2 - seg->x1);
+ y = (seg->y2 - seg->y1);
+ if (x < 0) x = -x;
+ if (y < 0) y = -y;
+
+ /* Note that "l" is a unitless grid dimension */
+ if (x == 0)
+ length = (float)y * (float)PitchY;
+ else
+ length = (float)x * (float)PitchX;
+
+ /* area is either the total top surface of the metal, */
+ /* or the total side surface of the metal (in um^2) */
+
+ width = LefGetRouteWidth(seg->layer);
+ if ((method == CALC_AREA) || (method == CALC_AGG_AREA))
+ area += (float)(length * width);
+ else if ((method == CALC_SIDEAREA) || (method == CALC_AGG_SIDEAREA)) {
+ thick = LefGetRouteThickness(seg->layer);
+ area += thick * 2.0 * (length + width);
+ }
+ }
+ }
+
+ /* Check other routes for intersection with this route */
+
+ for (rt2 = net->routes; rt2; rt2 = rt2->next) {
+ if (rt2->flags & RT_VISITED) continue;
+
+ if (!(rt2->flags & RT_START_NODE) && (rt2->start.route == rt)) {
+ /* The start point of rt2 connects somewhere on rt */
+ iseg = rt2->segments;
+ x = iseg->x1;
+ y = iseg->y1;
+ l = iseg->layer;
+ if (l > layer) continue;
+ }
+ else if (!(rt2->flags & RT_END_NODE) && (rt2->end.route == rt)) {
+ /* The end point of rt2 connects somewhere on rt */
+ for (iseg = rt2->segments; iseg && iseg->next; iseg = iseg->next);
+ x = iseg->x2;
+ y = iseg->y2;
+ l = iseg->layer;
+ if (l > layer) continue;
+ }
+ else
+ continue;
+
+ /* Must determine if rt2 intersects rt within the antenna area */
+
+ found = (u_char)0;
+ for (chkseg = rt->segments; chkseg && chkseg != seg; chkseg = chkseg->next) {
+ if (chkseg->segtype & ST_WIRE) {
+ if (iseg->segtype & ST_WIRE) {
+ compat = (l == chkseg->layer);
+ }
+ else {
+ compat = (l == chkseg->layer) || (l + 1 == chkseg->layer);
+ }
+ }
+ else {
+ if (iseg->segtype & ST_WIRE) {
+ compat = (l == chkseg->layer) || (l == chkseg->layer + 1);
+ }
+ else {
+ compat = (l == chkseg->layer) || (l == chkseg->layer + 1) ||
+ (l + 1 == chkseg->layer);
+ }
+ }
+ if (!compat) continue;
+
+ if (chkseg->segtype & ST_VIA) {
+ if ((chkseg->x1 == x) && (chkseg->y1 == y)) {
+ found = (u_char)1;
+ break;
+ }
+ }
+ else if (chkseg->x1 < chkseg->x2) {
+ if (chkseg->y1 == y) {
+ if ((chkseg->x1 <= x) && (chkseg->x2 >= x)) {
+ found = (u_char)1;
+ break;
+ }
+ }
+ }
+ else if (chkseg->x1 > chkseg->x2) {
+ if (chkseg->y1 == y) {
+ if ((chkseg->x1 >= x) && (chkseg->x2 <= x)) {
+ found = (u_char)1;
+ break;
+ }
+ }
+ }
+ else if (chkseg->y1 < chkseg->y2) {
+ if (chkseg->x1 == x) {
+ if ((chkseg->y1 <= y) && (chkseg->y2 >= y)) {
+ found = (u_char)1;
+ break;
+ }
+ }
+ }
+ else if (chkseg->y1 > chkseg->y2) {
+ if (chkseg->x1 == x) {
+ if ((chkseg->y1 >= y) && (chkseg->y2 <= y)) {
+ found = (u_char)1;
+ break;
+ }
+ }
+ }
+ }
+ if (found == (u_char)1) {
+ if (rt2->start.route == rt)
+ area += get_route_area_forward(net, rt2, layer, visited,
+ method, NodeTable, iroute);
+ else
+ area += get_route_area_reverse(net, rt2, layer, visited,
+ method, NodeTable, iroute);
+ }
+ }
+
+ /* The end of this route may be a node (so record it in visited) or */
+ /* a route (so walk it). */
+
+ if (seg == NULL) { /* If seg != NULL then we didn't reach the route end */
+ if (rt->flags & RT_END_NODE) {
+ NODE node;
+ GATE g;
+ int i;
+
+ node = rt->end.node;
+
+ /* Walk all other routes that start or end on this node */
+
+ for (rt2 = net->routes; rt2; rt2 = rt2->next) {
+ if (rt2->flags & RT_VISITED) continue;
+
+ if ((rt2->flags & RT_START_NODE) && (rt2->start.node == node)) {
+ /* The start point of rt2 connects to the same node */
+ area += get_route_area_forward(net, rt2, layer, visited,
+ method, NodeTable, NULL);
+ }
+ else if ((rt2->flags & RT_END_NODE) && (rt2->end.node == node)) {
+ /* The end point of rt2 connects to the same node */
+ for (iseg = rt2->segments; iseg && iseg->next; iseg = iseg->next);
+ area += get_route_area_reverse(net, rt2, layer, visited,
+ method, NodeTable, NULL);
+ }
+ }
+
+ g = FindGateNode(NodeTable, node, &i);
+ if (g == NULL) {
+ /* This should not happen */
+ Fprintf(stderr, "Error: net %s route end marked as node, but"
+ " no node found!\n", net->netname);
+ return 0.0;
+ }
+ if (g->area[i] == 0.0) {
+ /* There's a diffusion diode here! */
+ if (visited) visited[node->nodenum] = ANCHOR;
+ return 0.0;
+ } else {
+ /* Add this node to the list of nodes with gates */
+ /* attached to this antenna area. */
+ if (visited) visited[node->nodenum] = VISITED;
+ }
+ if ((method == ANTENNA_ROUTE) && (iroute != NULL)) {
+ set_node_to_net(node, PR_SOURCE, iroute->glist[0], iroute->bbox, 0);
+ }
+ }
+ else {
+ SEG rseg;
+
+ /* Back up seg to point to the last segment of the route */
+ for (seg = rt->segments; seg && seg->next; seg = seg->next);
+ x = seg->x2;
+ y = seg->y2;
+ l = seg->layer;
+
+ /* Find where on rt2 the segment lands, then search rt2 for */
+ /* antenna area forward and reverse from that segment. */
+
+ rt2 = rt->end.route;
+ if (rt2 == NULL) return; /* This should not happen */
+
+ for (rseg = rt2->segments; rseg; rseg = rseg->next) {
+ if (rseg->segtype & ST_WIRE) {
+ if (seg->segtype & ST_WIRE) {
+ compat = (l == rseg->layer);
+ }
+ else {
+ compat = (l == rseg->layer) || (l + 1 == rseg->layer);
+ }
+ }
+ else {
+ if (seg->segtype & ST_WIRE) {
+ compat = (l == rseg->layer) || (l == rseg->layer + 1);
+ }
+ else {
+ compat = (l == rseg->layer) || (l == rseg->layer + 1) ||
+ (l + 1 == rseg->layer);
+ }
+ }
+ if (compat) {
+ if (rseg->segtype & ST_VIA) {
+ if ((rseg->x2 == seg->x2) && (rseg->y2 == seg->y2))
+ break;
+ }
+ else if (rseg->x1 < rseg->x2) {
+ if (rseg->y2 == seg->y2) {
+ if ((rseg->x1 <= seg->x2) && (rseg->x2 >= seg->x2))
+ break;
+ }
+ }
+ else if (rseg->x1 > rseg->x2) {
+ if (rseg->y2 == seg->y2) {
+ if ((rseg->x1 >= seg->x2) && (rseg->x2 <= seg->x2))
+ break;
+ }
+ }
+ else if (rseg->y1 < rseg->y2) {
+ if (rseg->x2 == seg->x2) {
+ if ((rseg->y1 <= seg->y2) && (rseg->y2 >= seg->y2))
+ break;
+ }
+ }
+ else if (rseg->y1 > rseg->y2) {
+ if (rseg->x2 == seg->x2) {
+ if ((rseg->y1 >= seg->y2) && (rseg->y2 <= seg->y2))
+ break;
+ }
+ }
+ }
+ }
+ if (rseg == NULL) return; /* This should not happen */
+
+ if (rseg->next != NULL)
+ area += get_route_area_forward_fromseg(net, rt2, rseg->next,
+ layer, visited, method, NodeTable, iroute);
+ area += get_route_area_reverse_fromseg(net, rt2, rseg, layer,
+ visited, method, NodeTable, iroute);
+ }
+ }
+ return area;
+}
+
+/*--------------------------------------------------------------*/
+/* Check route antenna forward from the beginning of the route. */
+/*--------------------------------------------------------------*/
+
+float
+get_route_area_forward(NET net, ROUTE rt, int layer, u_char *visited,
+ u_char method, Tcl_HashTable *NodeTable, struct routeinfo_ *iroute)
+{
+ float area;
+
+ area = get_route_area_forward_fromseg(net, rt, NULL, layer, visited,
+ method, NodeTable, iroute);
+ return area;
+}
+
+/*--------------------------------------------------------------*/
+/* This is the same as get_route_area_forward_fromseg, but is */
+/* searching the path from end to beginning, so reverse the */
+/* route first and then call get_route_area_forward_fromseg(). */
+/*--------------------------------------------------------------*/
+
+float
+get_route_area_reverse_fromseg(NET net, ROUTE rt, SEG nseg, int layer,
+ u_char *visited, u_char method, Tcl_HashTable *NodeTable,
+ struct routeinfo_ *iroute)
+{
+ SEG seg, dseg, newseg, firstseg, saveseg;
+ NODE savestartnode, saveendnode;
+ float area;
+ u_char saveflags;
+
+ firstseg = NULL;
+
+ /* Reverse the route */
+ for (seg = rt->segments; seg; seg = seg->next) {
+ newseg = (SEG)malloc(sizeof(struct seg_));
+ newseg->layer = seg->layer;
+ newseg->x1 = seg->x2;
+ newseg->x2 = seg->x1;
+ newseg->y1 = seg->y2;
+ newseg->y2 = seg->y1;
+ newseg->segtype = seg->segtype;
+ newseg->next = firstseg;
+ firstseg = newseg;
+ }
+
+ saveseg = rt->segments;
+
+ /* Replace the route segment with the reversed route */
+ rt->segments = firstseg;
+
+ /* Reverse the endpoint information */
+ savestartnode = rt->start.node;
+ saveendnode = rt->end.node;
+ rt->start.node = saveendnode;
+ rt->end.node = savestartnode;
+
+ /* Reverse the start/end flags */
+ saveflags = rt->flags & (RT_START_NODE | RT_END_NODE);
+ rt->flags &= ~(RT_START_NODE | RT_END_NODE);
+ if (saveflags & RT_START_NODE) rt->flags |= RT_END_NODE;
+ if (saveflags & RT_END_NODE) rt->flags |= RT_START_NODE;
+
+ area = get_route_area_forward_fromseg(net, rt, nseg, layer, visited,
+ method, NodeTable, iroute);
+
+ /* Replace the route segment with the original route */
+ rt->segments = saveseg;
+
+ /* Revert the endpoint information */
+ rt->start.node = savestartnode;
+ rt->end.node = saveendnode;
+
+ /* Revert the start/end flags */
+ rt->flags &= ~(RT_START_NODE | RT_END_NODE);
+ rt->flags |= saveflags;
+
+ /* Free the reversed route */
+ for (seg = firstseg; seg; ) {
+ dseg = seg->next;
+ free(seg);
+ seg = dseg;
+ }
+ return area;
+}
+
+/*--------------------------------------------------------------*/
+/* Walk a route in reverse from end to start. */
+/*--------------------------------------------------------------*/
+
+float
+get_route_area_reverse(NET net, ROUTE rt, int layer, u_char *visited,
+ u_char method, Tcl_HashTable *NodeTable,
+ struct routeinfo_ *iroute)
+{
+ float area;
+ area = get_route_area_reverse_fromseg(net, rt, NULL, layer, visited,
+ method, NodeTable, iroute);
+ return area;
+}
+
+/*--------------------------------------------------------------*/
+/* Find all antenna violations at a specific metal layer */
+/*--------------------------------------------------------------*/
+
+int find_layer_antenna_violations(int layer, Tcl_HashTable *NodeTable)
+{
+ int numerrors, n, nn, numroutes, i, j, new, neterrors;
+ u_char *visited, method;
+ float antenna_ratio, thick;
+ GATE g;
+ NET net;
+ ROUTE rt, saveroute;
+ NODEINFO nodeptr;
+ NODE node, tnode;
+ SEG seg;
+ ANTENNAINFO newantenna;
+ float gate_area, metal_area, ratio, save_gate, save_metal, max_ratio;
+
+ numerrors = 0;
+
+ /* Get the metal layer record for this layer and find the metal */
+ /* area ratio limit and the method to be used for calculating */
+ /* metal area. */
+
+ method = LefGetRouteAntennaMethod(layer);
+ if (method == CALC_NONE) return 0; /* No antenna information in tech */
+ antenna_ratio = (float)LefGetRouteAreaRatio(layer);
+ thick = (float)LefGetRouteThickness(layer);
+ if (((method == CALC_SIDEAREA) || (method == CALC_AGG_SIDEAREA)) && (thick == 0.0))
+ return 0; /* Insufficient antenna information in tech */
+
+ /* Make a pass through all nets to find antenna violations */
+
+ for (n = 0; n < Numnets; n++) {
+ net = Nlnets[n];
+
+ if ((net->netnum == VDD_NET) || (net->netnum == GND_NET) ||
+ (net->netnum == ANTENNA_NET)) continue;
+
+ /* Ignore nets with no routes */
+ numroutes = 0;
+ for (rt = net->routes; rt; rt = rt->next) numroutes++;
+ if (numroutes == 0) continue;
+
+ /* Consider each terminal as a separate sub-net calculation. */
+ /* But if multiple terminals belong to the same sub-net, they */
+ /* are marked visited and ignored on subsequent calculations. */
+
+ visited = (u_char *)malloc(net->numnodes * sizeof(u_char));
+ for (node = net->netnodes; node != NULL; node = node->next) {
+ nn = node->nodenum;
+ visited[nn] = NOT_VISITED;
+ }
+
+ /* Make a pass through all nodes of the net. Where they are */
+ /* not connected together at "layer", these are individual */
+ /* sub-nets. */
+
+ neterrors = 0;
+ max_ratio = 0.0; /* For diagnostics only */
+ for (node = net->netnodes; node != NULL; node = node->next) {
+ nn = node->nodenum;
+ if (visited[nn] >= PROCESSED) continue; /* Already seen */
+
+ /* Find the gate area of this node */
+ g = FindGateNode(NodeTable, node, &i);
+ metal_area = 0.0;
+
+ if (g->area[i] == 0.0) {
+ visited[nn] = ANCHOR; /* Mark as S/D connection */
+ continue; /* No gate, so no violation */
+ }
+ else
+ visited[nn] = VISITED;
+
+ /* Clear visited flags for routes */
+
+ for (rt = net->routes; rt; rt = rt->next)
+ rt->flags &= ~RT_VISITED;
+
+ /* Find the route or routes that connect to this node */
+
+ for (rt = net->routes; rt; rt = rt->next) {
+ if ((rt->flags & RT_START_NODE) && (rt->start.node == node)) {
+ saveroute = rt;
+ metal_area += get_route_area_forward(net, rt, layer, visited,
+ method, NodeTable, NULL);
+ }
+ else if ((rt->flags & RT_END_NODE) && (rt->end.node == node)) {
+ saveroute = rt;
+ metal_area += get_route_area_reverse(net, rt, layer, visited,
+ method, NodeTable, NULL);
+ }
+ else continue;
+ }
+
+ /* Gate area is combined area of gates visited */
+
+ gate_area = 0.0;
+ for (tnode = net->netnodes; tnode != NULL; tnode = tnode->next) {
+ j = tnode->nodenum;
+ if (visited[j] == VISITED) {
+ g = FindGateNode(NodeTable, tnode, &i);
+ if (g->area[i] == 0.0) {
+ visited[j] = ANCHOR;
+ gate_area = 0.0;
+ break;
+ }
+ else
+ gate_area += g->area[i];
+ }
+
+ }
+
+ if (gate_area > 0.0) {
+ ratio = metal_area / gate_area;
+ if (ratio > max_ratio) {
+ max_ratio = ratio;
+ save_gate = gate_area;
+ save_metal = metal_area;
+ }
+
+ if (ratio > antenna_ratio) {
+
+ /* Record and report the violation */
+
+ numerrors++;
+ neterrors++;
+ if (Verbose > 1) {
+ Fprintf(stderr,
+ "Antenna violation on node %d of net %s at metal%d\n",
+ nn, net->netname, layer + 1);
+ }
+ if (Verbose > 2) {
+ Fprintf(stderr, "Metal area = %f, Gate area = %f, Ratio = %f\n",
+ metal_area, gate_area, ratio);
+ }
+ newantenna = (ANTENNAINFO)malloc(sizeof(struct antennainfo_));
+ newantenna->net = net;
+ newantenna->node = node;
+ newantenna->layer = layer;
+ newantenna->route = saveroute;
+ newantenna->next = AntennaList;
+ AntennaList = newantenna;
+ }
+ }
+
+ /* Mark gates as visited on previous pass */
+ for (tnode = net->netnodes; tnode != NULL; tnode = tnode->next) {
+ j = tnode->nodenum;
+ if (visited[j] == VISITED) visited[j] = PROCESSED;
+ }
+ }
+ free(visited);
+
+ if (Verbose > 3) {
+ /* Diagnostic */
+ if (neterrors == 0) {
+ if (max_ratio > 0.0)
+ Fprintf(stderr, "Worst case: Metal area = %f, Gate area = %f, "
+ "Ratio = %f\n", save_metal, save_gate, max_ratio);
+ }
+ }
+
+ /* Clear route visited flags */
+ for (rt = net->routes; rt; rt = rt->next)
+ rt->flags &= ~RT_VISITED;
+ }
+ return numerrors;
+}
+
+/*--------------------------------------------------------------*/
+/* This routine is a combination of set_node_to_net(), */
+/* set_routes_to_net(), and disable_node_nets() (see qrouter.c */
+/* and maze.c), but walks the routes in the same manner used */
+/* for finding the antenna violations. Set the antenna part of */
+/* the net as SOURCE, the free antenna taps as TARGET, and the */
+/* non-antenna portion of the net to an unused net number, */
+/* which can be converted back after routing. */
+/*--------------------------------------------------------------*/
+
+int set_antenna_to_net(int newflags, struct routeinfo_ *iroute,
+ u_char stage, ANTENNAINFO violation, Tcl_HashTable *NodeTable)
+{
+ int x, y, lay, rval, layer;
+ PROUTE *Pr;
+ ROUTE rt, clrrt;
+ NODE node;
+ NET net;
+
+ /* Set the node and connected antenna metal routes to PR_SOURCE. */
+
+ rt = violation->route;
+ node = violation->node;
+ net = violation->net;
+ layer = violation->layer;
+
+ if ((rt->flags & RT_START_NODE) && (rt->start.node == node))
+ get_route_area_forward(net, rt, layer, NULL, ANTENNA_ROUTE, NodeTable,
+ iroute);
+ else if ((rt->flags & RT_END_NODE) && (rt->end.node == node))
+ get_route_area_reverse(net, rt, layer, NULL, ANTENNA_ROUTE, NodeTable,
+ iroute);
+ else {
+ /* This should not happen */
+ Fprintf(stderr, "Error: Antenna route and node do not connect!\n");
+ return 1;
+ }
+
+ /* Clear route visited flags for next pass */
+ for (clrrt = iroute->net->routes; clrrt; clrrt = clrrt->next)
+ clrrt->flags &= ~RT_VISITED;
+
+ /* Disable the remainder of the route */
+
+ if ((rt->flags & RT_START_NODE) && (rt->start.node == node))
+ get_route_area_forward(net, rt, layer, NULL, ANTENNA_DISABLE, NodeTable,
+ iroute);
+ else if ((rt->flags & RT_END_NODE) && (rt->end.node == node))
+ get_route_area_reverse(net, rt, layer, NULL, ANTENNA_DISABLE, NodeTable,
+ iroute);
+ else {
+ /* This should not happen */
+ Fprintf(stderr, "Error: Antenna route and node do not connect!\n");
+ return 1;
+ }
+
+ /* Done checking routes; clear route visited flags */
+ for (clrrt = iroute->net->routes; clrrt; clrrt = clrrt->next)
+ clrrt->flags &= ~RT_VISITED;
+
+ /* Set the antenna taps to the net number. */
+ /* Routine is similar to set_powerbus_to_net(). */
+
+ rval = 0;
+ for (lay = 0; lay < Num_layers; lay++)
+ for (x = 0; x < NumChannelsX; x++)
+ for (y = 0; y < NumChannelsY; y++)
+ if ((OBSVAL(x, y, lay) & NETNUM_MASK) == ANTENNA_NET) {
+ Pr = &OBS2VAL(x, y, lay);
+ // Skip locations that have been purposefully disabled
+ if (!(Pr->flags & PR_COST) && (Pr->prdata.net == MAXNETNUM))
+ continue;
+ else if (!(Pr->flags & PR_SOURCE)) {
+ Pr->flags |= (PR_TARGET | PR_COST);
+ Pr->prdata.cost = MAXRT;
+ rval = 1;
+ OBSVAL(x, y, lay) &= ~NETNUM_MASK;
+ OBSVAL(x, y, lay) |= net->netnum;
+ }
+ }
+
+ return rval;
+}
+
+/*--------------------------------------------------------------*/
+/* This routine is similar to route_setup() for the normal */
+/* stage routes, with changes for the antenna routing. */
+/* Set the node in the "violation" record to source, and set */
+/* all free antenna taps to destination. Add existing routes */
+/* to the source in the same manner as was used to find the */
+/* antenna violation in the first place (this is a subnet of */
+/* the complete net). Disable the remainder of the net. */
+/* Set all free antenna taps to the net number being routed, */
+/* then route like stage 1 power routing. */
+/*--------------------------------------------------------------*/
+
+int antenna_setup(struct routeinfo_ *iroute, ANTENNAINFO violation,
+ Tcl_HashTable *NodeTable)
+{
+ int i, j, netnum, rval;
+ PROUTE *Pr;
+
+ for (i = 0; i < Num_layers; i++) {
+ for (j = 0; j < NumChannelsX * NumChannelsY; j++) {
+ netnum = Obs[i][j] & (~BLOCKED_MASK);
+ Pr = &Obs2[i][j];
+ if (netnum != 0) {
+ Pr->flags = 0; // Clear all flags
+ if (netnum == DRC_BLOCKAGE)
+ Pr->prdata.net = netnum;
+ else
+ Pr->prdata.net = netnum & NETNUM_MASK;
+ } else {
+ Pr->flags = PR_COST; // This location is routable
+ Pr->prdata.cost = MAXRT;
+ }
+ }
+ }
+
+ // Fill out route information record
+
+ iroute->net = violation->net;
+ iroute->rt = NULL;
+ for (i = 0; i < 6; i++)
+ iroute->glist[i] = NULL;
+ iroute->nsrc = violation->node;
+ iroute->nsrctap = iroute->nsrc->taps;
+ iroute->maxcost = MAXRT;
+ iroute->do_pwrbus = TRUE;
+ iroute->pwrbus_src = 0;
+
+ iroute->bbox.x2 = iroute->bbox.y2 = 0;
+ iroute->bbox.x1 = NumChannelsX;
+ iroute->bbox.y1 = NumChannelsY;
+
+ rval = set_antenna_to_net(PR_SOURCE, iroute, 0, violation, NodeTable);
+
+ /* Unlikely that MASK_BBOX would be useful, since one does */
+ /* not know if an antenna tap is inside the box or not. */
+ /* Maybe if bounding box is expanded to encompass some */
+ /* number of taps. . . */
+
+ // if (maskMode == MASK_NONE)
+ fillMask((u_char)0);
+ // else if (maskMode == MASK_BBOX)
+ // createBboxMask(iroute->net, (u_char)Numpasses);
+
+ iroute->maxcost = 20;
+ return rval;
+}
+
+/*--------------------------------------------------------------*/
+/* The simplest way to fix an antenna violation is to find */
+/* a place in the antenna metal to break the antenna and pull */
+/* it up to a higher level of metal. Depending on the severity */
+/* of the antenna violation, this may need to be done more than */
+/* once. If no place to break the antenna is found, return -1 */
+/* for failure. */
+/*--------------------------------------------------------------*/
+
+int simpleantennafix(ANTENNAINFO violation, Tcl_HashTable *NodeTable)
+{
+ return -1; /* Antenna was not fixed */
+}
+
+/*--------------------------------------------------------------*/
+/* Route from nets with antenna violations to the nearest */
+/* routable antenna cell tap. */
+/* */
+/* This routine is essentially the same as doroute() but with */
+/* some special handling related to the antenna taps, which */
+/* have much in common with VDD and GND taps but significant */
+/* differences as well. */
+/*--------------------------------------------------------------*/
+
+int doantennaroute(ANTENNAINFO violation, Tcl_HashTable *NodeTable)
+{
+ NET net;
+ NODE node;
+ ROUTE rt1, lrt;
+ int layer, i, result, savelayers;
+ struct routeinfo_ iroute;
+
+ net = violation->net;
+ node = violation->node;
+ layer = violation->layer;
+
+ result = antenna_setup(&iroute, violation, NodeTable);
+
+ rt1 = createemptyroute();
+ rt1->netnum = net->netnum;
+ iroute.rt = rt1;
+
+ /* Force routing to be done at or below the antenna check layer. */
+
+ savelayers = Num_layers;
+ Num_layers = violation->layer + 1;
+
+ result = route_segs(&iroute, 0, (u_char)0);
+
+ Num_layers = savelayers;
+
+ if (result < 0) {
+ /* To do: Handle failures? */
+ Fprintf(stderr, "Antenna anchoring route failed.\n");
+ free(rt1);
+ }
+ else {
+ TotalRoutes++;
+ if (net->routes) {
+ for (lrt = net->routes; lrt->next; lrt = lrt->next);
+ lrt->next = rt1;
+ }
+ else {
+ /* This should not happen */
+ Fprintf(stderr, "Error: Net has no routes!\n");
+ net->routes = rt1;
+ }
+ }
+
+ /* For power-bus-type routing, glist is not empty after routing */
+ free_glist(&iroute);
+
+ /* Put free taps back to ANTENNA_NET */
+ revert_antenna_taps(net->netnum, rt1->start.node);
+
+ return result;
+}
+
+/*--------------------------------------------------------------*/
+/* Top level routine called from tclqrouter.c */
+/*--------------------------------------------------------------*/
+
+void
+resolve_antenna(char *antennacell, u_char do_fix)
+{
+ FILE *fout;
+ int numtaps, numerrors, numfixed, result;
+ int layererrors;
+ int layer, i, new;
+ Tcl_HashTable NodeTable;
+ Tcl_HashEntry *entry;
+ GATE g;
+ NET net;
+ ROUTE rt;
+ ANTENNAINFO nextviolation, FixedList = NULL, BadList = NULL;
+
+ numtaps = count_free_antenna_taps(antennacell);
+ if (Verbose > 3) {
+ Fprintf(stdout, "Number of free antenna taps = %d\n", numtaps);
+ }
+
+ AntennaList = NULL;
+ numerrors = 0;
+ numfixed = 0;
+
+ /* Build a hash table of nodes, so the gate area can be found */
+ /* quickly for any node by hash lookup. */
+
+ Tcl_InitHashTable(&NodeTable, TCL_ONE_WORD_KEYS);
+
+ for (g = Nlgates; g; g = g->next) {
+ for (i = 0; i < g->nodes; i++) {
+ GATENODE gn;
+ gn = (GATENODE)malloc(sizeof(struct gatenode_));
+ gn->idx = i;
+ gn->gate = g;
+ entry = Tcl_CreateHashEntry(&NodeTable, (char *)(*(g->noderec + i)), &new);
+ Tcl_SetHashValue(entry, gn);
+ }
+ }
+
+ /* Working from the 1nd layer metal to the top, compute */
+ /* route metal to gate area ratios. Mark each one when */
+ /* done, as an antenna violation that has been fixed at, */
+ /* say, metal2 can no longer be a violation on any higer */
+ /* layer of metal. */
+
+ for (layer = 0; layer < Num_layers; layer++) {
+ layererrors = find_layer_antenna_violations(layer, &NodeTable);
+ numerrors += layererrors;
+ if (Verbose > 2) {
+ Fprintf(stdout, "Number of antenna errors on metal%d = %d\n",
+ layer + 1, layererrors);
+ }
+
+ /* Fix the violations found on this layer before moving */
+ /* on to the next layer. */
+
+ while (AntennaList != NULL) {
+ nextviolation = AntennaList->next;
+
+ if (do_fix) {
+ result = simpleantennafix(AntennaList, &NodeTable);
+ if (result == 0) {
+ /* No antenna cell involved, so no backannotation */
+ /* required. Remove the "route" record. */
+ AntennaList->route = NULL;
+ }
+ else
+ result = doantennaroute(AntennaList, &NodeTable);
+ if (result >= 0) numfixed++;
+ }
+
+ /* Move the error information to either the Fixed or Bad lists */
+ if (result >= 0) {
+ AntennaList->next = FixedList;
+ FixedList = AntennaList;
+ if (AntennaList->route != NULL) {
+ /* Replace the route record with the last route */
+ /* of the net, which was the route added to fix. */
+ /* If the net requires more than one antenna */
+ /* anchor, then routes won't be confused. */
+ for (rt = AntennaList->net->routes; rt && rt->next; rt = rt->next);
+ AntennaList->route = rt;
+ }
+ }
+ else {
+ AntennaList->next = BadList;
+ BadList = AntennaList;
+ }
+ AntennaList = nextviolation;
+ }
+ }
+
+ if (Verbose > 0) {
+ Fprintf(stdout, "Total number of antenna errors found = %d\n", numerrors);
+ if (do_fix)
+ Fprintf(stdout, "Total number of antenna errors fixed = %d\n", numfixed);
+ }
+ if (numtaps < numerrors) {
+ if (numtaps == 0)
+ Fprintf(stderr, "There are no antenna taps to use to correct "
+ "antenna errors!\n");
+ else {
+ Fprintf(stderr, "There are not enough antenna taps to use to "
+ "correct antenna errors!\n");
+ Fprintf(stderr, "Number of errors = %d, number of taps = %d\n",
+ numerrors, numtaps);
+ Fprintf(stderr, "Increate the amount of unallocated antenna cells"
+ " in the design.\n");
+ }
+ /* To do: Replace the error message with an ad-hoc solution to */
+ /* pull routes up to a higher metal layer near the gate causing */
+ /* the error. */
+ }
+
+ /* Output the violation lists. The fixed violations need to be */
+ /* known so that the additional connection to the net can be added */
+ /* to the netlist for verification purposes. The unfixed */
+ /* violations need to be reported so they can be tracked down and */
+ /* fixed by hand. */
+
+ if ((FixedList != NULL) || (BadList != NULL))
+ fout = fopen("antenna.out", "w");
+
+ if (FixedList != NULL) {
+ ROUTE rt;
+ fprintf(fout, "Revised netlist: New antenna anchor connections\n");
+
+ for (nextviolation = FixedList; nextviolation;
+ nextviolation = nextviolation->next) {
+ // NOTE: nextviolation->route was changed from the route that
+ // connects to the gate in violation, to the route that fixes
+ // the antenna error.
+ g = FindGateNode(&NodeTable, nextviolation->route->start.node, &i);
+ fprintf(fout, "Net=%s Instance=%s Cell=%s Pin=%s\n",
+ nextviolation->net->netname, g->gatename,
+ g->gatetype->gatename, g->gatetype->node[i]);
+ }
+ fprintf(fout, "\n");
+ }
+
+ if (BadList != NULL) {
+ fprintf(fout, "Unfixed antenna errors:\n");
+
+ for (nextviolation = BadList; nextviolation;
+ nextviolation = nextviolation->next) {
+ g = FindGateNode(&NodeTable, nextviolation->node, &i);
+ fprintf(fout, "Net=%s Instance=%s Cell=%s Pin=%s error on Metal%d\n",
+ nextviolation->net->netname,
+ g->gatename, g->gatetype->gatename,
+ g->gatetype->node[i], nextviolation->layer + 1);
+ }
+ }
+
+ if ((FixedList != NULL) || (BadList != NULL)) fclose(fout);
+
+ /* Free up the node hash table */
+
+ FreeNodeTable(&NodeTable);
+ Tcl_DeleteHashTable(&NodeTable);
+
+ /* Free up the violation lists */
+
+ while (FixedList != NULL) {
+ nextviolation = FixedList->next;
+ free(FixedList);
+ FixedList = nextviolation;
+ }
+ while (BadList != NULL) {
+ nextviolation = BadList->next;
+ free(BadList);
+ BadList = nextviolation;
+ }
+}
+
+#endif /* TCL_QROUTER */
+
+/* end of antenna.c */
diff --git a/config.log b/config.log
new file mode 100644
index 0000000..78ff1d3
--- /dev/null
+++ b/config.log
@@ -0,0 +1,499 @@
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by configure, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ ./configure
+
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = stravinsky
+uname -m = x86_64
+uname -r = 4.1.13-100.fc21.x86_64
+uname -s = Linux
+uname -v = #1 SMP Tue Nov 10 13:13:20 UTC 2015
+
+/usr/bin/uname -p = x86_64
+/bin/uname -X = unknown
+
+/bin/arch = x86_64
+/usr/bin/arch -k = unknown
+/usr/convex/getsysinfo = unknown
+/usr/bin/hostinfo = unknown
+/bin/machine = unknown
+/usr/bin/oslevel = unknown
+/bin/universe = unknown
+
+PATH: .
+PATH: /bin
+PATH: /sbin
+PATH: /usr/bin
+PATH: /usr/sbin
+PATH: /usr/local/bin
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+configure:2206: checking build system type
+configure:2220: result: x86_64-unknown-linux-gnu
+configure:2240: checking host system type
+configure:2253: result: x86_64-unknown-linux-gnu
+configure:2273: checking target system type
+configure:2286: result: x86_64-unknown-linux-gnu
+configure:2380: checking for gcc
+configure:2396: found /bin/gcc
+configure:2407: result: gcc
+configure:2636: checking for C compiler version
+configure:2645: gcc --version >&5
+gcc (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6)
+Copyright (C) 2014 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+configure:2656: $? = 0
+configure:2645: gcc -v >&5
+Using built-in specs.
+COLLECT_GCC=gcc
+COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.9.2/lto-wrapper
+Target: x86_64-redhat-linux
+Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.9.2-20150212/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.9.2-20150212/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
+Thread model: posix
+gcc version 4.9.2 20150212 (Red Hat 4.9.2-6) (GCC)
+configure:2656: $? = 0
+configure:2645: gcc -V >&5
+gcc: error: unrecognized command line option '-V'
+gcc: fatal error: no input files
+compilation terminated.
+configure:2656: $? = 4
+configure:2645: gcc -qversion >&5
+gcc: error: unrecognized command line option '-qversion'
+gcc: fatal error: no input files
+compilation terminated.
+configure:2656: $? = 4
+configure:2676: checking whether the C compiler works
+configure:2698: gcc conftest.c >&5
+configure:2702: $? = 0
+configure:2750: result: yes
+configure:2753: checking for C compiler default output file name
+configure:2755: result: a.out
+configure:2761: checking for suffix of executables
+configure:2768: gcc -o conftest conftest.c >&5
+configure:2772: $? = 0
+configure:2794: result:
+configure:2816: checking whether we are cross compiling
+configure:2824: gcc -o conftest conftest.c >&5
+configure:2828: $? = 0
+configure:2835: ./conftest
+configure:2839: $? = 0
+configure:2854: result: no
+configure:2859: checking for suffix of object files
+configure:2881: gcc -c conftest.c >&5
+configure:2885: $? = 0
+configure:2906: result: o
+configure:2910: checking whether we are using the GNU C compiler
+configure:2929: gcc -c conftest.c >&5
+configure:2929: $? = 0
+configure:2938: result: yes
+configure:2947: checking whether gcc accepts -g
+configure:2967: gcc -c -g conftest.c >&5
+configure:2967: $? = 0
+configure:3008: result: yes
+configure:3025: checking for gcc option to accept ISO C89
+configure:3088: gcc -c -g -O2 conftest.c >&5
+configure:3088: $? = 0
+configure:3101: result: none needed
+configure:3126: checking how to run the C preprocessor
+configure:3157: gcc -E conftest.c
+configure:3157: $? = 0
+configure:3171: gcc -E conftest.c
+conftest.c:9:28: fatal error: ac_nonexistent.h: No such file or directory
+ #include <ac_nonexistent.h>
+ ^
+compilation terminated.
+configure:3171: $? = 1
+configure: failed program was:
+| /* confdefs.h */
+| #define PACKAGE_NAME ""
+| #define PACKAGE_TARNAME ""
+| #define PACKAGE_VERSION ""
+| #define PACKAGE_STRING ""
+| #define PACKAGE_BUGREPORT ""
+| #define PACKAGE_URL ""
+| /* end confdefs.h. */
+| #include <ac_nonexistent.h>
+configure:3196: result: gcc -E
+configure:3216: gcc -E conftest.c
+configure:3216: $? = 0
+configure:3230: gcc -E conftest.c
+conftest.c:9:28: fatal error: ac_nonexistent.h: No such file or directory
+ #include <ac_nonexistent.h>
+ ^
+compilation terminated.
+configure:3230: $? = 1
+configure: failed program was:
+| /* confdefs.h */
+| #define PACKAGE_NAME ""
+| #define PACKAGE_TARNAME ""
+| #define PACKAGE_VERSION ""
+| #define PACKAGE_STRING ""
+| #define PACKAGE_BUGREPORT ""
+| #define PACKAGE_URL ""
+| /* end confdefs.h. */
+| #include <ac_nonexistent.h>
+configure:3259: checking for library containing strerror
+configure:3290: gcc -o conftest -g -O2 conftest.c >&5
+configure:3290: $? = 0
+configure:3307: result: none required
+configure:3332: checking for a BSD-compatible install
+configure:3400: result: /bin/install -c
+configure:3454: checking for ranlib
+configure:3470: found /bin/ranlib
+configure:3481: result: ranlib
+configure:3505: checking for autoconf
+configure:3521: found /bin/autoconf
+configure:3533: result: autoconf
+configure:3543: checking for cp
+configure:3559: found /bin/cp
+configure:3571: result: cp
+configure:3581: checking for rm
+configure:3597: found /bin/rm
+configure:3609: result: rm
+configure:3625: checking for grep that handles long lines and -e
+configure:3683: result: /bin/grep
+configure:3688: checking for egrep
+configure:3750: result: /bin/grep -E
+configure:3755: checking for ANSI C header files
+configure:3775: gcc -c -g -O2 conftest.c >&5
+configure:3775: $? = 0
+configure:3848: gcc -o conftest -g -O2 conftest.c >&5
+configure:3848: $? = 0
+configure:3848: ./conftest
+configure:3848: $? = 0
+configure:3859: result: yes
+configure:3870: checking for setenv
+configure:3870: gcc -o conftest -g -O2 conftest.c >&5
+configure:3870: $? = 0
+configure:3870: result: yes
+configure:3870: checking for putenv
+configure:3870: gcc -o conftest -g -O2 conftest.c >&5
+configure:3870: $? = 0
+configure:3870: result: yes
+configure:3902: checking for ld used by GCC
+configure:3965: result: /bin/ld
+configure:3972: checking if the linker (/bin/ld) is GNU ld
+GNU ld version 2.24
+configure:3984: result: yes
+configure:3990: checking for va_copy
+configure:4008: gcc -o conftest -g -O2 conftest.c >&5
+configure:4008: $? = 0
+configure:4017: result: yes
+configure:4025: checking for __va_copy
+configure:4043: gcc -o conftest -g -O2 conftest.c >&5
+configure:4043: $? = 0
+configure:4052: result: yes
+configure:4173: checking for tclConfig.sh
+configure:4247: result: /usr/lib64/tclConfig.sh
+configure:4263: checking for tkConfig.sh
+configure:4338: result: /usr/lib64/tkConfig.sh
+configure:4472: checking for wish executable
+configure:4499: result: /usr/bin/wish
+configure:4586: checking for X
+configure:4725: gcc -o conftest -g -O2 conftest.c -lX11 >&5
+configure:4725: $? = 0
+configure:4775: result: libraries , headers
+configure:4874: gcc -o conftest -g -O2 conftest.c -lX11 >&5
+configure:4874: $? = 0
+configure:4972: checking for gethostbyname
+configure:4972: gcc -o conftest -g -O2 conftest.c >&5
+configure:4972: $? = 0
+configure:4972: result: yes
+configure:5069: checking for connect
+configure:5069: gcc -o conftest -g -O2 conftest.c >&5
+configure:5069: $? = 0
+configure:5069: result: yes
+configure:5118: checking for remove
+configure:5118: gcc -o conftest -g -O2 conftest.c >&5
+configure:5118: $? = 0
+configure:5118: result: yes
+configure:5167: checking for shmat
+configure:5167: gcc -o conftest -g -O2 conftest.c >&5
+configure:5167: $? = 0
+configure:5167: result: yes
+configure:5225: checking for IceConnectionNumber in -lICE
+configure:5250: gcc -o conftest -g -O2 conftest.c -lICE >&5
+configure:5250: $? = 0
+configure:5259: result: yes
+configure:5280: checking for XtToolkitInitialize in -lXt
+configure:5305: gcc -o conftest -g -O2 conftest.c -lXt >&5
+configure:5305: $? = 0
+configure:5314: result: yes
+configure:5377: checking for sys/types.h
+configure:5377: gcc -c -g -O2 conftest.c >&5
+configure:5377: $? = 0
+configure:5377: result: yes
+configure:5377: checking for sys/stat.h
+configure:5377: gcc -c -g -O2 conftest.c >&5
+configure:5377: $? = 0
+configure:5377: result: yes
+configure:5377: checking for stdlib.h
+configure:5377: gcc -c -g -O2 conftest.c >&5
+configure:5377: $? = 0
+configure:5377: result: yes
+configure:5377: checking for string.h
+configure:5377: gcc -c -g -O2 conftest.c >&5
+configure:5377: $? = 0
+configure:5377: result: yes
+configure:5377: checking for memory.h
+configure:5377: gcc -c -g -O2 conftest.c >&5
+configure:5377: $? = 0
+configure:5377: result: yes
+configure:5377: checking for strings.h
+configure:5377: gcc -c -g -O2 conftest.c >&5
+configure:5377: $? = 0
+configure:5377: result: yes
+configure:5377: checking for inttypes.h
+configure:5377: gcc -c -g -O2 conftest.c >&5
+configure:5377: $? = 0
+configure:5377: result: yes
+configure:5377: checking for stdint.h
+configure:5377: gcc -c -g -O2 conftest.c >&5
+configure:5377: $? = 0
+configure:5377: result: yes
+configure:5377: checking for unistd.h
+configure:5377: gcc -c -g -O2 conftest.c >&5
+configure:5377: $? = 0
+configure:5377: result: yes
+configure:5391: checking sys/mman.h usability
+configure:5391: gcc -c -g -O2 conftest.c >&5
+configure:5391: $? = 0
+configure:5391: result: yes
+configure:5391: checking sys/mman.h presence
+configure:5391: gcc -E conftest.c
+configure:5391: $? = 0
+configure:5391: result: yes
+configure:5391: checking for sys/mman.h
+configure:5391: result: yes
+configure:5808: creating ./config.status
+
+## ---------------------- ##
+## Running config.status. ##
+## ---------------------- ##
+
+This file was extended by config.status, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES =
+ CONFIG_HEADERS =
+ CONFIG_LINKS =
+ CONFIG_COMMANDS =
+ $ ./config.status
+
+on stravinsky
+
+config.status:770: creating Makefile
+
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+
+ac_cv_build=x86_64-unknown-linux-gnu
+ac_cv_c___va_copy=yes
+ac_cv_c_compiler_gnu=yes
+ac_cv_c_va_copy=yes
+ac_cv_env_CC_set=
+ac_cv_env_CC_value=
+ac_cv_env_CFLAGS_set=
+ac_cv_env_CFLAGS_value=
+ac_cv_env_CPPFLAGS_set=
+ac_cv_env_CPPFLAGS_value=
+ac_cv_env_CPP_set=
+ac_cv_env_CPP_value=
+ac_cv_env_LDFLAGS_set=
+ac_cv_env_LDFLAGS_value=
+ac_cv_env_LIBS_set=
+ac_cv_env_LIBS_value=
+ac_cv_env_XMKMF_set=
+ac_cv_env_XMKMF_value=
+ac_cv_env_build_alias_set=
+ac_cv_env_build_alias_value=
+ac_cv_env_host_alias_set=
+ac_cv_env_host_alias_value=
+ac_cv_env_target_alias_set=
+ac_cv_env_target_alias_value=
+ac_cv_func_connect=yes
+ac_cv_func_gethostbyname=yes
+ac_cv_func_putenv=yes
+ac_cv_func_remove=yes
+ac_cv_func_setenv=yes
+ac_cv_func_shmat=yes
+ac_cv_have_x='have_x=yes ac_x_includes='\'''\'' ac_x_libraries='\'''\'''
+ac_cv_header_inttypes_h=yes
+ac_cv_header_memory_h=yes
+ac_cv_header_stdc=yes
+ac_cv_header_stdint_h=yes
+ac_cv_header_stdlib_h=yes
+ac_cv_header_string_h=yes
+ac_cv_header_strings_h=yes
+ac_cv_header_sys_mman_h=yes
+ac_cv_header_sys_stat_h=yes
+ac_cv_header_sys_types_h=yes
+ac_cv_header_unistd_h=yes
+ac_cv_host=x86_64-unknown-linux-gnu
+ac_cv_lib_ICE_IceConnectionNumber=yes
+ac_cv_lib_Xt_XtToolkitInitialize=yes
+ac_cv_objext=o
+ac_cv_path_EGREP='/bin/grep -E'
+ac_cv_path_GREP=/bin/grep
+ac_cv_path_LD=/bin/ld
+ac_cv_path_install='/bin/install -c'
+ac_cv_prog_AUTOCONF=autoconf
+ac_cv_prog_CP=cp
+ac_cv_prog_CPP='gcc -E'
+ac_cv_prog_RM=rm
+ac_cv_prog_ac_ct_CC=gcc
+ac_cv_prog_ac_ct_RANLIB=ranlib
+ac_cv_prog_cc_c89=
+ac_cv_prog_cc_g=yes
+ac_cv_prog_gnu_ld=yes
+ac_cv_search_strerror='none required'
+ac_cv_target=x86_64-unknown-linux-gnu
+
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+
+ALL_TARGET='tcl'
+AUTOCONF='autoconf'
+CC='gcc'
+CFLAGS='-g -O2'
+CP='cp'
+CPP='gcc -E'
+CPPFLAGS=' -m64 -fPIC'
+DEFS='-DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DHAVE_LIBXT=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_SYS_MMAN_H=1 -DTCL_QROUTER=1 -DLINUX=1 -DSYSV=1 -DVERSION=\"1.4\" -DREVISION=\"7\"'
+ECHO_C=''
+ECHO_N='-n'
+ECHO_T=''
+EGREP='/bin/grep -E'
+EXEEXT=''
+EXTRA_LIB_SPECS='-ldl'
+GREP='/bin/grep'
+INC_SPECS=''
+INSTALL_DATA='${INSTALL} -m 644'
+INSTALL_PROGRAM='${INSTALL}'
+INSTALL_SCRIPT='${INSTALL}'
+INSTALL_TARGET='install-tcl'
+LD='/bin/ld'
+LDDL_FLAGS='-shared -Wl,-soname,$@ -Wl,--version-script=symbol.map'
+LDFLAGS=''
+LD_RUN_PATH=''
+LIBOBJS=''
+LIBS='-lXt '
+LIB_SPECS=' -L/usr/lib64 -ltkstub8.6 -L/usr/lib64 -ltclstub8.6'
+LIB_SPECS_NOSTUB=' -L/usr/lib64 -ltk8.6 -L/usr/lib64 -ltcl8.6'
+LTLIBOBJS=''
+OBJEXT='o'
+PACKAGE_BUGREPORT=''
+PACKAGE_NAME=''
+PACKAGE_STRING=''
+PACKAGE_TARNAME=''
+PACKAGE_URL=''
+PACKAGE_VERSION=''
+PATH_SEPARATOR=':'
+QROUTER_LIB_DIR='share/qrouter'
+RANLIB='ranlib'
+REVISION='7'
+RM='rm'
+SHDLIB_EXT='.so'
+SHELL='/bin/sh'
+SHLIB_CFLAGS='-fPIC'
+SHLIB_LD=''
+SHLIB_LIB_SPECS=''
+STDLIBS=''
+TCL_LIB_DIR='/usr/lib64'
+TK_LIB_DIR='/usr/lib64'
+VERSION='1.4'
+WISH_EXE='/usr/bin/wish'
+XMKMF=''
+X_CFLAGS=''
+X_EXTRA_LIBS=''
+X_LIBS=''
+X_PRE_LIBS=' -lSM -lICE'
+ac_ct_CC='gcc'
+bindir='${exec_prefix}/bin'
+build='x86_64-unknown-linux-gnu'
+build_alias=''
+build_cpu='x86_64'
+build_os='linux-gnu'
+build_vendor='unknown'
+datadir='${datarootdir}'
+datarootdir='${prefix}/share'
+docdir='${datarootdir}/doc/${PACKAGE}'
+dvidir='${docdir}'
+exec_prefix='${prefix}'
+host='x86_64-unknown-linux-gnu'
+host_alias=''
+host_cpu='x86_64'
+host_os='linux-gnu'
+host_vendor='unknown'
+htmldir='${docdir}'
+includedir='${prefix}/include'
+infodir='${datarootdir}/info'
+libdir='${exec_prefix}/lib'
+libexecdir='${exec_prefix}/libexec'
+localedir='${datarootdir}/locale'
+localstatedir='${prefix}/var'
+mandir='${datarootdir}/man'
+oldincludedir='/usr/include'
+pdfdir='${docdir}'
+prefix='/usr/local'
+program_transform_name='s,x,x,'
+psdir='${docdir}'
+sbindir='${exec_prefix}/sbin'
+sharedstatedir='${prefix}/com'
+stub_defs=' -DUSE_TCL_STUBS -DUSE_TK_STUBS'
+sysconfdir='${prefix}/etc'
+target='x86_64-unknown-linux-gnu'
+target_alias=''
+target_cpu='x86_64'
+target_os='linux-gnu'
+target_vendor='unknown'
+
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+
+/* confdefs.h */
+#define PACKAGE_NAME ""
+#define PACKAGE_TARNAME ""
+#define PACKAGE_VERSION ""
+#define PACKAGE_STRING ""
+#define PACKAGE_BUGREPORT ""
+#define PACKAGE_URL ""
+#define STDC_HEADERS 1
+#define HAVE_SETENV 1
+#define HAVE_PUTENV 1
+#define HAVE_VA_COPY 1
+#define HAVE___VA_COPY 1
+#define HAVE_LIBXT 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STRING_H 1
+#define HAVE_MEMORY_H 1
+#define HAVE_STRINGS_H 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_SYS_MMAN_H 1
+#define TCL_QROUTER 1
+#define LINUX 1
+#define SYSV 1
+#define VERSION "1.4"
+#define REVISION "7"
+
+configure: exit 0
diff --git a/config.status b/config.status
new file mode 100755
index 0000000..e52ea93
--- /dev/null
+++ b/config.status
@@ -0,0 +1,942 @@
+#! /bin/sh
+# Generated by configure.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+# Files that config.status was made for.
+config_files=" Makefile"
+
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+ac_cs_config=""
+ac_cs_version="\
+config.status
+configured by ./configure, generated by GNU Autoconf 2.69,
+ with options \"$ac_cs_config\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='/home/tim/gitsrc/qrouter-1.4'
+srcdir='.'
+INSTALL='/bin/install -c'
+test -n "$AWK" || AWK=awk
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+if $ac_cs_recheck; then
+ set X /bin/sh './configure' $ac_configure_extra_args --no-create --no-recursion
+ shift
+ $as_echo "running CONFIG_SHELL=/bin/sh $*" >&6
+ CONFIG_SHELL='/bin/sh'
+ export CONFIG_SHELL
+ exec "$@"
+fi
+
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+cat >>"$ac_tmp/subs1.awk" <<\_ACAWK &&
+S["LTLIBOBJS"]=""
+S["LIBOBJS"]=""
+S["QROUTER_LIB_DIR"]="share/qrouter"
+S["INSTALL_TARGET"]="install-tcl"
+S["ALL_TARGET"]="tcl"
+S["STDLIBS"]=""
+S["LD_RUN_PATH"]=""
+S["SHLIB_CFLAGS"]="-fPIC"
+S["WISH_EXE"]="/usr/bin/wish"
+S["TK_LIB_DIR"]="/usr/lib64"
+S["TCL_LIB_DIR"]="/usr/lib64"
+S["LIB_SPECS_NOSTUB"]=" -L/usr/lib64 -ltk8.6 -L/usr/lib64 -ltcl8.6"
+S["LIB_SPECS"]=" -L/usr/lib64 -ltkstub8.6 -L/usr/lib64 -ltclstub8.6"
+S["INC_SPECS"]=""
+S["EXTRA_LIB_SPECS"]="-ldl"
+S["stub_defs"]=" -DUSE_TCL_STUBS -DUSE_TK_STUBS"
+S["SHLIB_LIB_SPECS"]=""
+S["LDDL_FLAGS"]="-shared -Wl,-soname,$@ -Wl,--version-script=symbol.map"
+S["LD"]="/bin/ld"
+S["SHLIB_LD"]=""
+S["SHDLIB_EXT"]=".so"
+S["X_EXTRA_LIBS"]=""
+S["X_LIBS"]=""
+S["X_PRE_LIBS"]=" -lSM -lICE"
+S["X_CFLAGS"]=""
+S["XMKMF"]=""
+S["EGREP"]="/bin/grep -E"
+S["GREP"]="/bin/grep"
+S["RM"]="rm"
+S["CP"]="cp"
+S["AUTOCONF"]="autoconf"
+S["RANLIB"]="ranlib"
+S["INSTALL_DATA"]="${INSTALL} -m 644"
+S["INSTALL_SCRIPT"]="${INSTALL}"
+S["INSTALL_PROGRAM"]="${INSTALL}"
+S["CPP"]="gcc -E"
+S["OBJEXT"]="o"
+S["EXEEXT"]=""
+S["ac_ct_CC"]="gcc"
+S["CPPFLAGS"]=" -m64 -fPIC"
+S["LDFLAGS"]=""
+S["CFLAGS"]="-g -O2"
+S["CC"]="gcc"
+S["REVISION"]="7"
+S["VERSION"]="1.4"
+S["target_os"]="linux-gnu"
+S["target_vendor"]="unknown"
+S["target_cpu"]="x86_64"
+S["target"]="x86_64-unknown-linux-gnu"
+S["host_os"]="linux-gnu"
+S["host_vendor"]="unknown"
+S["host_cpu"]="x86_64"
+S["host"]="x86_64-unknown-linux-gnu"
+S["build_os"]="linux-gnu"
+S["build_vendor"]="unknown"
+S["build_cpu"]="x86_64"
+S["build"]="x86_64-unknown-linux-gnu"
+S["target_alias"]=""
+S["host_alias"]=""
+S["build_alias"]=""
+S["LIBS"]="-lXt "
+S["ECHO_T"]=""
+S["ECHO_N"]="-n"
+S["ECHO_C"]=""
+S["DEFS"]="-DPACKAGE_NAME=\\\"\\\" -DPACKAGE_TARNAME=\\\"\\\" -DPACKAGE_VERSION=\\\"\\\" -DPACKAGE_STRING=\\\"\\\" -DPACKAGE_BUGREPORT=\\\"\\\" -DPACKAGE_URL=\\\"\\\" -DSTDC_HEADERS=1"\
+" -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DHAVE_LIBXT=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAV"\
+"E_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_SYS_MMAN_H=1 -DTCL_QROUTER=1 -DLINU"\
+"X=1 -DSYSV=1 -DVERSION=\\\"1.4\\\" -DREVISION=\\\"7\\\""
+S["mandir"]="${datarootdir}/man"
+S["localedir"]="${datarootdir}/locale"
+S["libdir"]="${exec_prefix}/lib"
+S["psdir"]="${docdir}"
+S["pdfdir"]="${docdir}"
+S["dvidir"]="${docdir}"
+S["htmldir"]="${docdir}"
+S["infodir"]="${datarootdir}/info"
+S["docdir"]="${datarootdir}/doc/${PACKAGE}"
+S["oldincludedir"]="/usr/include"
+S["includedir"]="${prefix}/include"
+S["localstatedir"]="${prefix}/var"
+S["sharedstatedir"]="${prefix}/com"
+S["sysconfdir"]="${prefix}/etc"
+S["datadir"]="${datarootdir}"
+S["datarootdir"]="${prefix}/share"
+S["libexecdir"]="${exec_prefix}/libexec"
+S["sbindir"]="${exec_prefix}/sbin"
+S["bindir"]="${exec_prefix}/bin"
+S["program_transform_name"]="s,x,x,"
+S["prefix"]="/usr/local"
+S["exec_prefix"]="${prefix}"
+S["PACKAGE_URL"]=""
+S["PACKAGE_BUGREPORT"]=""
+S["PACKAGE_STRING"]=""
+S["PACKAGE_VERSION"]=""
+S["PACKAGE_TARNAME"]=""
+S["PACKAGE_NAME"]=""
+S["PATH_SEPARATOR"]=":"
+S["SHELL"]="/bin/sh"
+_ACAWK
+cat >>"$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+ ac_datarootdir_hack='
+ s&@datadir@&${datarootdir}&g
+ s&@docdir@&${datarootdir}/doc/${PACKAGE}&g
+ s&@infodir@&${datarootdir}/info&g
+ s&@localedir@&${datarootdir}/locale&g
+ s&@mandir@&${datarootdir}/man&g
+ s&\${datarootdir}&${prefix}/share&g' ;;
+esac
+ac_sed_extra="/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}
+
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
diff --git a/def.c b/def.c
index 9930a04..6376b67 100644
--- a/def.c
+++ b/def.c
@@ -37,12 +37,12 @@ int numSpecial = 0; /* Tracks number of specialnets */
#ifndef TCL_QROUTER
/* Find an instance in the instance list. If qrouter */
-/* is compiled with Tcl support, then this routine is */
-/* found in tclqrouter.c and uses hash tables, greatly */
-/* speeding up the read-in of large DEF files. */
+/* is compiled with Tcl support, then this routine */
+/* uses Tcl hash tables, greatly speeding up the */
+/* read-in of large DEF files. */
-static GATE
-DefFindInstance(char *name)
+GATE
+DefFindGate(char *name)
{
GATE ginst;
@@ -53,6 +53,25 @@ DefFindInstance(char *name)
return NULL;
}
+/* Find a net in the list of nets. If qrouter is */
+/* compiled with Tcl support, then this routine */
+/* uses Tcl hash tables, greatly speeding up the */
+/* read-in of large DEF files. */
+
+NET
+DefFindNet(char *name)
+{
+ int i;
+ NET net;
+
+ for (i = 0; i < Numnets; i++) {
+ net = Nlnets[i];
+ if (!strcasecmp(net->netname, name))
+ return net;
+ }
+ return NULL;
+}
+
/* For the non-Tcl version, these are empty placeholders */
static void
@@ -65,13 +84,19 @@ DefHashInstance(GATE gateginfo)
{
}
+static void
+DefHashNet(NET net)
+{
+}
+
#else /* The versions using TCL hash tables */
#include <tk.h>
-/* This hash table speeds up DEF file reading */
+/* These hash tables speed up DEF file reading */
static Tcl_HashTable InstanceTable;
+static Tcl_HashTable NetTable;
/*--------------------------------------------------------------*/
/* Cell macro lookup based on the hash table */
@@ -83,10 +108,11 @@ DefHashInit(void)
/* Initialize the macro hash table */
Tcl_InitHashTable(&InstanceTable, TCL_STRING_KEYS);
+ Tcl_InitHashTable(&NetTable, TCL_STRING_KEYS);
}
-static GATE
-DefFindInstance(char *name)
+GATE
+DefFindGate(char *name)
{
GATE ginst;
Tcl_HashEntry *entry;
@@ -96,6 +122,20 @@ DefFindInstance(char *name)
return ginst;
}
+NET
+DefFindNet(char *name)
+{
+ NET net;
+ Tcl_HashEntry *entry;
+
+ // Guard against calls to find nets before DEF file is read
+ if (Numnets == 0) return NULL;
+
+ entry = Tcl_FindHashEntry(&NetTable, name);
+ net = (entry) ? (NET)Tcl_GetHashValue(entry) : NULL;
+ return net;
+}
+
/*--------------------------------------------------------------*/
/* Cell macro hash table generation */
/* Given an instance record, create an entry in the hash table */
@@ -115,6 +155,24 @@ DefHashInstance(GATE gateginfo)
Tcl_SetHashValue(entry, (ClientData)gateginfo);
}
+/*--------------------------------------------------------------*/
+/* Net hash table generation */
+/* Given a net record, create an entry in the hash table for */
+/* the net name, with the record entry pointing to the net */
+/* record. */
+/*--------------------------------------------------------------*/
+
+static void
+DefHashNet(NET net)
+{
+ int new;
+ Tcl_HashEntry *entry;
+
+ entry = Tcl_CreateHashEntry(&NetTable, net->netname, &new);
+ if (entry != NULL)
+ Tcl_SetHashValue(entry, (ClientData)net);
+}
+
#endif /* TCL_QROUTER */
/*
@@ -125,7 +183,7 @@ DefHashInstance(GATE gateginfo)
* Parse a network route statement from the DEF file.
* If "special" is 1, then, add the geometry to the
* list of obstructions. If "special" is 0, then read
- * the geometry into a route structure for the net.
+ * the geometry into a route structure for the net.
*
* Results:
* Returns the last token encountered.
@@ -145,6 +203,7 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
DSEG lr, drect;
struct point_ refp;
char valid = FALSE; /* is there a valid reference point? */
+ char noobstruct;
char initial = TRUE;
struct dseg_ locarea;
double x, y, lx, ly, w, hw, s;
@@ -158,6 +217,12 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
/* Set pitches and allocate memory for Obs[] if we haven't yet. */
set_num_channels();
+ /* Don't create obstructions or routes on routed specialnets inputs */
+ /* except for power and ground nets. */
+ noobstruct = ((special == (char)1) && (!(net->flags & NET_IGNORED)) &&
+ (net->netnum != VDD_NET) && (net->netnum != GND_NET)) ?
+ TRUE : FALSE;
+
while (initial || (token = LefNextToken(f, TRUE)) != NULL)
{
/* Get next point, token "NEW", or via name */
@@ -174,13 +239,14 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
if (routeLayer < 0)
{
- LefError("Unknown layer type \"%s\" for NEW route\n", token);
+ LefError(DEF_ERROR, "Unknown layer type \"%s\" for NEW route\n", token);
continue;
}
else if (routeLayer >= Num_layers)
{
- LefError("DEF file contains layer \"%s\" which is not allowed "
- "by the layer limit setting of %d\n", token, Num_layers);
+ LefError(DEF_ERROR, "DEF file contains layer \"%s\" which is"
+ " not allowed by the layer limit setting of %d\n",
+ token, Num_layers);
continue;
}
paintLayer = routeLayer;
@@ -191,7 +257,7 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
token = LefNextToken(f, TRUE);
if (sscanf(token, "%lg", &w) != 1)
{
- LefError("Bad width in special net\n");
+ LefError(DEF_ERROR, "Bad width in special net\n");
continue;
}
if (w != 0)
@@ -224,7 +290,7 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
else if (valid == FALSE)
{
- LefError("Route has via name \"%s\" but no points!\n", token);
+ LefError(DEF_ERROR, "Route has via name \"%s\" but no points!\n", token);
continue;
}
lefl = LefFindLayer(token);
@@ -235,14 +301,35 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
if (lefl != NULL)
{
if (lefl->lefClass == CLASS_VIA) {
+
+ // Note: layers may be defined in any order, metal or cut.
+ // Check both via.area and via.lr layers, and reject those
+ // that exceed the number of metal layers (those are cuts).
+
paintLayer = Num_layers - 1;
routeLayer = -1;
- lr = lefl->info.via.lr;
- while (lr != NULL) {
+ if (lefl->info.via.area.layer < Num_layers) {
+ routeLayer = lefl->info.via.area.layer;
+ if (routeLayer < paintLayer) paintLayer = routeLayer;
+ if ((routeLayer >= 0) && (special == (char)1) &&
+ (valid == TRUE) && (noobstruct == FALSE)) {
+ s = LefGetRouteSpacing(routeLayer);
+ drect = (DSEG)malloc(sizeof(struct dseg_));
+ drect->x1 = x + (lefl->info.via.area.x1 / 2.0) - s;
+ drect->x2 = x + (lefl->info.via.area.x2 / 2.0) + s;
+ drect->y1 = y + (lefl->info.via.area.y1 / 2.0) - s;
+ drect->y2 = y + (lefl->info.via.area.y2 / 2.0) + s;
+ drect->layer = routeLayer;
+ drect->next = UserObs;
+ UserObs = drect;
+ }
+ }
+ for (lr = lefl->info.via.lr; lr; lr = lr->next) {
+ if (lr->layer >= Num_layers) continue;
routeLayer = lr->layer;
if (routeLayer < paintLayer) paintLayer = routeLayer;
if ((routeLayer >= 0) && (special == (char)1) &&
- (valid == TRUE)) {
+ (valid == TRUE) && (noobstruct == FALSE)) {
s = LefGetRouteSpacing(routeLayer);
drect = (DSEG)malloc(sizeof(struct dseg_));
drect->x1 = x + (lr->x1 / 2.0) - s;
@@ -253,7 +340,6 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
drect->next = UserObs;
UserObs = drect;
}
- lr = lr->next;
}
if (routeLayer == -1) paintLayer = lefl->type;
}
@@ -265,11 +351,11 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
}
else
{
- LefError("Error: Via \"%s\" named but undefined.\n", token);
+ LefError(DEF_ERROR, "Error: Via \"%s\" named but undefined.\n", token);
paintLayer = routeLayer;
}
if ((special == (char)0) && (paintLayer >= 0) &&
- (paintLayer < Num_layers)) {
+ (paintLayer < (Num_layers - 1))) {
newRoute = (SEG)malloc(sizeof(struct seg_));
newRoute->segtype = ST_VIA;
@@ -294,14 +380,18 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
routednet->segments = newRoute;
}
else {
- if (paintLayer >= Num_layers)
- LefError("Via \"%s\" exceeds layer limit setting!\n", token);
- else
- LefError("Via \"%s\" does not define a metal layer!\n", token);
+ if (paintLayer >= (Num_layers - 1))
+ /* Not necessarily an error to have predefined geometry */
+ /* above the route layer limit. */
+ LefError(DEF_WARNING, "Via \"%s\" exceeds layer "
+ "limit setting.\n", token);
+ else if (special == (char)0)
+ LefError(DEF_ERROR, "Via \"%s\" does not define a"
+ " metal layer!\n", token);
}
}
else
- LefError("Via name \"%s\" unknown in route.\n", token);
+ LefError(DEF_ERROR, "Via name \"%s\" unknown in route.\n", token);
}
else
{
@@ -320,18 +410,28 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
{
if (valid == FALSE)
{
- LefError("No reference point for \"*\" wildcard\n");
+ LefError(DEF_ERROR, "No reference point for \"*\" wildcard\n");
goto endCoord;
}
}
else if (sscanf(token, "%lg", &x) == 1)
{
x /= oscale; // In microns
- refp.x1 = (int)((x - Xlowerbound + EPS) / PitchX[paintLayer]);
+ /* Note: offsets and stubs are always less than half a pitch, */
+ /* so round to the nearest integer grid point. */
+ refp.x1 = (int)(0.5 + ((x - Xlowerbound + EPS) / PitchX));
+
+ /* Flag offsets that are more than 1/3 track pitch, as they */
+ /* need careful analyzing (in route_set_connections()) to */
+ /* separate the main route from the stub route or offest. */
+ if ((special == (char)0) && ABSDIFF((double)refp.x1,
+ (x - Xlowerbound) / PitchX) > 0.33) {
+ if (routednet) routednet->flags |= RT_CHECK;
+ }
}
else
{
- LefError("Cannot parse X coordinate.\n");
+ LefError(DEF_ERROR, "Cannot parse X coordinate.\n");
goto endCoord;
}
token = LefNextToken(f, TRUE); /* read Y */
@@ -339,7 +439,7 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
{
if (valid == FALSE)
{
- LefError("No reference point for \"*\" wildcard\n");
+ LefError(DEF_ERROR, "No reference point for \"*\" wildcard\n");
if (newRoute != NULL) {
free(newRoute);
newRoute = NULL;
@@ -350,11 +450,16 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
else if (sscanf(token, "%lg", &y) == 1)
{
y /= oscale; // In microns
- refp.y1 = (int)((y - Ylowerbound + EPS) / PitchY[paintLayer]);
+ refp.y1 = (int)(0.5 + ((y - Ylowerbound + EPS) / PitchY));
+
+ if ((special == (u_char)0) && ABSDIFF((double)refp.y1,
+ (y - Ylowerbound) / PitchY) > 0.33) {
+ if (routednet) routednet->flags |= RT_CHECK;
+ }
}
else
{
- LefError("Cannot parse Y coordinate.\n");
+ LefError(DEF_ERROR, "Cannot parse Y coordinate.\n");
goto endCoord;
}
@@ -369,7 +474,7 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
/* Skip over nonmanhattan segments, reset the reference */
/* point, and output a warning. */
- LefError("Can't deal with nonmanhattan geometry in route.\n");
+ LefError(DEF_ERROR, "Can't deal with nonmanhattan geometry in route.\n");
locarea.x1 = refp.x1;
locarea.y1 = refp.y1;
lx = x;
@@ -380,8 +485,8 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
locarea.x2 = refp.x1;
locarea.y2 = refp.y1;
- if (special == (char)1) {
- if (valid == TRUE) {
+ if (special != (char)0) {
+ if ((valid == TRUE) && (noobstruct == FALSE)) {
s = LefGetRouteSpacing(routeLayer);
hw = w / 2;
drect = (DSEG)malloc(sizeof(struct dseg_));
@@ -417,10 +522,14 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
else if ((paintLayer >= 0) && (paintLayer < Num_layers)) {
newRoute = (SEG)malloc(sizeof(struct seg_));
newRoute->segtype = ST_WIRE;
- newRoute->x1 = locarea.x1;
- newRoute->x2 = locarea.x2;
- newRoute->y1 = locarea.y1;
- newRoute->y2 = locarea.y2;
+ // NOTE: Segments are added at the front of the linked
+ // list, so they are backwards from the entry in the
+ // DEF file. Therefore the first and second coordinates
+ // must be swapped, or the segments become disjoint.
+ newRoute->x1 = locarea.x2;
+ newRoute->x2 = locarea.x1;
+ newRoute->y1 = locarea.y2;
+ newRoute->y2 = locarea.y1;
newRoute->layer = paintLayer;
if (routednet == NULL) {
@@ -438,7 +547,7 @@ DefAddRoutes(FILE *f, float oscale, NET net, char special)
routednet->segments = newRoute;
}
else if (paintLayer >= Num_layers) {
- LefError("Route layer exceeds layer limit setting!\n");
+ LefError(DEF_ERROR, "Route layer exceeds layer limit setting!\n");
}
}
@@ -447,14 +556,22 @@ endCoord:
while (*token != ')')
token = LefNextToken(f, TRUE);
}
-
}
- /* Make sure we have allocated memory for nets */
- allocate_obs_array();
-
- /* Write the route(s) back into Obs[] */
- writeback_all_routes(net);
+ /* Remove routes that are less than 1 track long; these are stub */
+ /* routes to terminals that did not require a specialnets entry. */
+
+ if (routednet && (net->routes == routednet) && (routednet->flags & RT_CHECK)) {
+ int ix, iy;
+ SEG seg;
+ seg = routednet->segments;
+ if (seg && seg->next == NULL) {
+ ix = ABSDIFF(seg->x1, seg->x2);
+ iy = ABSDIFF(seg->y1, seg->y2);
+ if ((ix == 0 && iy == 1) || (ix == 1 && iy == 0))
+ remove_top_route(net);
+ }
+ }
return token; /* Pass back the last token found */
}
@@ -484,13 +601,13 @@ DefReadGatePin(NET net, NODE node, char *instname, char *pinname, double *home)
int gridx, gridy;
DPOINT dp;
- g = DefFindInstance(instname);
+ g = DefFindGate(instname);
if (g) {
gateginfo = g->gatetype;
if (!gateginfo) {
- LefError("Endpoint %s/%s of net %s not found\n",
+ LefError(DEF_ERROR, "Endpoint %s/%s of net %s not found\n",
instname, pinname, net->netname);
return;
}
@@ -509,23 +626,21 @@ DefReadGatePin(NET net, NODE node, char *instname, char *pinname, double *home)
// but not centered on gridpoints should be marked
// in some way, and handled appropriately.
- gridx = (int)((drect->x1 - Xlowerbound) /
- PitchX[drect->layer]) - 1;
+ gridx = (int)((drect->x1 - Xlowerbound) / PitchX) - 1;
if (gridx < 0) gridx = 0;
while (1) {
- dx = (gridx * PitchX[drect->layer]) + Xlowerbound;
+ dx = (gridx * PitchX) + Xlowerbound;
if (dx > drect->x2 + home[drect->layer] - EPS) break;
if (dx < drect->x1 - home[drect->layer] + EPS) {
gridx++;
continue;
}
- gridy = (int)((drect->y1 - Ylowerbound) /
- PitchY[drect->layer]) - 1;
+ gridy = (int)((drect->y1 - Ylowerbound) / PitchY) - 1;
if (gridy < 0) gridy = 0;
while (1) {
- dy = (gridy * PitchY[drect->layer]) + Ylowerbound;
+ dy = (gridy * PitchY) + Ylowerbound;
if (dy > drect->y2 + home[drect->layer] - EPS) break;
if (dy < drect->y1 - home[drect->layer] + EPS) {
gridy++;
@@ -579,7 +694,11 @@ DefReadGatePin(NET net, NODE node, char *instname, char *pinname, double *home)
* Read a NETS or SPECIALNETS section from a DEF file.
*
* Results:
- * None.
+ * Return the total number of fixed or cover nets,
+ * excluding power and ground nets. This gives the
+ * base number of nets to be copied verbatim from
+ * input to output (used only for SPECIALNETS, as
+ * regular nets are tracked with the NET_IGNORED flag).
*
* Side Effects:
* Many. Networks are created, and geometry may be
@@ -594,14 +713,16 @@ enum def_netprop_keys {
DEF_NETPROP_COVER, DEF_NETPROP_SHAPE, DEF_NETPROP_SOURCE,
DEF_NETPROP_WEIGHT, DEF_NETPROP_PROPERTY};
-static void
+static int
DefReadNets(FILE *f, char *sname, float oscale, char special, int total)
{
char *token;
int keyword, subkey;
int i, processed = 0;
int nodeidx;
+ int fixed = 0;
char instname[MAX_NAME_LEN], pinname[MAX_NAME_LEN];
+ u_char is_new;
NET net;
int netidx;
@@ -641,6 +762,7 @@ DefReadNets(FILE *f, char *sname, float oscale, char special, int total)
}
}
else {
+ netidx = Numnets;
Nlnets = (NET *)realloc(Nlnets, (Numnets + total) * sizeof(NET));
for (i = Numnets; i < (Numnets + total); i++) Nlnets[i] = NULL;
}
@@ -650,7 +772,7 @@ DefReadNets(FILE *f, char *sname, float oscale, char special, int total)
keyword = Lookup(token, net_keys);
if (keyword < 0)
{
- LefError("Unknown keyword \"%s\" in NET "
+ LefError(DEF_WARNING, "Unknown keyword \"%s\" in NET "
"definition; ignoring.\n", token);
LefEndStatement(f);
continue;
@@ -662,31 +784,40 @@ DefReadNets(FILE *f, char *sname, float oscale, char special, int total)
/* Get net name */
token = LefNextToken(f, TRUE);
+ net = DefFindNet(token);
+
+ if (net == NULL) {
+ net = (NET)malloc(sizeof(struct net_));
+ Nlnets[Numnets++] = net;
+ net->netorder = 0;
+ net->numnodes = 0;
+ net->flags = 0;
+ net->netname = strdup(token);
+ net->netnodes = (NODE)NULL;
+ net->noripup = (NETLIST)NULL;
+ net->routes = (ROUTE)NULL;
+ net->xmin = net->ymin = 0;
+ net->xmax = net->ymax = 0;
+
+ // Net numbers start at MIN_NET_NUMBER for regular nets,
+ // use VDD_NET and GND_NET for power and ground, and 0
+ // is not a valid net number.
+
+ if (vddnet && !strcmp(token, vddnet))
+ net->netnum = VDD_NET;
+ else if (gndnet && !strcmp(token, gndnet))
+ net->netnum = GND_NET;
+ else
+ net->netnum = netidx++;
+ DefHashNet(net);
- net = (NET)malloc(sizeof(struct net_));
- Nlnets[Numnets++] = net;
- net->netorder = 0;
- net->numnodes = 0;
- net->flags = 0;
- net->netname = strdup(token);
- net->netnodes = (NODE)NULL;
- net->noripup = (NETLIST)NULL;
- net->routes = (ROUTE)NULL;
- net->xmin = net->ymin = 0;
- net->xmax = net->ymax = 0;
-
- // Net numbers start at MIN_NET_NUMBER for regular nets,
- // use VDD_NET and GND_NET for power and ground, and 0
- // is not a valid net number.
-
- if (vddnet && !strcmp(token, vddnet))
- net->netnum = VDD_NET;
- else if (gndnet && !strcmp(token, gndnet))
- net->netnum = GND_NET;
- else
- net->netnum = netidx++;
-
- nodeidx = 0;
+ nodeidx = 0;
+ is_new = TRUE;
+ }
+ else {
+ nodeidx = net->numnodes;
+ is_new = FALSE;
+ }
/* Update the record of the number of nets processed */
/* and spit out a message for every 5% finished. */
@@ -732,7 +863,7 @@ DefReadNets(FILE *f, char *sname, float oscale, char special, int total)
subkey = Lookup(token, net_property_keys);
if (subkey < 0)
{
- LefError("Unknown net property \"%s\" in "
+ LefError(DEF_WARNING, "Unknown net property \"%s\" in "
"NET definition; ignoring.\n", token);
continue;
}
@@ -745,24 +876,29 @@ DefReadNets(FILE *f, char *sname, float oscale, char special, int total)
/* Ignore this too, along with the next keyword */
token = LefNextToken(f, TRUE);
break;
+ case DEF_NETPROP_FIXED:
+ case DEF_NETPROP_COVER:
+ /* Read in fixed nets like regular nets but mark
+ * them as NET_IGNORED. HOWEVER, if the net
+ * already exists and is not marked NET_IGNORED,
+ * then don't force it to be ignored. That is
+ * particularly an issue for a net like power or
+ * ground, which may need to be routed like a
+ * regular net but also has fixed portions. */
+ if (is_new) {
+ net->flags |= NET_IGNORED;
+ fixed++;
+ }
+ // fall through
case DEF_NETPROP_ROUTED:
// Read in the route; qrouter now takes
// responsibility for this route.
while (token && (*token != ';'))
token = DefAddRoutes(f, oscale, net, special);
- break;
- case DEF_NETPROP_FIXED:
- case DEF_NETPROP_COVER:
- // Treat fixed nets like specialnets: read them
- // in as obstructions, and write them out as-is.
- // Use special = 2 so it is treated like a
- // specialnet but does not expect the specialnet
- // syntax (unless it is, in fact, a specialnet
- // entry).
-
- while (token && (*token != ';'))
- token = DefAddRoutes(f, oscale, net,
- (special == (char)0) ? (char)2 : special);
+ // Treat power and ground nets in specialnets as fixed
+ if (subkey == DEF_NETPROP_ROUTED && special == (char)1)
+ if (net->netnum == VDD_NET || net->netnum == GND_NET)
+ fixed++;
break;
}
}
@@ -771,7 +907,7 @@ DefReadNets(FILE *f, char *sname, float oscale, char special, int total)
case DEF_NET_END:
if (!LefParseEndStatement(f, sname))
{
- LefError("Net END statement missing.\n");
+ LefError(DEF_ERROR, "Net END statement missing.\n");
keyword = -1;
}
break;
@@ -801,8 +937,9 @@ DefReadNets(FILE *f, char *sname, float oscale, char special, int total)
(special) ? " special" : "");
}
else
- LefError("Warning: Number of nets read (%d) does not match "
+ LefError(DEF_WARNING, "Warning: Number of nets read (%d) does not match "
"the number declared (%d).\n", processed, total);
+ return fixed;
}
/*
@@ -853,7 +990,7 @@ DefReadLocation(gate, f, oscale)
keyword = Lookup(token, orientations);
if (keyword < 0)
{
- LefError("Unknown macro orientation \"%s\".\n", token);
+ LefError(DEF_ERROR, "Unknown macro orientation \"%s\".\n", token);
return -1;
}
@@ -877,7 +1014,7 @@ DefReadLocation(gate, f, oscale)
case DEF_WEST:
case DEF_FLIPPED_EAST:
case DEF_FLIPPED_WEST:
- LefError("Error: Cannot handle 90-degree rotated components!\n");
+ LefError(DEF_ERROR, "Error: Cannot handle 90-degree rotated components!\n");
break;
}
@@ -891,7 +1028,7 @@ DefReadLocation(gate, f, oscale)
return 0;
parse_error:
- LefError("Cannot parse location: must be ( X Y ) orient\n");
+ LefError(DEF_ERROR, "Cannot parse location: must be ( X Y ) orient\n");
return -1;
}
@@ -979,7 +1116,7 @@ DefReadPins(FILE *f, char *sname, float oscale, int total)
if (keyword < 0)
{
- LefError("Unknown keyword \"%s\" in PINS "
+ LefError(DEF_WARNING, "Unknown keyword \"%s\" in PINS "
"definition; ignoring.\n", token);
LefEndStatement(f);
continue;
@@ -997,7 +1134,7 @@ DefReadPins(FILE *f, char *sname, float oscale, int total)
token = LefNextToken(f, TRUE);
if (sscanf(token, "%2047s", pinname) != 1)
{
- LefError("Bad pin statement: Need pin name\n");
+ LefError(DEF_ERROR, "Bad pin statement: Need pin name\n");
LefEndStatement(f);
break;
}
@@ -1014,6 +1151,7 @@ DefReadPins(FILE *f, char *sname, float oscale, int total)
gate->taps = (DSEG *)malloc(sizeof(DSEG));
gate->noderec = (NODE *)malloc(sizeof(NODE));
gate->direction = (u_char *)malloc(sizeof(u_char));
+ gate->area = (float *)malloc(sizeof(float));
gate->netnum = (int *)malloc(sizeof(int));
gate->node = (char **)malloc(sizeof(char *));
gate->taps[0] = NULL;
@@ -1021,6 +1159,7 @@ DefReadPins(FILE *f, char *sname, float oscale, int total)
gate->netnum[0] = -1;
gate->node[0] = NULL;
gate->direction[0] = PORT_CLASS_DEFAULT;
+ gate->area[0] = 0.0;
/* Now do a search through the line for "+" entries */
/* And process each. */
@@ -1034,7 +1173,7 @@ DefReadPins(FILE *f, char *sname, float oscale, int total)
subkey = Lookup(token, pin_property_keys);
if (subkey < 0)
{
- LefError("Unknown pin property \"%s\" in "
+ LefError(DEF_WARNING, "Unknown pin property \"%s\" in "
"PINS definition; ignoring.\n", token);
continue;
}
@@ -1050,21 +1189,24 @@ DefReadPins(FILE *f, char *sname, float oscale, int total)
token = LefNextToken(f, TRUE);
subkey = Lookup(token, pin_classes);
if (subkey < 0)
- LefError("Unknown pin class %s\n", token);
+ LefError(DEF_ERROR, "Unknown pin class %s\n", token);
else
gate->direction[0] = subkey;
break;
case DEF_PINS_PROP_LAYER:
curlayer = LefReadLayer(f, FALSE);
currect = LefReadRect(f, curlayer, oscale);
- gate->width = currect->x2 - currect->x1;
- gate->height = currect->y2 - currect->y1;
+ /* Warn if pin is on layer above routing layer limit? */
+ if (currect) {
+ gate->width = currect->x2 - currect->x1;
+ gate->height = currect->y2 - currect->y1;
+ }
break;
case DEF_PINS_PROP_USE:
token = LefNextToken(f, TRUE);
subkey = Lookup(token, pin_uses);
if (subkey < 0)
- LefError("Unknown pin use %s\n", token);
+ LefError(DEF_ERROR, "Unknown pin use %s\n", token);
else
pin_use = subkey;
break;
@@ -1105,8 +1247,8 @@ DefReadPins(FILE *f, char *sname, float oscale, int total)
DefHashInstance(gate);
}
else {
- LefError("Pin %s is defined outside of route layer area!\n",
- pinname);
+ LefError(DEF_ERROR, "Pin %s is defined outside of route "
+ "layer area!\n", pinname);
free(gate->taps);
free(gate->noderec);
free(gate->direction);
@@ -1120,7 +1262,7 @@ DefReadPins(FILE *f, char *sname, float oscale, int total)
case DEF_PINS_END:
if (!LefParseEndStatement(f, sname))
{
- LefError("Pins END statement missing.\n");
+ LefError(DEF_ERROR, "Pins END statement missing.\n");
keyword = -1;
}
if (pin_use != PORT_USE_DEFAULT && gate->direction[0] ==
@@ -1153,7 +1295,7 @@ DefReadPins(FILE *f, char *sname, float oscale, int total)
Fprintf(stdout, " Processed %d pins total.\n", processed);
}
else
- LefError("Warning: Number of pins read (%d) does not match "
+ LefError(DEF_WARNING, "Warning: Number of pins read (%d) does not match "
"the number declared (%d).\n", processed, total);
}
@@ -1210,7 +1352,7 @@ DefReadVias(f, sname, oscale, total)
if (keyword < 0)
{
- LefError("Unknown keyword \"%s\" in VIAS "
+ LefError(DEF_WARNING, "Unknown keyword \"%s\" in VIAS "
"definition; ignoring.\n", token);
LefEndStatement(f);
continue;
@@ -1228,7 +1370,7 @@ DefReadVias(f, sname, oscale, total)
token = LefNextToken(f, TRUE);
if (sscanf(token, "%2047s", vianame) != 1)
{
- LefError("Bad via statement: Need via name\n");
+ LefError(DEF_ERROR, "Bad via statement: Need via name\n");
LefEndStatement(f);
break;
}
@@ -1246,6 +1388,10 @@ DefReadVias(f, sname, oscale, total)
lefl->info.via.area.layer = -1;
lefl->info.via.cell = (GATE)NULL;
lefl->info.via.lr = (DSEG)NULL;
+ /* Note: "generated" flag only refers to vias that */
+ /* are internally generated by qrouter. All others */
+ /* in the DEF file are read/written verbatim. */
+ lefl->info.via.generated = FALSE;
lefl->lefName = strdup(token);
lefl->next = LefInfo;
@@ -1253,7 +1399,8 @@ DefReadVias(f, sname, oscale, total)
}
else
{
- LefError("Warning: Composite via \"%s\" redefined.\n", vianame);
+ LefError(DEF_WARNING, "Warning: Composite via \"%s\" "
+ "redefined.\n", vianame);
lefl = LefRedefined(lefl, vianame);
}
@@ -1269,7 +1416,7 @@ DefReadVias(f, sname, oscale, total)
subkey = Lookup(token, via_property_keys);
if (subkey < 0)
{
- LefError("Unknown via property \"%s\" in "
+ LefError(DEF_WARNING, "Unknown via property \"%s\" in "
"VIAS definition; ignoring.\n", token);
continue;
}
@@ -1286,7 +1433,7 @@ DefReadVias(f, sname, oscale, total)
case DEF_VIAS_END:
if (!LefParseEndStatement(f, sname))
{
- LefError("Vias END statement missing.\n");
+ LefError(DEF_ERROR, "Vias END statement missing.\n");
keyword = -1;
}
break;
@@ -1299,7 +1446,7 @@ DefReadVias(f, sname, oscale, total)
Fprintf(stdout, " Processed %d vias total.\n", processed);
}
else
- LefError("Warning: Number of vias read (%d) does not match "
+ LefError(DEF_WARNING, "Warning: Number of vias read (%d) does not match "
"the number declared (%d).\n", processed, total);
}
@@ -1343,7 +1490,7 @@ DefReadBlockages(FILE *f, char *sname, float oscale, int total)
if (keyword < 0)
{
- LefError("Unknown keyword \"%s\" in BLOCKAGE "
+ LefError(DEF_WARNING, "Unknown keyword \"%s\" in BLOCKAGE "
"definition; ignoring.\n", token);
LefEndStatement(f);
continue;
@@ -1372,7 +1519,7 @@ DefReadBlockages(FILE *f, char *sname, float oscale, int total)
}
else
{
- LefError("Bad blockage statement: Need layer name\n");
+ LefError(DEF_ERROR, "Bad blockage statement: Need layer name\n");
LefEndStatement(f);
break;
}
@@ -1381,7 +1528,7 @@ DefReadBlockages(FILE *f, char *sname, float oscale, int total)
case DEF_BLOCK_END:
if (!LefParseEndStatement(f, sname))
{
- LefError("Blockage END statement missing.\n");
+ LefError(DEF_ERROR, "Blockage END statement missing.\n");
keyword = -1;
}
break;
@@ -1394,7 +1541,7 @@ DefReadBlockages(FILE *f, char *sname, float oscale, int total)
Fprintf(stdout, " Processed %d blockages total.\n", processed);
}
else
- LefError("Warning: Number of blockages read (%d) does not match "
+ LefError(DEF_WARNING, "Warning: Number of blockages read (%d) does not match "
"the number declared (%d).\n", processed, total);
}
@@ -1406,7 +1553,7 @@ DefReadBlockages(FILE *f, char *sname, float oscale, int total)
* Read a COMPONENTS section from a DEF file.
*
* Results:
- * None.
+ * 0 on success, 1 on fatal error.
*
* Side Effects:
* Many. Cell instances are created and added to
@@ -1423,7 +1570,7 @@ enum def_prop_keys {
DEF_PROP_REGION, DEF_PROP_GENERATE, DEF_PROP_PROPERTY,
DEF_PROP_EEQMASTER};
-static void
+static int
DefReadComponents(FILE *f, char *sname, float oscale, int total)
{
GATE gateginfo;
@@ -1435,6 +1582,7 @@ DefReadComponents(FILE *f, char *sname, float oscale, int total)
char OK;
DSEG drect, newrect;
double tmp;
+ int err_fatal = 0;
static char *component_keys[] = {
"-",
@@ -1463,7 +1611,7 @@ DefReadComponents(FILE *f, char *sname, float oscale, int total)
if (keyword < 0)
{
- LefError("Unknown keyword \"%s\" in COMPONENT "
+ LefError(DEF_WARNING, "Unknown keyword \"%s\" in COMPONENT "
"definition; ignoring.\n", token);
LefEndStatement(f);
continue;
@@ -1481,8 +1629,10 @@ DefReadComponents(FILE *f, char *sname, float oscale, int total)
token = LefNextToken(f, TRUE);
if (sscanf(token, "%511s", usename) != 1)
{
- LefError("Bad component statement: Need use and macro names\n");
+ LefError(DEF_ERROR, "Bad component statement: Need use "
+ "and macro names\n");
LefEndStatement(f);
+ err_fatal++;
break;
}
token = LefNextToken(f, TRUE);
@@ -1496,9 +1646,10 @@ DefReadComponents(FILE *f, char *sname, float oscale, int total)
}
}
if (!OK) {
- LefError("Could not find a macro definition for \"%s\"\n",
+ LefError(DEF_ERROR, "Could not find a macro definition for \"%s\"\n",
token);
gate = NULL;
+ err_fatal++;
}
else {
gate = (GATE)malloc(sizeof(struct gate_));
@@ -1518,7 +1669,7 @@ DefReadComponents(FILE *f, char *sname, float oscale, int total)
subkey = Lookup(token, property_keys);
if (subkey < 0)
{
- LefError("Unknown component property \"%s\" in "
+ LefError(DEF_WARNING, "Unknown component property \"%s\" in "
"COMPONENT definition; ignoring.\n", token);
continue;
}
@@ -1553,6 +1704,7 @@ DefReadComponents(FILE *f, char *sname, float oscale, int total)
gate->taps = (DSEG *)malloc(gate->nodes * sizeof(DSEG));
gate->noderec = (NODE *)malloc(gate->nodes * sizeof(NODE));
gate->direction = (u_char *)malloc(gate->nodes * sizeof(u_char));
+ gate->area = (float *)malloc(gate->nodes * sizeof(float));
gate->netnum = (int *)malloc(gate->nodes * sizeof(int));
gate->node = (char **)malloc(gate->nodes * sizeof(char *));
@@ -1565,16 +1717,19 @@ DefReadComponents(FILE *f, char *sname, float oscale, int total)
gate->node[i] = gateginfo->node[i]; /* copy pointer */
gate->direction[i] = gateginfo->direction[i]; /* copy */
+ gate->area[i] = gateginfo->area[i];
gate->taps[i] = (DSEG)NULL;
/* Global power/ground bus check */
- if (vddnet && !strcmp(gate->node[i], vddnet)) {
+ if (vddnet && gate->node[i] &&
+ !strcmp(gate->node[i], vddnet)) {
/* Create a placeholder node with no taps */
gate->netnum[i] = VDD_NET;
gate->noderec[i] = (NODE)calloc(1, sizeof(struct node_));
gate->noderec[i]->netnum = VDD_NET;
}
- else if (gndnet && !strcmp(gate->node[i], gndnet)) {
+ else if (gndnet && gate->node[i] &&
+ !strcmp(gate->node[i], gndnet)) {
/* Create a placeholder node with no taps */
gate->netnum[i] = GND_NET;
gate->noderec[i] = (NODE)calloc(1, sizeof(struct node_));
@@ -1586,13 +1741,15 @@ DefReadComponents(FILE *f, char *sname, float oscale, int total)
}
/* Make a copy of the gate nodes and adjust for */
- /* instance position */
+ /* instance position and number of layers */
for (drect = gateginfo->taps[i]; drect; drect = drect->next) {
- newrect = (DSEG)malloc(sizeof(struct dseg_));
- *newrect = *drect;
- newrect->next = gate->taps[i];
- gate->taps[i] = newrect;
+ if (drect->layer < Num_layers) {
+ newrect = (DSEG)malloc(sizeof(struct dseg_));
+ *newrect = *drect;
+ newrect->next = gate->taps[i];
+ gate->taps[i] = newrect;
+ }
}
for (drect = gate->taps[i]; drect; drect = drect->next) {
@@ -1631,10 +1788,12 @@ DefReadComponents(FILE *f, char *sname, float oscale, int total)
/* Make a copy of the gate obstructions and adjust */
/* for instance position */
for (drect = gateginfo->obs; drect; drect = drect->next) {
- newrect = (DSEG)malloc(sizeof(struct dseg_));
- *newrect = *drect;
- newrect->next = gate->obs;
- gate->obs = newrect;
+ if (drect->layer < Num_layers) {
+ newrect = (DSEG)malloc(sizeof(struct dseg_));
+ *newrect = *drect;
+ newrect->next = gate->obs;
+ gate->obs = newrect;
+ }
}
for (drect = gate->obs; drect; drect = drect->next) {
@@ -1678,8 +1837,9 @@ DefReadComponents(FILE *f, char *sname, float oscale, int total)
case DEF_COMP_END:
if (!LefParseEndStatement(f, sname))
{
- LefError("Component END statement missing.\n");
+ LefError(DEF_ERROR, "Component END statement missing.\n");
keyword = -1;
+ err_fatal++;
}
/* Finish final call by placing the cell use */
@@ -1698,8 +1858,9 @@ DefReadComponents(FILE *f, char *sname, float oscale, int total)
Fprintf(stdout, " Processed %d subcell instances total.\n", processed);
}
else
- LefError("Warning: Number of subcells read (%d) does not match "
+ LefError(DEF_WARNING, "Warning: Number of subcells read (%d) does not match "
"the number declared (%d).\n", processed, total);
+ return err_fatal;
}
/*
@@ -1732,18 +1893,19 @@ enum def_sections {DEF_VERSION = 0, DEF_NAMESCASESENSITIVE,
DEF_CONSTRAINTS, DEF_GROUPS, DEF_EXTENSION,
DEF_END};
-float
-DefRead(char *inName)
+int
+DefRead(char *inName, float *retscale)
{
FILE *f;
char filename[256];
char *token;
int keyword, dscale, total;
int curlayer = -1, channels;
- int v, h, i;
+ int i;
+ int err_fatal = 0;
float oscale;
double start, step;
- double llx, lly, urx, ury;
+ double llx, lly, urx, ury, locpitch;
double dXlowerbound, dYlowerbound, dXupperbound, dYupperbound;
char corient = '.';
DSEG diearea;
@@ -1791,7 +1953,8 @@ DefRead(char *inName)
{
Fprintf(stderr, "Cannot open input file: ");
perror(filename);
- return (float)0.0;
+ *retscale = (float)0.0;
+ return 1;
}
/* Initialize */
@@ -1803,7 +1966,6 @@ DefRead(char *inName)
oscale = 1;
lefCurrentLine = 0;
- v = h = -1;
DefHashInit();
@@ -1814,47 +1976,12 @@ DefRead(char *inName)
keyword = Lookup(token, sections);
if (keyword < 0)
{
- LefError("Unknown keyword \"%s\" in DEF file; ignoring.\n", token);
+ LefError(DEF_WARNING, "Unknown keyword \"%s\" in DEF file; "
+ "ignoring.\n", token);
LefEndStatement(f);
continue;
}
-
- /* After the TRACKS have been read in, corient is 'x' or 'y'. */
- /* On the next keyword, finish filling in track information. */
-
- if (keyword != DEF_TRACKS && corient != '.')
- {
- /* Because the TRACKS statement only covers the pitch of */
- /* a single direction, we need to fill in with the pitch */
- /* of opposing layers. For now, we expect all horizontal */
- /* routes to be at the same pitch, and all vertical routes */
- /* to be at the same pitch. */
-
- if (h == -1) h = v;
- if (v == -1) v = h;
-
- /* This code copied from qconfig.c. Preferably, all */
- /* information available in the DEF file should be taken */
- /* from the DEF file. */
-
- for (i = 0; i < Num_layers; i++)
- {
- if (PitchX[i] != 0.0 && PitchX[i] != PitchX[v] && Verbose > 0)
- Fprintf(stderr, "Multiple vertical route layers at different"
- " pitches. Using pitch %g and routing on 1-of-N"
- " tracks for larger pitches.\n",
- PitchX[v]);
- PitchX[i] = PitchX[v];
- if (PitchY[i] != 0.0 && PitchY[i] != PitchY[h] && Verbose > 0)
- Fprintf(stderr, "Multiple horizontal route layers at different"
- " pitches. Using pitch %g and routing on 1-of-N"
- " tracks for larger pitches.\n",
- PitchY[h]);
- PitchY[i] = PitchY[h];
-
- corient = '.'; // So we don't run this code again.
- }
- }
+ if (keyword != DEF_TRACKS) corient = '.';
switch (keyword)
{
@@ -1886,8 +2013,8 @@ DefRead(char *inName)
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &dscale) != 1)
{
- LefError("Invalid syntax for UNITS statement.\n");
- LefError("Assuming default value of 100\n");
+ LefError(DEF_ERROR, "Invalid syntax for UNITS statement.\n");
+ LefError(DEF_WARNING, "Assuming default value of 100\n");
dscale = 100;
}
/* We don't care if the scale is 100, 200, 1000, or 2000. */
@@ -1901,28 +2028,33 @@ DefRead(char *inName)
case DEF_TRACKS:
token = LefNextToken(f, TRUE);
if (strlen(token) != 1) {
- LefError("Problem parsing track orientation (X or Y).\n");
+ LefError(DEF_ERROR, "Problem parsing track orientation (X or Y).\n");
}
corient = tolower(token[0]); // X or Y
token = LefNextToken(f, TRUE);
if (sscanf(token, "%lg", &start) != 1) {
- LefError("Problem parsing track start position.\n");
+ LefError(DEF_ERROR, "Problem parsing track start position.\n");
+ err_fatal++;
}
token = LefNextToken(f, TRUE);
if (strcmp(token, "DO")) {
- LefError("TRACKS missing DO loop.\n");
+ LefError(DEF_ERROR, "TRACKS missing DO loop.\n");
+ err_fatal++;
}
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &channels) != 1) {
- LefError("Problem parsing number of track channels.\n");
+ LefError(DEF_ERROR, "Problem parsing number of track channels.\n");
+ err_fatal++;
}
token = LefNextToken(f, TRUE);
if (strcmp(token, "STEP")) {
- LefError("TRACKS missing STEP size.\n");
+ LefError(DEF_ERROR, "TRACKS missing STEP size.\n");
+ err_fatal++;
}
token = LefNextToken(f, TRUE);
if (sscanf(token, "%lg", &step) != 1) {
- LefError("Problem parsing track step size.\n");
+ LefError(DEF_ERROR, "Problem parsing track step size.\n");
+ err_fatal++;
}
token = LefNextToken(f, TRUE);
if (!strcmp(token, "LAYER")) {
@@ -1930,10 +2062,9 @@ DefRead(char *inName)
}
if (corient == 'x') {
Vert[curlayer] = 1;
- PitchX[curlayer] = step / oscale;
- if ((v == -1) || (PitchX[curlayer] < PitchX[v])) v = curlayer;
- if ((curlayer < Num_layers - 1) && PitchX[curlayer + 1] == 0.0)
- PitchX[curlayer + 1] = PitchX[curlayer];
+ locpitch = step / oscale;
+ if ((PitchX == 0.0) || (locpitch < PitchX))
+ PitchX = locpitch;
llx = start;
urx = start + step * channels;
if ((llx / oscale) < Xlowerbound)
@@ -1943,10 +2074,9 @@ DefRead(char *inName)
}
else {
Vert[curlayer] = 0;
- PitchY[curlayer] = step / oscale;
- if ((h == -1) || (PitchY[curlayer] < PitchX[h])) h = curlayer;
- if ((curlayer < Num_layers - 1) && PitchY[curlayer + 1] == 0.0)
- PitchY[curlayer + 1] = PitchY[curlayer];
+ locpitch = step / oscale;
+ if ((PitchY == 0.0) || (locpitch < PitchY))
+ PitchY = locpitch;
lly = start;
ury = start + step * channels;
if ((lly / oscale) < Ylowerbound)
@@ -1991,7 +2121,7 @@ DefRead(char *inName)
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &total) != 1) total = 0;
LefEndStatement(f);
- DefReadComponents(f, sections[DEF_COMPONENTS], oscale, total);
+ err_fatal += DefReadComponents(f, sections[DEF_COMPONENTS], oscale, total);
break;
case DEF_BLOCKAGES:
token = LefNextToken(f, TRUE);
@@ -2018,16 +2148,16 @@ DefRead(char *inName)
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &total) != 1) total = 0;
LefEndStatement(f);
- DefReadNets(f, sections[DEF_SPECIALNETS], oscale, TRUE, total);
- numSpecial = total;
+ numSpecial = DefReadNets(f, sections[DEF_SPECIALNETS], oscale, TRUE,
+ total);
break;
case DEF_NETS:
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &total) != 1) total = 0;
LefEndStatement(f);
if (total > MAX_NETNUMS) {
- LefError("Number of nets in design (%d) exceeds maximum (%d)\n",
- total, MAX_NETNUMS);
+ LefError(DEF_WARNING, "Number of nets in design (%d) exceeds "
+ "maximum (%d)\n", total, MAX_NETNUMS);
}
DefReadNets(f, sections[DEF_NETS], oscale, FALSE, total);
break;
@@ -2049,7 +2179,7 @@ DefRead(char *inName)
case DEF_END:
if (!LefParseEndStatement(f, "DESIGN"))
{
- LefError("END statement out of context.\n");
+ LefError(DEF_ERROR, "END statement out of context.\n");
keyword = -1;
}
break;
@@ -2058,7 +2188,7 @@ DefRead(char *inName)
}
if (Verbose > 0)
Fprintf(stdout, "DEF read: Processed %d lines.\n", lefCurrentLine);
- LefError(NULL); /* print statement of errors, if any, and reset */
+ LefError(DEF_ERROR, NULL); /* print statement of errors, if any, and reset */
/* If there were no TRACKS statements, then use the DIEAREA */
if (Xlowerbound == Xupperbound) {
@@ -2073,5 +2203,6 @@ DefRead(char *inName)
/* Cleanup */
if (f != NULL) fclose(f);
- return oscale;
+ *retscale = oscale;
+ return err_fatal;
}
diff --git a/def.h b/def.h
index 9e42f14..f08f753 100644
--- a/def.h
+++ b/def.h
@@ -9,6 +9,9 @@
#define _DEFINT_H
extern int numSpecial;
-extern float DefRead(char *inName);
+extern int DefRead(char *inName, float *);
+
+extern GATE DefFindGate(char *name);
+extern NET DefFindNet(char *name);
#endif /* _DEFINT_H */
diff --git a/delays.c b/delays.c
index 967a296..6f75376 100644
--- a/delays.c
+++ b/delays.c
@@ -26,16 +26,6 @@
/* Find a node in the node list. */
/*--------------------------------------------------------------*/
-/* Define record holding information pointing to a gate and the */
-/* index into a specific node of that gate. */
-
-typedef struct gatenode_ *GATENODE;
-
-struct gatenode_ {
- GATE gate;
- int idx;
-};
-
GATE
FindGateNode(Tcl_HashTable *NodeTable, NODE node, int *ridx)
{
@@ -62,13 +52,11 @@ typedef struct _endpointinfo {
ROUTE orig; /* original pointer to routed segments */
int startx; /* values at segment start */
int starty;
- int startl;
- u_char starttype;
+ int startl; /* note: layer is exact, not base via layer */
NODE startnode;
int endx; /* values at segment end */
int endy;
int endl;
- u_char endtype;
NODE endnode;
double res; /* total resistance of segment */
double cap; /* total capacitance of segment */
@@ -143,39 +131,17 @@ check_downstream(SEG walkseg, endpointinfo *eptinfo, int eidx,
/* Check wire/via layer compatibility */
- if (eptinfo[i].starttype & ST_WIRE) {
- if (walkseg->segtype & ST_WIRE)
- startcompat = (walkseg->layer == eptinfo[i].startl);
- else
- startcompat = (walkseg->layer == eptinfo[i].startl) ||
- (walkseg->layer + 1 == eptinfo[i].startl);
- }
- else {
- if (walkseg->segtype & ST_WIRE)
- startcompat = (walkseg->layer == eptinfo[i].startl) ||
- (walkseg->layer == eptinfo[i].startl + 1);
- else
- startcompat = (walkseg->layer == eptinfo[i].startl) ||
- (walkseg->layer == eptinfo[i].startl + 1) ||
+ if (walkseg->segtype & ST_WIRE)
+ startcompat = (walkseg->layer == eptinfo[i].startl);
+ else
+ startcompat = (walkseg->layer == eptinfo[i].startl) ||
(walkseg->layer + 1 == eptinfo[i].startl);
- }
- if (eptinfo[i].endtype & ST_WIRE) {
- if (walkseg->segtype & ST_WIRE)
- endcompat = (walkseg->layer == eptinfo[i].endl);
- else
- endcompat = (walkseg->layer == eptinfo[i].endl) ||
- (walkseg->layer + 1 == eptinfo[i].endl);
- }
- else {
- if (walkseg->segtype & ST_WIRE)
- endcompat = (walkseg->layer == eptinfo[i].endl) ||
- (walkseg->layer == eptinfo[i].endl + 1);
- else
- endcompat = (walkseg->layer == eptinfo[i].endl) ||
- (walkseg->layer == eptinfo[i].endl + 1) ||
+ if (walkseg->segtype & ST_WIRE)
+ endcompat = (walkseg->layer == eptinfo[i].endl);
+ else
+ endcompat = (walkseg->layer == eptinfo[i].endl) ||
(walkseg->layer + 1 == eptinfo[i].endl);
- }
if ((walkseg->x2 == eptinfo[i].startx) &&
(walkseg->y2 == eptinfo[i].starty) && startcompat) {
@@ -258,7 +224,6 @@ walk_route(int eidx, int driverend, endpointinfo *eptinfo,
GATE g;
NODE node;
int i;
- u_char f;
ROUTE rt;
eptinfo[eidx].flags |= EPT_VISITED;
@@ -312,10 +277,6 @@ walk_route(int eidx, int driverend, endpointinfo *eptinfo,
i = eptinfo[eidx].startl;
eptinfo[eidx].startl = eptinfo[eidx].endl;
eptinfo[eidx].endl = i;
-
- f = eptinfo[eidx].starttype;
- eptinfo[eidx].starttype = eptinfo[eidx].endtype;
- eptinfo[eidx].endtype = f;
}
else
firstseg = rt->segments;
@@ -396,7 +357,10 @@ walk_route_output(endpointinfo *eptinfo, int eidx,
fprintf(delayFile, "%s/%s ", g->gatename, g->gatetype->node[i]);
if (d > 0) fprintf(delayFile, ", ");
}
-
+ else if (d == 0) {
+ /* This should not happen: No node, no route */
+ fprintf(delayFile, "ERROR ");
+ }
/* Output downstream nodes */
for (i = 0; i < d; i++) {
@@ -410,6 +374,24 @@ walk_route_output(endpointinfo *eptinfo, int eidx,
}
/*--------------------------------------------------------------*/
+/* Free data associated with each entry in the NodeTable hash. */
+/*--------------------------------------------------------------*/
+
+int FreeNodeTable(Tcl_HashTable *NodeTable)
+{
+ Tcl_HashEntry *entry;
+ Tcl_HashSearch hs;
+ GATENODE gn;
+
+ entry = Tcl_FirstHashEntry(NodeTable, &hs);
+ while (entry != NULL) {
+ gn = Tcl_GetHashValue(entry);
+ if (gn != NULL) free(gn);
+ entry = Tcl_NextHashEntry(&hs);
+ }
+}
+
+/*--------------------------------------------------------------*/
/* Write an output file of the calculated R, C for every route */
/* branch. Because the qrouter algorithm is agnostic about the */
/* direction of the signaling of routes, this has to be */
@@ -431,7 +413,7 @@ int write_delays(char *filename)
NODEINFO nodeptr;
SEG seg, newseg, lastseg, nxseg;
GATE g, drivergate;
- int i, j, n, new, driverend;
+ int i, j, n, new, driverend, testl;
int drivernodeidx, driveridx;
int nroute, numroutes;
endpointinfo *eptinfo;
@@ -479,11 +461,11 @@ int write_delays(char *filename)
LefGetRouteRCvalues(i, &areacap, &edgecap, &respersq);
width = LefGetRouteWidth(i);
- lefrcvalues[i].resx = (PitchX[i] / width) * respersq;
- lefrcvalues[i].resy = (PitchY[i] / width) * respersq;
+ lefrcvalues[i].resx = (PitchX / width) * respersq;
+ lefrcvalues[i].resy = (PitchY / width) * respersq;
- lefrcvalues[i].capx = (PitchX[i] * width) * areacap + (PitchX[i] * edgecap);
- lefrcvalues[i].capy = (PitchY[i] * width) * areacap + (PitchY[i] * edgecap);
+ lefrcvalues[i].capx = (PitchX * width) * areacap + (PitchX * edgecap);
+ lefrcvalues[i].capy = (PitchY * width) * areacap + (PitchY * edgecap);
if (i < (Num_layers - 1))
LefGetViaResistance(i, &(lefrcvalues[i].viares));
@@ -496,16 +478,14 @@ int write_delays(char *filename)
for (n = 0; n < Numnets; n++) {
net = Nlnets[n];
- if ((net->netnum == VDD_NET) || (net->netnum == GND_NET)) continue;
+ if ((net->netnum == VDD_NET) || (net->netnum == GND_NET) ||
+ (net->netnum == ANTENNA_NET)) continue;
/* Count number of net routes */
numroutes = 0;
for (rt = net->routes; rt; rt = rt->next) numroutes++;
if (numroutes == 0) continue; /* Ignore nets with no routes */
- /* Marked as one driver node. Not handling more than one driver yet. */
- fprintf(delayFile, "%s 1", net->netname);
-
/* Determine the driver node, as determined by the node with */
/* LEF direction 'OUTPUT'. */
/* (For now, if a net has multiple tristate drivers, just use */
@@ -530,18 +510,31 @@ int write_delays(char *filename)
eptinfo[nroute].startx = seg->x1;
eptinfo[nroute].starty = seg->y1;
eptinfo[nroute].startl = seg->layer;
- eptinfo[nroute].starttype = seg->segtype;
eptinfo[nroute].res = 0.0;
eptinfo[nroute].cap = 0.0;
+
+ /* If a via, check if direction is up or down */
+ if (seg->segtype & ST_VIA) {
+ if (seg->next && (seg->next->layer <= seg->layer))
+ eptinfo[nroute].startl++;
+ }
}
/* Segment end */
- for (seg = rt->segments; seg && seg->next; seg = seg->next);
+ testl = eptinfo[nroute].startl;
+ for (seg = rt->segments; seg && seg->next; seg = seg->next)
+ testl = seg->layer;
+
if (seg != NULL) {
eptinfo[nroute].endx = seg->x2;
eptinfo[nroute].endy = seg->y2;
eptinfo[nroute].endl = seg->layer;
- eptinfo[nroute].endtype = seg->segtype;
+
+ /* If a via, check if direction is up or down */
+ if (seg->segtype & ST_VIA) {
+ if (testl <= seg->layer)
+ eptinfo[nroute].endl++;
+ }
}
nroute++;
}
@@ -592,19 +585,23 @@ int write_delays(char *filename)
j = 0;
for (rt = droutes; rt; rt = rt->next) {
ROUTE testroute;
- int startx, starty, startl, starttype;
- int endx, endy, endl, endtype;
- int brkx, brky, brki, startcompat, endcompat;
+ int startx, starty, startl;
+ int endx, endy, endl;
+ int brkx, brky, brkl, brki, startcompat, endcompat;
int initial, final;
int x1, y1, x2, y2;
/* Check all segments (but not the endpoints) */
- for (seg = rt->segments; seg; seg = seg->next) {
+ lastseg = NULL;
+ for (seg = rt->segments; seg; lastseg = seg, seg = seg->next) {
initial = (seg == rt->segments) ? 1 : 0;
final = (seg->next == NULL) ? 1 : 0;
if (initial && (seg->segtype & ST_VIA)) continue;
- if (final && (seg->segtype & ST_VIA)) continue;
+ if (final && (seg->segtype & ST_VIA) &&
+ ((lastseg != rt->segments) ||
+ (!(rt->segments->segtype & ST_VIA))))
+ continue;
x1 = seg->x1;
x2 = seg->x2;
@@ -635,8 +632,10 @@ int write_delays(char *filename)
x2++;
else if (x1 < x2)
x2--;
- else
- continue; /* shouldn't happen */
+ /* x1 == x2 here implies that the route is made of */
+ /* exactly two vias. To continue would be to miss */
+ /* the center point between the vias. This unique */
+ /* condition is type == ST_VIA, final == TRUE. */
}
else {
if (y1 > y2)
@@ -652,7 +651,6 @@ int write_delays(char *filename)
brki = -1;
for (i = 0; i < numroutes; i++) {
if (eptinfo[i].route == rt) continue;
- if (eptinfo[i].endl == -2) continue;
testroute = eptinfo[i].orig;
if ((!(testroute->flags & RT_START_NODE)) &&
@@ -670,42 +668,33 @@ int write_delays(char *filename)
startx = eptinfo[i].startx;
starty = eptinfo[i].starty;
startl = eptinfo[i].startl;
- starttype = eptinfo[i].starttype;
endx = eptinfo[i].endx;
endy = eptinfo[i].endy;
endl = eptinfo[i].endl;
- endtype = eptinfo[i].endtype;
/* Check various combinations of wire and via layers */
+
if (seg->segtype & ST_WIRE) {
- if (starttype & ST_WIRE)
+ startcompat = (startl == seg->layer);
+ endcompat = (endl == seg->layer);
+ }
+ else if (final) {
+ /* Unique condition: route is two vias. Look */
+ /* only at the point between the vias. */
+ if (lastseg->layer < seg->layer) {
startcompat = (startl == seg->layer);
- else
- startcompat = (startl == seg->layer)
- || (startl + 1 == seg->layer);
-
- if (endtype & ST_WIRE)
endcompat = (endl == seg->layer);
- else
- endcompat = (endl == seg->layer)
- || (endl + 1 == seg->layer);
+ }
+ else {
+ startcompat = (startl == seg->layer + 1);
+ endcompat = (endl == seg->layer + 1);
+ }
}
else {
- if (starttype & ST_WIRE)
- startcompat = (startl == seg->layer)
+ startcompat = (startl == seg->layer)
|| (startl == seg->layer + 1);
- else
- startcompat = (startl == seg->layer)
- || (startl == seg->layer + 1)
- || (startl + 1 == seg->layer);
-
- if (endtype & ST_WIRE)
- endcompat = (endl == seg->layer)
+ endcompat = (endl == seg->layer)
|| (endl == seg->layer + 1);
- else
- endcompat = (endl == seg->layer)
- || (endl == seg->layer + 1)
- || (endl + 1 == seg->layer);
}
if (x1 == x2) {
@@ -715,6 +704,7 @@ int write_delays(char *filename)
starty <= y1) {
brkx = startx;
brky = starty;
+ brkl = startl;
y2 = brky;
brki = i;
}
@@ -724,6 +714,7 @@ int write_delays(char *filename)
starty <= y2) {
brkx = startx;
brky = starty;
+ brkl = startl;
y2 = brky;
brki = i;
}
@@ -735,6 +726,7 @@ int write_delays(char *filename)
endy <= y1) {
brkx = endx;
brky = endy;
+ brkl = endl;
y2 = brky;
brki = i;
}
@@ -744,6 +736,7 @@ int write_delays(char *filename)
endy <= y2) {
brkx = endx;
brky = endy;
+ brkl = endl;
y2 = brky;
brki = i;
}
@@ -757,6 +750,7 @@ int write_delays(char *filename)
startx <= x1) {
brkx = startx;
brky = starty;
+ brkl = startl;
x2 = brkx;
brki = i;
}
@@ -766,6 +760,7 @@ int write_delays(char *filename)
startx <= x2) {
brkx = startx;
brky = starty;
+ brkl = startl;
x2 = brkx;
brki = i;
}
@@ -777,6 +772,7 @@ int write_delays(char *filename)
endx <= x1) {
brkx = endx;
brky = endy;
+ brkl = endl;
x2 = brkx;
brki = i;
}
@@ -786,6 +782,7 @@ int write_delays(char *filename)
endx <= x2) {
brkx = endx;
brky = endy;
+ brkl = endl;
x2 = brkx;
brki = i;
}
@@ -793,27 +790,64 @@ int write_delays(char *filename)
}
}
}
- if ((brki >= 0) && (eptinfo[brki].endl != -2)) {
+ if (brki >= 0) {
/* Disable this endpoint so it is not checked again */
eptinfo[brki].endl = -2;
/* Break route at this point */
- /* Make a copy of the segment where the break occurs */
+ /* If route type is a wire, then make a copy of the */
+ /* segment where the break occurs. If a via, then */
+ /* determine which side of the break the via goes */
+ /* to. */
+
newroute = (ROUTE)malloc(sizeof(struct route_));
- newseg = (SEG)malloc(sizeof(struct seg_));
- newseg->segtype = seg->segtype;
- newseg->x1 = brkx;
- newseg->y1 = brky;
- newseg->x2 = seg->x2;
- newseg->y2 = seg->y2;
- newseg->layer = seg->layer;
-
- newseg->next = seg->next;
- seg->next = NULL;
- seg->x2 = brkx;
- seg->y2 = brky;
- newroute->segments = newseg;
+ if (seg->segtype & ST_WIRE) {
+ newseg = (SEG)malloc(sizeof(struct seg_));
+ newseg->segtype = seg->segtype;
+ newseg->x1 = brkx;
+ newseg->y1 = brky;
+ newseg->x2 = seg->x2;
+ newseg->y2 = seg->y2;
+ newseg->layer = seg->layer;
+
+ newseg->next = seg->next;
+ seg->next = NULL;
+ seg->x2 = brkx;
+ seg->y2 = brky;
+
+ newroute->segments = newseg;
+ }
+ else if (lastseg == NULL) {
+ /* Via is the route before the break */
+ newroute->segments = seg->next;
+ seg->next = NULL;
+ }
+ else if (lastseg->layer <= seg->layer) {
+ if (brkl > seg->layer) {
+ /* Via goes at the end of the route before the break */
+ newroute->segments = seg->next;
+ seg->next = NULL;
+ }
+ else {
+ /* Via goes at the start of the route after the break */
+ newroute->segments = seg;
+ lastseg->next = NULL;
+ }
+ }
+ else { /* (lastseg->layer > seg->layer) */
+ if (brkl > seg->layer) {
+ /* Via goes at the start of the route after the break */
+ newroute->segments = seg;
+ lastseg->next = NULL;
+ }
+ else {
+ /* Via goes at the end of the route before the break */
+ newroute->segments = seg->next;
+ seg->next = NULL;
+ }
+ }
+
newroute->netnum = rt->netnum;
newroute->flags = (u_char)0;
newroute->next = rt->next;
@@ -862,7 +896,9 @@ int write_delays(char *filename)
eptinfo[nroute].startx = seg->x1;
eptinfo[nroute].starty = seg->y1;
eptinfo[nroute].startl = seg->layer;
- eptinfo[nroute].starttype = seg->segtype;
+ /* Check for via in down direction rather than the default up */
+ if ((seg->segtype & ST_VIA) && seg->next && seg->next->layer <= seg->layer)
+ eptinfo[nroute].startl++;
nodeptr = (seg->layer < Pinlayers) ?
NODEIPTR(seg->x1, seg->y1, seg->layer) : NULL;
eptinfo[nroute].startnode = nodeptr ? nodeptr->nodesav : NULL;
@@ -874,7 +910,7 @@ int write_delays(char *filename)
eptinfo[nroute].cap = 0.0;
/* Look up node */
- if (nodeptr) {
+ if (nodeptr && nodeptr->nodesav) {
g = FindGateNode(&NodeTable, nodeptr->nodesav, &i);
if (g && (g->gatetype->direction[i] == PORT_CLASS_OUTPUT)) {
drivernodeidx = i;
@@ -908,13 +944,20 @@ int write_delays(char *filename)
eptinfo[nroute].endx = seg->x2;
eptinfo[nroute].endy = seg->y2;
eptinfo[nroute].endl = seg->layer;
- eptinfo[nroute].endtype = seg->segtype;
- nodeptr = (seg->layer < Pinlayers) ?
- NODEIPTR(seg->x2, seg->y2, seg->layer) : NULL;
+ /* Check for via in down direction rather than default up */
+ if (seg->segtype & ST_VIA) {
+ if (lastseg && lastseg->layer <= seg->layer)
+ eptinfo[nroute].endl++;
+ else if (!lastseg && eptinfo[nroute].endl <= seg->layer)
+ eptinfo[nroute].endl++;
+ }
+
+ nodeptr = (eptinfo[nroute].endl < Pinlayers) ?
+ NODEIPTR(seg->x2, seg->y2, eptinfo[nroute].endl) : NULL;
eptinfo[nroute].endnode = nodeptr ? nodeptr->nodesav : NULL;
/* Look up node */
- if (nodeptr) {
+ if (nodeptr && nodeptr->nodesav) {
g = FindGateNode(&NodeTable, nodeptr->nodesav, &i);
if (g && (g->gatetype->direction[i] == PORT_CLASS_OUTPUT)) {
drivernodeidx = i;
@@ -959,11 +1002,11 @@ int write_delays(char *filename)
drivergate->gatetype->node[drivernodeidx]);
*/
if (!strcmp(drivergate->gatetype->node[drivernodeidx], "pin"))
- fprintf(delayFile, " PIN/%s %d ",
- drivergate->gatename, net->numnodes - 1);
+ fprintf(delayFile, "%s 1 PIN/%s %d ",
+ net->netname, drivergate->gatename, net->numnodes - 1);
else
- fprintf(delayFile, " %s/%s %d ",
- drivergate->gatename,
+ fprintf(delayFile, "%s 1 %s/%s %d ",
+ net->netname, drivergate->gatename,
drivergate->gatetype->node[drivernodeidx],
net->numnodes - 1);
@@ -1012,6 +1055,7 @@ int write_delays(char *filename)
free(lefrcvalues);
+ FreeNodeTable(&NodeTable);
Tcl_DeleteHashTable(&NodeTable);
return 0;
diff --git a/graphics.c b/graphics.c
index 2778d61..6beff4e 100644
--- a/graphics.c
+++ b/graphics.c
@@ -102,9 +102,9 @@ void highlight_source() {
// Draw source pins as magenta squares
XSetForeground(dpy, gc, magentapix);
for (i = 0; i < Num_layers; i++) {
- for (x = 0; x < NumChannelsX[i]; x++) {
+ for (x = 0; x < NumChannelsX; x++) {
xspc = (x + 1) * spacing - hspc;
- for (y = 0; y < NumChannelsY[i]; y++) {
+ for (y = 0; y < NumChannelsY; y++) {
Pr = &OBS2VAL(x, y, i);
if (Pr->flags & PR_SOURCE) {
yspc = height - (y + 1) * spacing - hspc;
@@ -140,9 +140,9 @@ void highlight_dest() {
// Draw destination pins as purple squares
XSetForeground(dpy, gc, purplepix);
for (i = 0; i < Num_layers; i++) {
- for (x = 0; x < NumChannelsX[i]; x++) {
+ for (x = 0; x < NumChannelsX; x++) {
xspc = (x + 1) * spacing - hspc;
- for (y = 0; y < NumChannelsY[i]; y++) {
+ for (y = 0; y < NumChannelsY; y++) {
Pr = &OBS2VAL(x, y, i);
if (Pr->flags & PR_TARGET) {
yspc = height - (y + 1) * spacing - hspc;
@@ -199,9 +199,9 @@ void highlight_mask(void) {
hspc = spacing >> 1;
// Draw destination pins as tan squares
- for (x = 0; x < NumChannelsX[0]; x++) {
+ for (x = 0; x < NumChannelsX; x++) {
xspc = (x + 1) * spacing - hspc;
- for (y = 0; y < NumChannelsY[0]; y++) {
+ for (y = 0; y < NumChannelsY; y++) {
XSetForeground(dpy, gc, brownvector[RMASK(x, y)]);
yspc = height - (y + 1) * spacing - hspc;
XFillRectangle(dpy, win, gc, xspc, yspc, spacing, spacing);
@@ -227,9 +227,9 @@ map_obstruction()
// Draw obstructions as light gray squares
XSetForeground(dpy, gc, ltgraypix);
for (i = 0; i < Num_layers; i++) {
- for (x = 0; x < NumChannelsX[i]; x++) {
+ for (x = 0; x < NumChannelsX; x++) {
xspc = (x + 1) * spacing - hspc;
- for (y = 0; y < NumChannelsY[i]; y++) {
+ for (y = 0; y < NumChannelsY; y++) {
if (OBSVAL(x, y, i) & NO_NET) {
yspc = height - (y + 1) * spacing - hspc;
XFillRectangle(dpy, buffer, gc, xspc, yspc,
@@ -242,9 +242,9 @@ map_obstruction()
// Draw pins as gray squares
XSetForeground(dpy, gc, graypix);
for (i = 0; i < Pinlayers; i++) {
- for (x = 0; x < NumChannelsX[i]; x++) {
+ for (x = 0; x < NumChannelsX; x++) {
xspc = (x + 1) * spacing - hspc;
- for (y = 0; y < NumChannelsY[i]; y++) {
+ for (y = 0; y < NumChannelsY; y++) {
if (NODEIPTR(x, y, i) != NULL) {
yspc = height - (y + 1) * spacing - hspc;
XFillRectangle(dpy, buffer, gc, xspc, yspc,
@@ -271,13 +271,13 @@ map_congestion()
hspc = spacing >> 1;
- Congestion = (u_char *)calloc(NumChannelsX[0] * NumChannelsY[0],
+ Congestion = (u_char *)calloc(NumChannelsX * NumChannelsY,
sizeof(u_char));
// Analyze Obs[] array for congestion
for (i = 0; i < Num_layers; i++) {
- for (x = 0; x < NumChannelsX[i]; x++) {
- for (y = 0; y < NumChannelsY[i]; y++) {
+ for (x = 0; x < NumChannelsX; x++) {
+ for (y = 0; y < NumChannelsY; y++) {
value = (u_char)0;
n = OBSVAL(x, y, i);
if (n & ROUTED_NET) value++;
@@ -290,8 +290,8 @@ map_congestion()
}
maxval = 0;
- for (x = 0; x < NumChannelsX[0]; x++) {
- for (y = 0; y < NumChannelsY[0]; y++) {
+ for (x = 0; x < NumChannelsX; x++) {
+ for (y = 0; y < NumChannelsY; y++) {
value = CONGEST(x, y);
if (value > maxval) maxval = value;
}
@@ -299,9 +299,9 @@ map_congestion()
norm = (LONGSPAN - 1) / maxval;
// Draw destination pins as blue squares
- for (x = 0; x < NumChannelsX[0]; x++) {
+ for (x = 0; x < NumChannelsX; x++) {
xspc = (x + 1) * spacing - hspc;
- for (y = 0; y < NumChannelsY[0]; y++) {
+ for (y = 0; y < NumChannelsY; y++) {
XSetForeground(dpy, gc, bluevector[norm * CONGEST(x, y)]);
yspc = height - (y + 1) * spacing - hspc;
XFillRectangle(dpy, buffer, gc, xspc, yspc, spacing, spacing);
@@ -328,7 +328,7 @@ map_estimate()
hspc = spacing >> 1;
- Congestion = (float *)calloc(NumChannelsX[0] * NumChannelsY[0],
+ Congestion = (float *)calloc(NumChannelsX * NumChannelsY,
sizeof(float));
// Use net bounding boxes to estimate congestion
@@ -352,8 +352,8 @@ map_estimate()
}
maxval = 0.0;
- for (x = 0; x < NumChannelsX[0]; x++) {
- for (y = 0; y < NumChannelsY[0]; y++) {
+ for (x = 0; x < NumChannelsX; x++) {
+ for (y = 0; y < NumChannelsY; y++) {
density = CONGEST(x, y);
if (density > maxval) maxval = density;
}
@@ -361,9 +361,9 @@ map_estimate()
norm = (float)(LONGSPAN - 1) / maxval;
// Draw destination pins as blue squares
- for (x = 0; x < NumChannelsX[0]; x++) {
+ for (x = 0; x < NumChannelsX; x++) {
xspc = (x + 1) * spacing - hspc;
- for (y = 0; y < NumChannelsY[0]; y++) {
+ for (y = 0; y < NumChannelsY; y++) {
value = (int)(norm * CONGEST(x, y));
XSetForeground(dpy, gc, bluevector[value]);
yspc = height - (y + 1) * spacing - hspc;
@@ -782,8 +782,8 @@ int redraw(ClientData clientData, Tcl_Interp *interp, int objc,
}
/*------------------------------------------------------*/
-/* Call to recalculate the spacing if NumChannelsX[0] */
-/* or NumChannelsY[0] changes. */
+/* Call to recalculate the spacing if NumChannelsX */
+/* or NumChannelsY changes. */
/* */
/* Return 1 if the spacing changed, 0 otherwise. */
/*------------------------------------------------------*/
@@ -793,8 +793,8 @@ int recalc_spacing()
int xspc, yspc;
int oldspacing = spacing;
- xspc = width / (NumChannelsX[0] + 1);
- yspc = height / (NumChannelsY[0] + 1);
+ xspc = width / (NumChannelsX + 1);
+ yspc = height / (NumChannelsY + 1);
spacing = (xspc < yspc) ? xspc : yspc;
if (spacing == 0) spacing = 1;
diff --git a/lef.c b/lef.c
index 959fcb7..9c654ac 100644
--- a/lef.c
+++ b/lef.c
@@ -274,6 +274,8 @@ LefNextToken(FILE *f, u_char ignore_eol)
* Print an error message (via fprintf) giving the line
* number of the input file on which the error occurred.
*
+ * "type" should be either LEF_ERROR or LEF_WARNING (or DEF_*).
+ *
* Results:
* None.
*
@@ -284,36 +286,49 @@ LefNextToken(FILE *f, u_char ignore_eol)
*/
void
-LefError(char *fmt, ...)
+LefError(int type, char *fmt, ...)
{
- static int errors = 0;
+ static int fatal = 0;
+ static int nonfatal = 0;
+ char lefordef = 'L';
+ int errors;
va_list args;
if (Verbose == 0) return;
+ if ((type == DEF_WARNING) || (type == DEF_ERROR)) lefordef = 'D';
+
+ errors = fatal + nonfatal;
if (fmt == NULL) /* Special case: report any errors and reset */
{
- if (errors)
+ if (errors > 0)
{
- Fprintf(stdout, "LEF Read: encountered %d error%s total.\n",
- errors, (errors == 1) ? "" : "s");
- errors = 0;
+ Fprintf(stdout, "%cEF Read: encountered %d error%s and %d warning%s total.\n",
+ lefordef,
+ fatal, (fatal == 1) ? "" : "s",
+ nonfatal, (nonfatal == 1) ? "" : "s");
+ fatal = 0;
+ nonfatal = 0;
}
return;
}
if (errors < LEF_MAX_ERRORS)
{
- Fprintf(stderr, "LEF Read, Line %d: ", lefCurrentLine);
+ Fprintf(stderr, "%cEF Read, Line %d: ", lefordef, lefCurrentLine);
va_start(args, fmt);
Vprintf(stderr, fmt, args);
va_end(args);
Flush(stderr);
}
else if (errors == LEF_MAX_ERRORS)
- Fprintf(stderr, "LEF Read: Further errors will not be reported.\n");
+ Fprintf(stderr, "%cEF Read: Further errors/warnings will not be reported.\n",
+ lefordef);
- errors++;
+ if ((type == LEF_ERROR) || (type == DEF_ERROR))
+ fatal++;
+ else if ((type == LEF_WARNING) || (type == DEF_WARNING))
+ nonfatal++;
}
/*
@@ -349,7 +364,7 @@ LefParseEndStatement(FILE *f, char *match)
token = LefNextToken(f, (match == NULL) ? FALSE : TRUE);
if (token == NULL)
{
- LefError("Bad file read while looking for END statement\n");
+ LefError(LEF_ERROR, "Bad file read while looking for END statement\n");
return FALSE;
}
@@ -413,7 +428,7 @@ LefSkipSection(FILE *f, char *section)
}
}
- LefError("Section %s has no END record!\n", section);
+ LefError(LEF_ERROR, "Section %s has no END record!\n", section);
return;
}
@@ -611,7 +626,9 @@ LefFindLayerNum(char *token)
/*
*---------------------------------------------------------------
- * Find the maximum routing layer number defined by the LEF file
+ * Find the maximum layer number defined by the LEF file
+ * This includes layer numbers assigned to both routes and
+ * via cut layers.
*---------------------------------------------------------------
*/
@@ -629,6 +646,26 @@ LefGetMaxLayer(void)
}
/*
+ *---------------------------------------------------------------
+ * Find the maximum routing layer number defined by the LEF file
+ *---------------------------------------------------------------
+ */
+
+int
+LefGetMaxRouteLayer(void)
+{
+ int maxlayer = -1;
+ LefList lefl;
+
+ for (lefl = LefInfo; lefl; lefl = lefl->next) {
+ if (lefl->lefClass != CLASS_ROUTE) continue;
+ if (lefl->type > maxlayer)
+ maxlayer = lefl->type;
+ }
+ return (maxlayer + 1);
+}
+
+/*
*------------------------------------------------------------
* Return the route keepout area, defined as the route space
* plus 1/2 the route width. This is the distance outward
@@ -657,7 +694,7 @@ LefGetRouteKeepout(int layer)
+ lefl->info.route.spacing->spacing;
}
}
- return MIN(PitchX[layer], PitchY[layer]) - PathWidth[layer] / 2.0;
+ return MIN(PitchX, PitchY) - PathWidth[layer] / 2.0;
}
/*
@@ -680,7 +717,7 @@ LefGetRouteWidth(int layer)
return lefl->info.route.width;
}
}
- return MIN(PitchX[layer], PitchY[layer]) / 2.0;
+ return MIN(PitchX, PitchY) / 2.0;
}
/*
@@ -708,7 +745,7 @@ LefGetRouteOffset(int layer)
return lefl->info.route.offsetx;
}
}
- return MIN(PitchX[layer], PitchY[layer]) / 2.0;
+ return MIN(PitchX, PitchY) / 2.0;
}
double
@@ -723,7 +760,7 @@ LefGetRouteOffsetX(int layer)
return lefl->info.route.offsetx;
}
}
- return PitchX[layer] / 2.0;
+ return MIN(PitchX, PitchY) / 2.0;
}
double
@@ -738,7 +775,28 @@ LefGetRouteOffsetY(int layer)
return lefl->info.route.offsety;
}
}
- return PitchY[layer] / 2.0;
+ return PitchY / 2.0;
+}
+
+/*
+ *------------------------------------------------------------
+ * Find and return the minimum metal area requirement for a
+ * route layer.
+ *------------------------------------------------------------
+ */
+
+double
+LefGetRouteMinArea(int layer)
+{
+ LefList lefl;
+
+ lefl = LefFindLayerByNum(layer);
+ if (lefl) {
+ if (lefl->lefClass == CLASS_ROUTE) {
+ return lefl->info.route.minarea;
+ }
+ }
+ return 0.0; /* Assume no minimum area requirement */
}
/*
@@ -769,12 +827,19 @@ LefGetViaWidth(int base, int layer, int dir)
/*
*------------------------------------------------------------
- * The base routing used by LefGetViaWidth(), with an
+ * The base routine used by LefGetViaWidth(), with an
* additional argument that specifies which via orientation
* to use, if an alternative orientation is available. This
- * is necessary for doing checkerboard via patterning and
- * for certain standard cells with ports that do not always
- * fit one orientation of via.
+ * is necessary for doing checkerboard via patterning and for
+ * certain standard cells with ports that do not always fit
+ * one orientation of via.
+ *
+ * "orient" is defined as follows:
+ * 0 = XX = both layers horizontal
+ * 1 = XY = bottom layer horizontal, top layer vertical
+ * 2 = YX = bottom layer vertical, top layer horizontal
+ * 3 = YY = both layers vertical.
+ *
*------------------------------------------------------------
*/
@@ -786,18 +851,79 @@ LefGetXYViaWidth(int base, int layer, int dir, int orient)
double width;
char **viatable;
- viatable = (orient == 1) ? ViaY : ViaX;
-
+ switch (orient) {
+ case 0:
+ viatable = ViaXX;
+ break;
+ case 1:
+ viatable = ViaXY;
+ break;
+ case 2:
+ viatable = ViaYX;
+ break;
+ case 3:
+ viatable = ViaYY;
+ break;
+ }
lefl = LefFindLayer(*(viatable + base));
+
+ /* The routine LefAssignLayerVias() should assign all Via** types. */
+ /* Below are fallback assignments. */
+
if (!lefl) {
- viatable = (orient == 1) ? ViaX : ViaY;
+ switch (orient) {
+ case 0:
+ viatable = ViaXY;
+ break;
+ case 1:
+ viatable = ViaYX;
+ break;
+ case 2:
+ viatable = ViaYY;
+ break;
+ case 3:
+ viatable = ViaYX;
+ break;
+ }
lefl = LefFindLayer(*(viatable + base));
- viatable = (orient == 1) ? ViaY : ViaX;
}
+
if (!lefl) {
- if (base == (Num_layers - 1))
- lefl = LefFindLayer(*(viatable + base - 1));
+ switch (orient) {
+ case 0:
+ viatable = ViaYX;
+ break;
+ case 1:
+ viatable = ViaYY;
+ break;
+ case 2:
+ viatable = ViaXX;
+ break;
+ case 3:
+ viatable = ViaXY;
+ break;
+ }
+ lefl = LefFindLayer(*(viatable + base));
}
+
+ if (!lefl) {
+ switch (orient) {
+ case 0:
+ viatable = ViaYY;
+ break;
+ case 1:
+ viatable = ViaYX;
+ break;
+ case 2:
+ viatable = ViaXY;
+ break;
+ case 3:
+ viatable = ViaXX;
+ break;
+ }
+ lefl = LefFindLayer(*(viatable + base));
+ }
+
if (lefl) {
if (lefl->lefClass == CLASS_VIA) {
if (lefl->info.via.area.layer == layer) {
@@ -818,7 +944,7 @@ LefGetXYViaWidth(int base, int layer, int dir, int orient)
}
}
}
- return MIN(PitchX[layer], PitchY[layer]) / 2.0; // Best guess
+ return MIN(PitchX, PitchY) / 2.0; // Best guess
}
/*
@@ -841,7 +967,7 @@ LefGetRouteSpacing(int layer)
return 0.0;
}
}
- return MIN(PitchX[layer], PitchY[layer]) / 2.0;
+ return MIN(PitchX, PitchY) / 2.0;
}
/*
@@ -869,7 +995,7 @@ LefGetRouteWideSpacing(int layer, double width)
return spacing;
}
}
- return MIN(PitchX[layer], PitchY[layer]) / 2.0;
+ return MIN(PitchX, PitchY) / 2.0;
}
/*
@@ -894,7 +1020,7 @@ LefGetRoutePitch(int layer)
return lefl->info.route.pitchx;
}
}
- return MIN(PitchX[layer], PitchY[layer]);
+ return MIN(PitchX, PitchY);
}
/*
@@ -914,7 +1040,7 @@ LefGetRoutePitchX(int layer)
return lefl->info.route.pitchx;
}
}
- return PitchX[layer];
+ return PitchX;
}
/*
@@ -934,7 +1060,45 @@ LefGetRoutePitchY(int layer)
return lefl->info.route.pitchy;
}
}
- return PitchY[layer];
+ return PitchY;
+}
+
+/*
+ *------------------------------------------------------------
+ * Set the route pitch in X for a given layer
+ *------------------------------------------------------------
+ */
+
+void
+LefSetRoutePitchX(int layer, double value)
+{
+ LefList lefl;
+
+ lefl = LefFindLayerByNum(layer);
+ if (lefl) {
+ if (lefl->lefClass == CLASS_ROUTE) {
+ lefl->info.route.pitchx = value;
+ }
+ }
+}
+
+/*
+ *------------------------------------------------------------
+ * Set the route pitch in Y for a given layer
+ *------------------------------------------------------------
+ */
+
+void
+LefSetRoutePitchY(int layer, double value)
+{
+ LefList lefl;
+
+ lefl = LefFindLayerByNum(layer);
+ if (lefl) {
+ if (lefl->lefClass == CLASS_ROUTE) {
+ lefl->info.route.pitchy = value;
+ }
+ }
}
/*
@@ -1007,6 +1171,67 @@ LefGetRouteRCvalues(int layer, double *areacap, double *edgecap,
/*
*------------------------------------------------------------
+ * Get the antenna violation area ratio for the given layer.
+ *------------------------------------------------------------
+ */
+
+double
+LefGetRouteAreaRatio(int layer)
+{
+ LefList lefl;
+
+ lefl = LefFindLayerByNum(layer);
+ if (lefl) {
+ if (lefl->lefClass == CLASS_ROUTE) {
+ return lefl->info.route.antenna;
+ }
+ }
+ return 0.0;
+}
+
+/*
+ *------------------------------------------------------------
+ * Get the antenna violation area calculation method for the
+ * given layer.
+ *------------------------------------------------------------
+ */
+
+u_char
+LefGetRouteAntennaMethod(int layer)
+{
+ LefList lefl;
+
+ lefl = LefFindLayerByNum(layer);
+ if (lefl) {
+ if (lefl->lefClass == CLASS_ROUTE) {
+ return lefl->info.route.method;
+ }
+ }
+ return CALC_NONE;
+}
+
+/*
+ *------------------------------------------------------------
+ * Get the route metal layer thickness (if any is defined)
+ *------------------------------------------------------------
+ */
+
+double
+LefGetRouteThickness(int layer)
+{
+ LefList lefl;
+
+ lefl = LefFindLayerByNum(layer);
+ if (lefl) {
+ if (lefl->lefClass == CLASS_ROUTE) {
+ return lefl->info.route.thick;
+ }
+ }
+ return 0.0;
+}
+
+/*
+ *------------------------------------------------------------
* Get resistance per via for a via layer.
* Return 0 on success, -1 if the layer is not found.
* Fill in the pointer value with the resistance.
@@ -1019,11 +1244,19 @@ LefGetViaResistance(int layer, double *respervia)
DSEG lrect;
LefList lefl;
double width;
- char **viatable = ViaX;
+ char **viatable = ViaXX;
lefl = LefFindLayer(*(viatable + layer));
if (!lefl) {
- viatable = ViaY;
+ viatable = ViaXY;
+ lefl = LefFindLayer(*(viatable + layer));
+ }
+ if (!lefl) {
+ viatable = ViaYX;
+ lefl = LefFindLayer(*(viatable + layer));
+ }
+ if (!lefl) {
+ viatable = ViaYY;
lefl = LefFindLayer(*(viatable + layer));
}
if (lefl) {
@@ -1068,7 +1301,7 @@ LefReadLayers(f, obstruct, lreturn)
token = LefNextToken(f, TRUE);
if (*token == ';')
{
- LefError("Bad Layer statement\n");
+ LefError(LEF_ERROR, "Bad Layer statement\n");
return -1;
}
else
@@ -1082,7 +1315,7 @@ LefReadLayers(f, obstruct, lreturn)
curlayer = lefl->obsType;
if ((curlayer < 0) && (lefl->lefClass != CLASS_IGNORE))
curlayer = lefl->type;
- else if (lefl->lefClass == CLASS_VIA)
+ else if (lefl->lefClass == CLASS_VIA || lefl->lefClass == CLASS_CUT)
if (lreturn) *lreturn = lefl->info.via.obsType;
}
else
@@ -1096,8 +1329,28 @@ LefReadLayers(f, obstruct, lreturn)
/* CLASS_VIA in lefl record is a cut, and the layer */
/* geometry is ignored for the purpose of routing. */
- if ((!lefl) || (lefl->lefClass != CLASS_VIA))
- LefError("Don't know how to parse layer \"%s\"\n", token);
+ if (lefl && (lefl->lefClass == CLASS_CUT)) {
+ int cuttype;
+
+ /* By the time a cut layer is being requested, */
+ /* presumably from a VIA definition, the route */
+ /* layers should all be defined, so start */
+ /* assigning layers to cuts. */
+
+ /* If a cut layer is found with an unassigned number, */
+ /* then assign it here. */
+ cuttype = LefGetMaxLayer();
+ if (cuttype < MAX_TYPES) {
+ lefl->type = cuttype;
+ curlayer = cuttype;
+ strcpy(CIFLayer[cuttype], lefl->lefName);
+ }
+ else
+ LefError(LEF_WARNING, "Too many cut types; type \"%s\" ignored.\n",
+ token);
+ }
+ else if ((!lefl) || (lefl->lefClass != CLASS_VIA))
+ LefError(LEF_ERROR, "Don't know how to parse layer \"%s\"\n", token);
}
}
return curlayer;
@@ -1188,7 +1441,7 @@ LefReadRect(FILE *f, int curlayer, float oscale)
}
if (curlayer < 0) {
/* Issue warning but keep geometry with negative layer number */
- LefError("No layer defined for RECT.\n");
+ LefError(LEF_WARNING, "No layer defined for RECT.\n");
}
/* Scale coordinates (microns to centimicrons) */
@@ -1201,7 +1454,59 @@ LefReadRect(FILE *f, int curlayer, float oscale)
return (&paintrect);
parse_error:
- LefError("Bad port geometry: RECT requires 4 values.\n");
+ LefError(LEF_ERROR, "Bad port geometry: RECT requires 4 values.\n");
+ return (DSEG)NULL;
+}
+
+/*
+ *------------------------------------------------------------
+ * LefReadEnclosure --
+ *
+ * Read a LEF "ENCLOSURE" record from the file, and
+ * return a Rect in micron coordinates, representing
+ * the bounding box of the stated enclosure dimensions
+ * in both directions, centered on the origin.
+ *
+ * Results:
+ * Returns a pointer to a Rect containing the micron
+ * coordinates, or NULL if an error occurred.
+ *
+ * Side Effects:
+ * Reads input from file f
+ *
+ *------------------------------------------------------------
+ */
+
+DSEG
+LefReadEnclosure(FILE *f, int curlayer, float oscale)
+{
+ char *token;
+ float x, y, scale;
+ static struct dseg_ paintrect;
+
+ token = LefNextToken(f, TRUE);
+ if (!token || sscanf(token, "%f", &x) != 1) goto enc_parse_error;
+ token = LefNextToken(f, TRUE);
+ if (!token || sscanf(token, "%f", &y) != 1) goto enc_parse_error;
+
+ if (curlayer < 0) {
+ /* Issue warning but keep geometry with negative layer number */
+ LefError(LEF_ERROR, "No layer defined for RECT.\n");
+ }
+
+ /* Scale coordinates (microns to centimicrons) (doubled) */
+
+ scale = oscale / 2.0;
+
+ paintrect.x1 = -x / scale;
+ paintrect.y1 = -y / scale;
+ paintrect.x2 = x / scale;
+ paintrect.y2 = y / scale;
+ paintrect.layer = curlayer;
+ return (&paintrect);
+
+enc_parse_error:
+ LefError(LEF_ERROR, "Bad enclosure geometry: ENCLOSURE requires 2 values.\n");
return (DSEG)NULL;
}
@@ -1406,7 +1711,7 @@ LefPolygonToRects(DSEG *rectListPtr, DPOINT pointlist)
if (npts < 4)
{
- LefError("Polygon with fewer than 4 points.\n");
+ LefError(LEF_ERROR, "Polygon with fewer than 4 points.\n");
goto done;
}
@@ -1418,7 +1723,7 @@ LefPolygonToRects(DSEG *rectListPtr, DPOINT pointlist)
if (!lefOrient(edges, npts, dir))
{
- LefError("I can't handle non-manhattan polygons!\n");
+ LefError(LEF_ERROR, "I can't handle non-manhattan polygons!\n");
goto done;
}
@@ -1494,13 +1799,15 @@ LefReadPolygon(FILE *f, int curlayer, float oscale)
char *token;
double px, py;
+ if (curlayer >= Num_layers) return (DPOINT)NULL;
+
while (1)
{
token = LefNextToken(f, TRUE);
if (token == NULL || *token == ';') break;
if (sscanf(token, "%lg", &px) != 1)
{
- LefError("Bad X value in polygon.\n");
+ LefError(LEF_ERROR, "Bad X value in polygon.\n");
LefEndStatement(f);
break;
}
@@ -1508,12 +1815,12 @@ LefReadPolygon(FILE *f, int curlayer, float oscale)
token = LefNextToken(f, TRUE);
if (token == NULL || *token == ';')
{
- LefError("Missing Y value in polygon point!\n");
+ LefError(LEF_ERROR, "Missing Y value in polygon point!\n");
break;
}
if (sscanf(token, "%lg", &py) != 1)
{
- LefError("Bad Y value in polygon.\n");
+ LefError(LEF_ERROR, "Bad Y value in polygon.\n");
LefEndStatement(f);
break;
}
@@ -1579,7 +1886,8 @@ LefReadGeometry(GATE lefMacro, FILE *f, float oscale)
keyword = Lookup(token, geometry_keys);
if (keyword < 0)
{
- LefError("Unknown keyword \"%s\" in LEF file; ignoring.\n", token);
+ LefError(LEF_WARNING, "Unknown keyword \"%s\" in LEF file; ignoring.\n",
+ token);
LefEndStatement(f);
continue;
}
@@ -1620,7 +1928,7 @@ LefReadGeometry(GATE lefMacro, FILE *f, float oscale)
case LEF_GEOMETRY_END:
if (!LefParseEndStatement(f, NULL))
{
- LefError("Geometry (PORT or OBS) END statement missing.\n");
+ LefError(LEF_ERROR, "Geometry (PORT or OBS) END statement missing.\n");
keyword = -1;
}
break;
@@ -1649,11 +1957,12 @@ LefReadGeometry(GATE lefMacro, FILE *f, float oscale)
*/
void
-LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, oscale)
+LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, pinArea, oscale)
GATE lefMacro;
FILE *f;
char *pinName;
int pinNum, pinDir, pinUse;
+ double pinArea;
float oscale;
{
DSEG rectList, rlist;
@@ -1675,6 +1984,8 @@ LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, oscale)
nodealloc * 10 * sizeof(NODE));
lefMacro->direction = (u_char *)realloc(lefMacro->direction,
nodealloc * 10 * sizeof(u_char));
+ lefMacro->area = (float *)realloc(lefMacro->area,
+ nodealloc * 10 * sizeof(float));
lefMacro->netnum = (int *)realloc(lefMacro->netnum,
nodealloc * 10 * sizeof(int));
lefMacro->node = (char **)realloc(lefMacro->node,
@@ -1683,7 +1994,9 @@ LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, oscale)
}
lefMacro->taps[pinNum] = rectList;
lefMacro->noderec[pinNum] = NULL;
+ lefMacro->area[pinNum] = 0.0;
lefMacro->direction[pinNum] = pinDir;
+ lefMacro->area[pinNum] = pinArea;
lefMacro->netnum[pinNum] = -1;
if (pinName != NULL)
lefMacro->node[pinNum] = strdup(pinName);
@@ -1706,7 +2019,8 @@ LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, oscale)
* Read a PIN statement from a LEF file.
*
* Results:
- * None.
+ * 0 if the pin had a port (success), 1 if not (indicating
+ * an unused pin that should be ignored).
*
* Side Effects:
* Reads input from file f;
@@ -1720,7 +2034,7 @@ enum lef_pin_keys {LEF_DIRECTION = 0, LEF_USE, LEF_PORT, LEF_CAPACITANCE,
LEF_ANTENNAPAR, LEF_ANTENNAPARSIDE, LEF_ANTENNAMAX, LEF_ANTENNAMAXSIDE,
LEF_SHAPE, LEF_NETEXPR, LEF_PIN_END};
-void
+int
LefReadPin(lefMacro, f, pinname, pinNum, oscale)
GATE lefMacro;
FILE *f;
@@ -1732,6 +2046,8 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale)
int keyword, subkey;
int pinDir = PORT_CLASS_DEFAULT;
int pinUse = PORT_USE_DEFAULT;
+ float pinArea = 0.0;
+ int retval = 1;
static char *pin_keys[] = {
"DIRECTION",
@@ -1798,7 +2114,8 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale)
keyword = Lookup(token, pin_keys);
if (keyword < 0)
{
- LefError("Unknown keyword \"%s\" in LEF file; ignoring.\n", token);
+ LefError(LEF_WARNING, "Unknown keyword \"%s\" in LEF file; ignoring.\n",
+ token);
LefEndStatement(f);
continue;
}
@@ -1808,7 +2125,7 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale)
token = LefNextToken(f, TRUE);
subkey = Lookup(token, pin_classes);
if (subkey < 0)
- LefError("Improper DIRECTION statement\n");
+ LefError(LEF_ERROR, "Improper DIRECTION statement\n");
else
pinDir = lef_class_to_bitmask[subkey];
LefEndStatement(f);
@@ -1817,17 +2134,24 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale)
token = LefNextToken(f, TRUE);
subkey = Lookup(token, pin_uses);
if (subkey < 0)
- LefError("Improper USE statement\n");
+ LefError(LEF_ERROR, "Improper USE statement\n");
else
pinUse = lef_use_to_bitmask[subkey];
LefEndStatement(f);
break;
case LEF_PORT:
- LefReadPort(lefMacro, f, pinname, pinNum, pinDir, pinUse, oscale);
+ LefReadPort(lefMacro, f, pinname, pinNum, pinDir, pinUse, pinArea, oscale);
+ retval = 0;
+ break;
+ case LEF_ANTENNAGATE:
+ /* Read off the next value as the pin's antenna gate area. */
+ /* The layers or layers are not recorded. */
+ token = LefNextToken(f, TRUE);
+ sscanf(token, "%g", &pinArea);
+ LefEndStatement(f);
break;
case LEF_CAPACITANCE:
case LEF_ANTENNADIFF:
- case LEF_ANTENNAGATE:
case LEF_ANTENNAMOD:
case LEF_ANTENNAPAR:
case LEF_ANTENNAPARSIDE:
@@ -1840,13 +2164,14 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale)
case LEF_PIN_END:
if (!LefParseEndStatement(f, pinname))
{
- LefError("Pin END statement missing.\n");
+ LefError(LEF_ERROR, "Pin END statement missing.\n");
keyword = -1;
}
break;
}
if (keyword == LEF_PIN_END) break;
}
+ return retval;
}
/*
@@ -1942,7 +2267,7 @@ LefReadMacro(f, mname, oscale)
if (!strcmp(altMacro->gatename, newname))
break;
}
- LefError("Cell \"%s\" was already defined in this file. "
+ LefError(LEF_WARNING, "Cell \"%s\" was already defined in this file. "
"Renaming original cell \"%s\"\n", mname, newname);
lefMacro->gatename = strdup(newname);
@@ -1965,11 +2290,13 @@ LefReadMacro(f, mname, oscale)
lefMacro->taps = (DSEG *)malloc(10 * sizeof(DSEG));
lefMacro->noderec = (NODE *)malloc(10 * sizeof(NODE));
lefMacro->direction = (u_char *)malloc(10 * sizeof(u_char));
+ lefMacro->area = (float *)malloc(10 * sizeof(float));
lefMacro->netnum = (int *)malloc(10 * sizeof(int));
lefMacro->node = (char **)malloc(10 * sizeof(char *));
// Fill in 1st entry
lefMacro->taps[0] = NULL;
lefMacro->noderec[0] = NULL;
+ lefMacro->area[0] = 0.0;
lefMacro->node[0] = NULL;
lefMacro->netnum[0] = -1;
GateInfo = lefMacro;
@@ -1986,7 +2313,8 @@ LefReadMacro(f, mname, oscale)
keyword = Lookup(token, macro_keys);
if (keyword < 0)
{
- LefError("Unknown keyword \"%s\" in LEF file; ignoring.\n", token);
+ LefError(LEF_WARNING, "Unknown keyword \"%s\" in LEF file; ignoring.\n",
+ token);
LefEndStatement(f);
continue;
}
@@ -2013,7 +2341,7 @@ LefReadMacro(f, mname, oscale)
LefEndStatement(f);
break;
size_error:
- LefError("Bad macro SIZE; requires values X BY Y.\n");
+ LefError(LEF_ERROR, "Bad macro SIZE; requires values X BY Y.\n");
LefEndStatement(f);
break;
case LEF_ORIGIN:
@@ -2032,7 +2360,7 @@ size_error:
LefEndStatement(f);
break;
origin_error:
- LefError("Bad macro ORIGIN; requires 2 values.\n");
+ LefError(LEF_ERROR, "Bad macro ORIGIN; requires 2 values.\n");
LefEndStatement(f);
break;
case LEF_SYMMETRY:
@@ -2066,7 +2394,8 @@ origin_error:
if (is_imported)
LefSkipSection(f, tsave);
else
- LefReadPin(lefMacro, f, tsave, pinNum++, oscale);
+ if (LefReadPin(lefMacro, f, tsave, pinNum, oscale) == 0)
+ pinNum++;
break;
case LEF_OBS:
/* Diagnostic */
@@ -2087,7 +2416,7 @@ origin_error:
case LEF_MACRO_END:
if (!LefParseEndStatement(f, mname))
{
- LefError("Macro END statement missing.\n");
+ LefError(LEF_ERROR, "Macro END statement missing.\n");
keyword = -1;
}
break;
@@ -2109,7 +2438,7 @@ origin_error:
lefMacro->placedY = lefBBox.y1;
}
else {
- LefError("Gate %s has no size information!\n", lefMacro->gatename);
+ LefError(LEF_ERROR, "Gate %s has no size information!\n", lefMacro->gatename);
}
}
}
@@ -2150,6 +2479,19 @@ LefAddViaGeometry(FILE *f, LefList lefl, int curlayer, float oscale)
if (lefl->info.via.area.layer < 0)
{
lefl->info.via.area = *currect;
+
+ /* If entries exist for info.via.lr, this is a via GENERATE */
+ /* statement, and metal enclosures have been parsed. Therefore */
+ /* add the via dimensions to the enclosure rectangles. */
+
+ viarect = lefl->info.via.lr;
+ while (viarect != NULL) {
+ viarect->x1 += currect->x1;
+ viarect->x2 += currect->x2;
+ viarect->y1 += currect->y1;
+ viarect->y2 += currect->y2;
+ viarect = viarect->next;
+ }
}
else
{
@@ -2163,6 +2505,76 @@ LefAddViaGeometry(FILE *f, LefList lefl, int curlayer, float oscale)
/*
*------------------------------------------------------------
*
+ * LefNewRoute ---
+ *
+ * Allocate space for and fill out default records of a
+ * route layer.
+ *
+ *------------------------------------------------------------
+ */
+
+LefList LefNewRoute(char *name)
+{
+ LefList lefl;
+
+ lefl = (LefList)malloc(sizeof(lefLayer));
+ lefl->type = -1;
+ lefl->obsType = -1;
+ lefl->lefClass = CLASS_IGNORE; /* For starters */
+ lefl->lefName = strdup(name);
+
+ return lefl;
+}
+
+/*
+ *------------------------------------------------------------
+ *
+ * LefNewVia ---
+ *
+ * Allocate space for and fill out default records of a
+ * via definition.
+ *
+ *------------------------------------------------------------
+ */
+
+LefList LefNewVia(char *name)
+{
+ LefList lefl;
+
+ lefl = (LefList)calloc(1, sizeof(lefLayer));
+ lefl->type = -1;
+ lefl->obsType = -1;
+ lefl->lefClass = CLASS_VIA;
+ lefl->info.via.area.x1 = 0.0;
+ lefl->info.via.area.y1 = 0.0;
+ lefl->info.via.area.x2 = 0.0;
+ lefl->info.via.area.y2 = 0.0;
+ lefl->info.via.area.layer = -1;
+ lefl->info.via.cell = (GATE)NULL;
+ lefl->info.via.lr = (DSEG)NULL;
+ lefl->info.via.generated = FALSE;
+ lefl->info.via.respervia = 0.0;
+ lefl->lefName = strdup(name);
+
+ return lefl;
+}
+
+/* Note: Used directly below, as it is passed to variable "mode"
+ * in LefReadLayerSection(). However, mainly used in LefRead().
+ */
+
+enum lef_sections {LEF_VERSION = 0,
+ LEF_BUSBITCHARS, LEF_DIVIDERCHAR, LEF_MANUFACTURINGGRID,
+ LEF_USEMINSPACING, LEF_CLEARANCEMEASURE,
+ LEF_NAMESCASESENSITIVE, LEF_PROPERTYDEFS, LEF_UNITS,
+ LEF_SECTION_LAYER, LEF_SECTION_VIA, LEF_SECTION_VIARULE,
+ LEF_SECTION_SPACING, LEF_SECTION_SITE, LEF_PROPERTY,
+ LEF_NOISETABLE, LEF_CORRECTIONTABLE, LEF_IRDROP,
+ LEF_ARRAY, LEF_SECTION_TIMING, LEF_EXTENSION, LEF_MACRO,
+ LEF_END};
+/*
+ *------------------------------------------------------------
+ *
* LefReadLayerSection --
*
* Read in a LAYER, VIA, or VIARULE section from a LEF file.
@@ -2177,14 +2589,17 @@ LefAddViaGeometry(FILE *f, LefList lefl, int curlayer, float oscale)
*/
enum lef_layer_keys {LEF_LAYER_TYPE=0, LEF_LAYER_WIDTH,
- LEF_LAYER_MAXWIDTH, LEF_LAYER_AREA,
+ LEF_LAYER_MINWIDTH, LEF_LAYER_MAXWIDTH, LEF_LAYER_AREA,
LEF_LAYER_SPACING, LEF_LAYER_SPACINGTABLE,
LEF_LAYER_PITCH, LEF_LAYER_DIRECTION, LEF_LAYER_OFFSET,
LEF_LAYER_WIREEXT,
LEF_LAYER_RES, LEF_LAYER_CAP, LEF_LAYER_EDGECAP,
- LEF_LAYER_THICKNESS, LEF_LAYER_HEIGHT,
- LEF_LAYER_MINDENSITY, LEF_LAYER_ANTENNADIFF,
- LEF_LAYER_ANTENNASIDE,
+ LEF_LAYER_THICKNESS, LEF_LAYER_HEIGHT, LEF_LAYER_MINIMUMCUT,
+ LEF_LAYER_MINDENSITY, LEF_LAYER_ACDENSITY, LEF_LAYER_DCDENSITY,
+ LEF_LAYER_PROPERTY, LEF_LAYER_ANTENNAMODEL, LEF_LAYER_ANTENNA,
+ LEF_LAYER_ANTENNADIFF, LEF_LAYER_ANTENNASIDE,
+ LEF_LAYER_AGG_ANTENNA, LEF_LAYER_AGG_ANTENNADIFF,
+ LEF_LAYER_AGG_ANTENNASIDE,
LEF_VIA_DEFAULT, LEF_VIA_LAYER, LEF_VIA_RECT,
LEF_VIA_ENCLOSURE, LEF_VIA_PREFERENCLOSURE,
LEF_VIARULE_OVERHANG,
@@ -2205,6 +2620,7 @@ LefReadLayerSection(f, lname, mode, lefl)
struct seg_ viaArea;
int curlayer = -1;
double dvalue, oscale;
+ LefList altVia;
lefSpacingRule *newrule = NULL, *testrule;
/* These are defined in the order of CLASS_* in lefInt.h */
@@ -2219,6 +2635,7 @@ LefReadLayerSection(f, lname, mode, lefl)
static char *layer_keys[] = {
"TYPE",
"WIDTH",
+ "MINWIDTH",
"MAXWIDTH",
"AREA",
"SPACING",
@@ -2232,9 +2649,18 @@ LefReadLayerSection(f, lname, mode, lefl)
"EDGECAPACITANCE",
"THICKNESS",
"HEIGHT",
+ "MINIMUMCUT",
"MINIMUMDENSITY",
+ "ACCURRENTDENSITY",
+ "DCCURRENTDENSITY",
+ "PROPERTY",
+ "ANTENNAMODEL",
+ "ANTENNAAREARATIO",
"ANTENNADIFFAREARATIO",
"ANTENNASIDEAREARATIO",
+ "ANTENNACUMAREARATIO",
+ "ANTENNACUMDIFFAREARATIO",
+ "ANTENNACUMSIDEAREARATIO",
"DEFAULT",
"LAYER",
"RECT",
@@ -2268,19 +2694,24 @@ LefReadLayerSection(f, lname, mode, lefl)
keyword = Lookup(token, layer_keys);
if (keyword < 0)
{
- LefError("Unknown keyword \"%s\" in LEF file; ignoring.\n", token);
+ LefError(LEF_WARNING, "Unknown keyword \"%s\" in LEF file; ignoring.\n",
+ token);
LefEndStatement(f);
continue;
}
switch (keyword)
{
+ case LEF_LAYER_PROPERTY:
+ /* Some kind of forward-compatibility thing. */
+ LefEndStatement(f);
+ break;
case LEF_LAYER_TYPE:
token = LefNextToken(f, TRUE);
if (*token != '\n')
{
typekey = Lookup(token, layer_type_keys);
if (typekey < 0)
- LefError("Unknown layer type \"%s\" in LEF file; "
+ LefError(LEF_WARNING, "Unknown layer type \"%s\" in LEF file; "
"ignoring.\n", token);
}
if (lefl->lefClass == CLASS_IGNORE) {
@@ -2295,36 +2726,24 @@ LefReadLayerSection(f, lname, mode, lefl)
// been specified and needs to be set to default.
lefl->info.route.offsetx = -1.0;
lefl->info.route.offsety = -1.0;
- lefl->info.route.hdirection = (u_char)0;
+ lefl->info.route.hdirection = DIR_UNKNOWN;
- /* A routing type has been declared. Assume */
- /* this takes the name "metal1", "M1", or some */
- /* variant thereof. */
+ lefl->info.route.minarea = 0.0;
+ lefl->info.route.thick = 0.0;
+ lefl->info.route.antenna = 0.0;
+ lefl->info.route.method = CALC_NONE;
- for (tp = lefl->lefName; *tp != '\0'; tp++) {
- if (*tp >= '0' && *tp <= '9') {
- sscanf(tp, "%d", &lefl->type);
-
- /* "metal1", e.g., is assumed to be layer #0 */
- /* This may not be a proper assumption, always */
-
- lefl->type--;
- break;
- }
- }
+ lefl->info.route.areacap = 0.0;
+ lefl->info.route.respersq = 0.0;
+ lefl->info.route.edgecap = 0.0;
- /* This is probably some special non-numerical */
- /* name for a top metal layer. Take a stab at */
- /* it, defining it to be the next layer up from */
- /* whatever the previous topmost route layer */
- /* was. This should work unless the LEF file */
- /* is really weirdly written. */
+ /* A routing type has been declared. Route */
+ /* layers are supposed to be in order from */
+ /* bottom to top in the technology LEF file. */
- if (lefl->type < 0) {
- lefl->type = LefGetMaxLayer();
- }
+ lefl->type = LefGetMaxRouteLayer();
}
- else if (typekey == CLASS_VIA) {
+ else if (typekey == CLASS_CUT || typekey == CLASS_VIA) {
lefl->info.via.area.x1 = 0.0;
lefl->info.via.area.y1 = 0.0;
lefl->info.via.area.x2 = 0.0;
@@ -2332,19 +2751,39 @@ LefReadLayerSection(f, lname, mode, lefl)
lefl->info.via.area.layer = -1;
lefl->info.via.cell = (GATE)NULL;
lefl->info.via.lr = (DSEG)NULL;
+
+ /* Note: lefl->type not set here for cut */
+ /* layers so that route layers will all be */
+ /* clustered at the bottom. */
}
}
else if (lefl->lefClass != typekey) {
- LefError("Attempt to reclassify layer %s from %s to %s\n",
+ LefError(LEF_ERROR, "Attempt to reclassify layer %s from %s to %s\n",
lname, layer_type_keys[lefl->lefClass],
layer_type_keys[typekey]);
}
LefEndStatement(f);
break;
+ case LEF_LAYER_MINWIDTH:
+ // Not handled if width is already defined.
+ if ((lefl->lefClass != CLASS_ROUTE) ||
+ (lefl->info.route.width != 0)) {
+ LefEndStatement(f);
+ break;
+ }
+ /* drop through */
case LEF_LAYER_WIDTH:
token = LefNextToken(f, TRUE);
sscanf(token, "%lg", &dvalue);
- lefl->info.route.width = dvalue / (double)oscale;
+ if (lefl->lefClass == CLASS_ROUTE)
+ lefl->info.route.width = dvalue / (double)oscale;
+ else if (lefl->lefClass == CLASS_CUT) {
+ double baseval = (dvalue / (double)oscale) / 2.0;
+ lefl->info.via.area.x1 = -baseval;
+ lefl->info.via.area.y1 = -baseval;
+ lefl->info.via.area.x2 = baseval;
+ lefl->info.via.area.y2 = baseval;
+ }
LefEndStatement(f);
break;
case LEF_LAYER_MAXWIDTH:
@@ -2352,10 +2791,22 @@ LefReadLayerSection(f, lname, mode, lefl)
LefEndStatement(f);
break;
case LEF_LAYER_AREA:
- // Not handled, but needed!
+ /* Read minimum area rule value */
+ token = LefNextToken(f, TRUE);
+ if (lefl->lefClass == CLASS_ROUTE) {
+ sscanf(token, "%lg", &dvalue);
+ // Units of area (length * length)
+ lefl->info.route.minarea = dvalue / (double)oscale / (double)oscale;
+ }
LefEndStatement(f);
break;
case LEF_LAYER_SPACING:
+ // Only parse spacing for routes
+
+ if (lefl->lefClass != CLASS_ROUTE) {
+ LefEndStatement(f);
+ break;
+ }
token = LefNextToken(f, TRUE);
sscanf(token, "%lg", &dvalue);
token = LefNextToken(f, TRUE);
@@ -2409,12 +2860,12 @@ LefReadLayerSection(f, lname, mode, lefl)
else
entries++;
}
- if (*token != ';')
- newrule = (lefSpacingRule *)malloc(sizeof(lefSpacingRule));
while (*token != ';') {
token = LefNextToken(f, TRUE); // Minimum width value
sscanf(token, "%lg", &dvalue);
+
+ newrule = (lefSpacingRule *)malloc(sizeof(lefSpacingRule));
newrule->width = dvalue / (double)oscale;
for (i = 0; i < entries; i++) {
@@ -2422,7 +2873,6 @@ LefReadLayerSection(f, lname, mode, lefl)
}
sscanf(token, "%lg", &dvalue);
newrule->spacing = dvalue / (double)oscale;
- token = LefNextToken(f, TRUE);
for (testrule = lefl->info.route.spacing; testrule;
testrule = testrule->next)
@@ -2455,6 +2905,18 @@ LefReadLayerSection(f, lname, mode, lefl)
}
else {
lefl->info.route.pitchy = lefl->info.route.pitchx;
+ /* If the orientation is known, then zero the pitch */
+ /* in the opposing direction. If not, then set the */
+ /* direction to DIR_RESOLVE so that the pitch in */
+ /* the opposing direction can be zeroed when the */
+ /* direction is specified. */
+
+ if (lefl->info.route.hdirection == DIR_UNKNOWN)
+ lefl->info.route.hdirection = DIR_RESOLVE;
+ else if (lefl->info.route.hdirection == DIR_VERTICAL)
+ lefl->info.route.pitchy = 0.0;
+ else if (lefl->info.route.hdirection == DIR_HORIZONTAL)
+ lefl->info.route.pitchx = 0.0;
}
/* Offset default is 1/2 the pitch. Offset is */
@@ -2468,7 +2930,14 @@ LefReadLayerSection(f, lname, mode, lefl)
case LEF_LAYER_DIRECTION:
token = LefNextToken(f, TRUE);
LefLower(token);
- lefl->info.route.hdirection = (token[0] == 'h') ? TRUE : FALSE;
+ if (lefl->info.route.hdirection == DIR_RESOLVE) {
+ if (token[0] == 'h')
+ lefl->info.route.pitchx = 0.0;
+ else if (token[0] == 'v')
+ lefl->info.route.pitchy = 0.0;
+ }
+ lefl->info.route.hdirection = (token[0] == 'h') ? DIR_HORIZONTAL
+ : DIR_VERTICAL;
LefEndStatement(f);
break;
case LEF_LAYER_OFFSET:
@@ -2496,7 +2965,7 @@ LefReadLayerSection(f, lname, mode, lefl)
lefl->info.route.respersq = dvalue;
}
}
- else if (lefl->lefClass == CLASS_VIA) {
+ else if (lefl->lefClass == CLASS_VIA || lefl->lefClass == CLASS_CUT) {
sscanf(token, "%lg", &dvalue);
lefl->info.via.respervia = dvalue; // Units ohms
}
@@ -2526,9 +2995,74 @@ LefReadLayerSection(f, lname, mode, lefl)
break;
case LEF_LAYER_THICKNESS:
case LEF_LAYER_HEIGHT:
- case LEF_LAYER_MINDENSITY:
- case LEF_LAYER_ANTENNADIFF:
+ /* Assuming thickness and height are the same thing? */
+ token = LefNextToken(f, TRUE);
+ if (lefl->lefClass == CLASS_ROUTE) {
+ sscanf(token, "%lg", &dvalue);
+ // Units of length
+ lefl->info.route.thick = dvalue / (double)oscale;
+ }
+ LefEndStatement(f);
+ break;
+ case LEF_LAYER_MINIMUMCUT:
+ /* Not handling minimum cuts for wide wires yet */
+ LefEndStatement(f);
+ case LEF_LAYER_ANTENNAMODEL:
+ /* Not handling antenna models yet */
+ LefEndStatement(f);
+ break;
+ case LEF_LAYER_ANTENNA:
case LEF_LAYER_ANTENNASIDE:
+ case LEF_LAYER_AGG_ANTENNA:
+ case LEF_LAYER_AGG_ANTENNASIDE:
+ /* NOTE: Assuming that only one of these methods will */
+ /* be used! If more than one is present, then only the */
+ /* last one will be recorded and used. */
+
+ token = LefNextToken(f, TRUE);
+ if (lefl->lefClass == CLASS_ROUTE) {
+ sscanf(token, "%lg", &dvalue);
+ // Unitless values (ratio)
+ lefl->info.route.antenna = dvalue;
+ }
+ if (keyword == LEF_LAYER_ANTENNA)
+ lefl->info.route.method = CALC_AREA;
+ else if (keyword == LEF_LAYER_ANTENNASIDE)
+ lefl->info.route.method = CALC_SIDEAREA;
+ else if (keyword == LEF_LAYER_AGG_ANTENNA)
+ lefl->info.route.method = CALC_AGG_AREA;
+ else
+ lefl->info.route.method = CALC_AGG_SIDEAREA;
+ LefEndStatement(f);
+ case LEF_LAYER_ANTENNADIFF:
+ case LEF_LAYER_AGG_ANTENNADIFF:
+ /* Not specifically handling these antenna types */
+ /* (antenna ratios for antennas connected to diodes, */
+ /* which can still blow gates if the diode area is */
+ /* insufficiently large.) */
+ LefEndStatement(f);
+ break;
+ case LEF_LAYER_ACDENSITY:
+ /* The idiocy of the LEF format on display. */
+ token = LefNextToken(f, TRUE); /* value type */
+ token = LefNextToken(f, TRUE); /* value, FREQUENCY */
+ if (!strcmp(token, "FREQUENCY")) {
+ LefEndStatement(f);
+ token = LefNextToken(f, TRUE); /* value, FREQUENCY */
+ if (!strcmp(token, "WIDTH")) /* Optional width */
+ LefEndStatement(f); /* Additional statement TABLEENTRIES */
+ }
+ LefEndStatement(f);
+ break;
+ case LEF_LAYER_DCDENSITY:
+ /* The idiocy of the LEF format still on display. */
+ token = LefNextToken(f, TRUE); /* value type */
+ token = LefNextToken(f, TRUE); /* value, WIDTH */
+ if (!strcmp(token, "WIDTH"))
+ LefEndStatement(f); /* Additional statement TABLEENTRIES */
+ LefEndStatement(f);
+ break;
+ case LEF_LAYER_MINDENSITY:
case LEF_LAYER_WIREEXT:
/* Not specifically handling these */
LefEndStatement(f);
@@ -2547,10 +3081,36 @@ LefReadLayerSection(f, lname, mode, lefl)
LefEndStatement(f);
break;
case LEF_VIA_ENCLOSURE:
- case LEF_VIA_PREFERENCLOSURE:
+ /* Defines how to draw via metal layers. Ignore unless */
+ /* this is a VIARULE GENERATE section. */
+ if (mode == LEF_SECTION_VIARULE) {
+ /* Note that values can interact with ENCLOSURE */
+ /* values given for the cut layer type. This is */
+ /* not being handled. */
+
+ DSEG viarect, encrect;
+ encrect = LefReadEnclosure(f, curlayer, oscale);
+ viarect = (DSEG)malloc(sizeof(struct dseg_));
+ *viarect = *encrect;
+ viarect->next = lefl->info.via.lr;
+ lefl->info.via.lr = viarect;
+ lefl->info.via.generated = TRUE;
+ }
+ LefEndStatement(f);
+ break;
case LEF_VIARULE_OVERHANG:
case LEF_VIARULE_METALOVERHANG:
- /* Ignoring this: Need to handle via generates */
+ /* These are from older LEF definitions (e.g., 5.4) */
+ /* and cannot completely specify via geometry. So if */
+ /* seen, ignore the rest of the via section. Only the */
+ /* explicitly defined VIA types will be used. */
+ LefError(LEF_WARNING, "NOTE: Old format VIARULE ignored.\n");
+ lefl->lefClass == CLASS_IGNORE;
+ LefEndStatement(f);
+ /* LefSkipSection(f, lname); */ /* Continue parsing */
+ break;
+ case LEF_VIA_PREFERENCLOSURE:
+ /* Ignoring this. */
LefEndStatement(f);
break;
case LEF_VIARULE_VIA:
@@ -2559,7 +3119,7 @@ LefReadLayerSection(f, lname, mode, lefl)
case LEF_LAYER_END:
if (!LefParseEndStatement(f, lname))
{
- LefError("Layer END statement missing.\n");
+ LefError(LEF_ERROR, "Layer END statement missing.\n");
keyword = -1;
}
break;
@@ -2568,46 +3128,204 @@ LefReadLayerSection(f, lname, mode, lefl)
}
}
-/*----------------------------------------------------------------*/
-/* This routine runs through all the defined vias, from last to */
-/* first defined. Check the X vs. Y dimension of the base layer. */
-/* If X is longer, save as ViaX. If Y is longer, save as ViaY. */
-/* If there is an AllowedVias list, then only assign vias that */
-/* are in the list. */
-/*----------------------------------------------------------------*/
+/*--------------------------------------------------------------*/
+/* If any vias have been built from VIARULE entries, then they */
+/* do not appear in the tech LEF and need to be defined in the */
+/* DEF file. This routine finds all generated vias and writes */
+/* out the entries to the indicated file f. */
+/* */
+/* "defvias" is the number of vias found in the input DEF file. */
+/* If non-zero, they will be written out after the internally */
+/* generated vias, so add defvias to the count written after */
+/* the VIAS statement, and do not write the "END" statement. */
+/*--------------------------------------------------------------*/
+
+void
+LefWriteGeneratedVias(FILE *f, double oscale, int defvias)
+{
+ double scale;
+ int numvias;
+ LefList lefl;
+
+ scale = oscale / 2.0; /* Via dimensions are double */
+
+ /* 1st pass---check if any vias are generated. Also check if any */
+ /* vias have non-route layers (e.g., POLY, or Num_layers and above) */
+ /* and unmark them. */
+
+ numvias = defvias;
+ for (lefl = LefInfo; lefl; lefl = lefl->next)
+ if (lefl->lefClass == CLASS_VIA)
+ if (lefl->info.via.generated) {
+ if (!lefl->info.via.lr ||
+ (lefl->info.via.lr->layer < 0) ||
+ (lefl->info.via.lr->layer >= Num_layers)) {
+ lefl->info.via.generated = FALSE;
+ continue;
+ }
+ else if (!lefl->info.via.lr->next ||
+ (lefl->info.via.lr->next->layer < 0) ||
+ (lefl->info.via.lr->next->layer >= Num_layers)) {
+ lefl->info.via.generated = FALSE;
+ continue;
+ }
+ numvias++;
+ }
+
+ if (numvias == 0) return; /* Nothing to write */
+
+ fprintf(f, "\n");
+ fprintf(f, "VIAS %d ;\n", numvias);
+
+ /* 2nd pass---output the VIA records. All vias consist of */
+ /* two metal layers and a cut layer. */
+
+ for (lefl = LefInfo; lefl; lefl = lefl->next)
+ if (lefl->lefClass == CLASS_VIA)
+ if (lefl->info.via.generated) {
+ fprintf(f, "- %s\n", lefl->lefName);
+ fprintf(f, "+ RECT %s ( %ld %ld ) ( %ld %ld )",
+ CIFLayer[lefl->info.via.area.layer],
+ (long) (-0.5 + scale * lefl->info.via.area.x1),
+ (long) (-0.5 + scale * lefl->info.via.area.y1),
+ (long) (0.5 + scale * lefl->info.via.area.x2),
+ (long) (0.5 + scale * lefl->info.via.area.y2));
+ if (lefl->info.via.lr != NULL) {
+ fprintf(f, "\n+ RECT %s ( %ld %ld ) ( %ld %ld )",
+ CIFLayer[lefl->info.via.lr->layer],
+ (long) (-0.5 + scale * lefl->info.via.lr->x1),
+ (long) (-0.5 + scale * lefl->info.via.lr->y1),
+ (long) (0.5 + scale * lefl->info.via.lr->x2),
+ (long) (0.5 + scale * lefl->info.via.lr->y2));
+ if (lefl->info.via.lr->next != NULL) {
+ fprintf(f, "\n+ RECT %s ( %ld %ld ) ( %ld %ld )",
+ CIFLayer[lefl->info.via.lr->next->layer],
+ (long) (-0.5 + scale * lefl->info.via.lr->next->x1),
+ (long) (-0.5 + scale * lefl->info.via.lr->next->y1),
+ (long) (0.5 + scale * lefl->info.via.lr->next->x2),
+ (long) (0.5 + scale * lefl->info.via.lr->next->y2));
+ }
+ }
+ fprintf(f, " ;\n"); /* Finish record */
+ }
+
+ if (defvias == 0) {
+ fprintf(f, "END VIAS\n", numvias);
+ fprintf(f, "\n");
+ }
+}
+
+/*--------------------------------------------------------------*/
+/* This routine runs through all the defined vias, from last to */
+/* first defined. Check the X vs. Y dimension of the base and */
+/* top layers. If both base and top layers are longer in X, */
+/* then save as ViaXX. If longer in Y, save as ViaYY. If the */
+/* base is longer in X and the top is longer in Y, then save as */
+/* ViaXY, and if the base is longer in Y and the top is longer */
+/* in X, then save as ViaYX. */
+/* */
+/* If all via types have the same X and Y for the top and/or */
+/* bottom layer, then save as both X and Y variants. */
+/* */
+/* If there is an AllowedVias list, then only assign vias that */
+/* are in the list. */
+/* */
+/* If the layer pair has a VIARULE GENERATE type, then it is */
+/* preferred over fixed via definitions. */
+/*--------------------------------------------------------------*/
void
LefAssignLayerVias()
{
LefList lefl;
- int layer;
- double xydiff;
+ int toplayer, baselayer;
+ int minroute, maxroute;
+ double xybdiff, xytdiff;
DSEG grect;
LinkedStringPtr viaName;
- char *newViaX[MAX_LAYERS];
- char *newViaY[MAX_LAYERS];
+ char *newViaXX[MAX_LAYERS];
+ char *newViaXY[MAX_LAYERS];
+ char *newViaYX[MAX_LAYERS];
+ char *newViaYY[MAX_LAYERS];
+ u_char hasGenerate[MAX_LAYERS];
+
+ for (baselayer = 0; baselayer < MAX_LAYERS; baselayer++) {
+ newViaXX[baselayer] = newViaXY[baselayer] = NULL;
+ newViaYX[baselayer] = newViaYY[baselayer] = NULL;
+ hasGenerate[baselayer] = FALSE;
+ }
+
+ /* Determine if there is a VIARULE GENERATE for each base layer */
+
+ for (lefl = LefInfo; lefl; lefl = lefl->next) {
+ if (lefl->lefClass == CLASS_VIA) {
+ if (lefl->info.via.generated == TRUE) {
+ /* Find the base layer and set hasGenerate[] for that layer */
+ baselayer = lefl->info.via.area.layer;
+ if (lefl->info.via.lr)
+ if ((baselayer < 0) || (lefl->info.via.lr->layer < baselayer))
+ baselayer = lefl->info.via.lr->layer;
+ if (lefl->info.via.lr->next)
+ if ((baselayer < 0) || (lefl->info.via.lr->next->layer < baselayer))
+ baselayer = lefl->info.via.lr->next->layer;
+ if ((baselayer >= 0) && (baselayer < MAX_LAYERS))
+ hasGenerate[baselayer] = TRUE;
+ }
+ }
+ }
+
+ /* Make sure we know what are the minimum and maximum route layers */
- for (layer = 0; layer < MAX_LAYERS; layer++) {
- newViaX[layer] = newViaY[layer] = NULL;
+ minroute = maxroute = -1;
+ for (lefl = LefInfo; lefl; lefl = lefl->next) {
+ if (lefl->lefClass == CLASS_ROUTE) {
+ if (minroute == -1) {
+ minroute = lefl->type;
+ maxroute = lefl->type;
+ }
+ else {
+ if (lefl->type < minroute)
+ minroute = lefl->type;
+ if (lefl->type > maxroute)
+ maxroute = lefl->type;
+ }
+ }
}
for (lefl = LefInfo; lefl; lefl = lefl->next) {
if (lefl->lefClass == CLASS_VIA) {
if (lefl->info.via.lr) {
- layer = MAX_LAYERS;
- if (lefl->info.via.area.layer >= 0) {
- layer = lefl->info.via.area.layer;
- xydiff = (lefl->info.via.area.x2 - lefl->info.via.area.x1) -
+ baselayer = toplayer = MAX_LAYERS;
+ if (lefl->info.via.area.layer >= minroute &&
+ lefl->info.via.area.layer <= maxroute) {
+ baselayer = toplayer = lefl->info.via.area.layer;
+ xybdiff = xytdiff =
+ (lefl->info.via.area.x2 - lefl->info.via.area.x1) -
(lefl->info.via.area.y2 - lefl->info.via.area.y1);
}
for (grect = lefl->info.via.lr; grect; grect = grect->next) {
- if (grect->layer >= 0 && grect->layer < layer) {
- layer = grect->layer;
- xydiff = (grect->x2 - grect->x1) - (grect->y2 - grect->y1);
+ if (grect->layer >= minroute && grect->layer <= maxroute) {
+ if (grect->layer < baselayer) {
+ baselayer = grect->layer;
+ xybdiff = (grect->x2 - grect->x1) - (grect->y2 - grect->y1);
+ }
}
}
- if (layer < MAX_LAYERS) {
+ toplayer = baselayer;
+
+ for (grect = lefl->info.via.lr; grect; grect = grect->next) {
+ if (grect->layer >= minroute && grect->layer <= maxroute) {
+ if (grect->layer > toplayer) {
+ toplayer = grect->layer;
+ xytdiff = (grect->x2 - grect->x1) - (grect->y2 - grect->y1);
+ }
+ }
+ }
+
+ /* Ignore vias on undefined layers (-1) */
+ if ((baselayer < MAX_LAYERS) && (toplayer < MAX_LAYERS) &&
+ (baselayer >= 0) && (toplayer >= 0)) {
/* Assign only to layers in AllowedVias, if it is non-NULL */
if (AllowedVias != NULL) {
for (viaName = AllowedVias; viaName; viaName = viaName->next) {
@@ -2616,44 +3334,114 @@ LefAssignLayerVias()
}
if (viaName == NULL) continue;
}
- if (xydiff > -EPS) {
- if (newViaX[layer] != NULL) free(newViaX[layer]);
- newViaX[layer] = strdup(lefl->lefName);
+ else if (hasGenerate[baselayer] && lefl->info.via.generated == FALSE)
+ continue;
+
+ /* Check for unexpected via definitions */
+ if ((toplayer - baselayer) != 1) {
+ LefError(LEF_WARNING, "Via \"%s\" in LEF file is defined "
+ "on non-contiguous route layers!\n", lefl->lefName);
+ }
+
+ if ((xytdiff > EPS) && (xybdiff < -EPS)) {
+ if (newViaYX[baselayer] != NULL) free(newViaYX[baselayer]);
+ newViaYX[baselayer] = strdup(lefl->lefName);
+ }
+ else if ((xytdiff < -EPS) && (xybdiff > EPS)) {
+ if (newViaXY[baselayer] != NULL) free(newViaXY[baselayer]);
+ newViaXY[baselayer] = strdup(lefl->lefName);
+ }
+ else if ((xytdiff > EPS) || (xybdiff > EPS)) {
+ if (newViaXX[baselayer] != NULL) free(newViaXX[baselayer]);
+ newViaXX[baselayer] = strdup(lefl->lefName);
+ }
+ else if ((xytdiff < -EPS) || (xybdiff < -EPS)) {
+ if (newViaYY[baselayer] != NULL) free(newViaYY[baselayer]);
+ newViaYY[baselayer] = strdup(lefl->lefName);
}
else {
- if (newViaY[layer] != NULL) free(newViaY[layer]);
- newViaY[layer] = strdup(lefl->lefName);
+ if (newViaXX[baselayer] == NULL) {
+ newViaXX[baselayer] = strdup(lefl->lefName);
+ }
}
}
}
}
}
- /* Copy newViaX and newViaY back into viaX and viaY, making */
- /* sure that at least one entry exists for each layer. */
-
- /* At this time, only ViaX[] reports values back in */
- /* LefGetViaWidth(), so make sure that if there is only one */
- /* allowed via for a layer, it is copied into the ViaX */
- /* array, regardless of its orientation. */
+ /* Copy newVia** back into via**, making sure that at least */
+ /* one entry exists for each layer. */
- for (layer = 0; layer < MAX_LAYERS; layer++) {
- if ((newViaX[layer] == NULL) && (newViaY[layer] == NULL))
+ for (baselayer = 0; baselayer < MAX_LAYERS; baselayer++) {
+ if ((newViaXX[baselayer] == NULL) && (newViaXY[baselayer] == NULL)
+ && (newViaYX[baselayer] == NULL) && (newViaYY[baselayer] == NULL))
continue;
- if (ViaX[layer] != NULL) free(ViaX[layer]);
- if (ViaY[layer] != NULL) free(ViaY[layer]);
+ if (ViaXX[baselayer] != NULL) {
+ free(ViaXX[baselayer]);
+ ViaXX[baselayer] = NULL;
+ }
+ if (ViaXY[baselayer] != NULL) {
+ free(ViaXY[baselayer]);
+ ViaXY[baselayer] = NULL;
+ }
+ if (ViaYX[baselayer] != NULL) {
+ free(ViaYX[baselayer]);
+ ViaYX[baselayer] = NULL;
+ }
+ if (ViaYY[baselayer] != NULL) {
+ free(ViaYY[baselayer]);
+ ViaYY[baselayer] = NULL;
+ }
- if (newViaX[layer] != NULL)
- ViaX[layer] = strdup(newViaX[layer]);
- else
- ViaX[layer] = strdup(newViaY[layer]);
- if (newViaY[layer] != NULL)
- ViaY[layer] = strdup(newViaY[layer]);
+ if (newViaXX[baselayer] != NULL)
+ ViaXX[baselayer] = strdup(newViaXX[baselayer]);
+ if (newViaXY[baselayer] != NULL)
+ ViaXY[baselayer] = strdup(newViaXY[baselayer]);
+ if (newViaYX[baselayer] != NULL)
+ ViaYX[baselayer] = strdup(newViaYX[baselayer]);
+ if (newViaYY[baselayer] != NULL)
+ ViaYY[baselayer] = strdup(newViaYY[baselayer]);
+
+ /* Fallback in case some permutations don't exist */
+ if (ViaXX[baselayer] == NULL) {
+ if (newViaXY[baselayer] != NULL)
+ ViaXX[baselayer] = strdup(newViaXY[baselayer]);
+ else if (newViaYX[baselayer] != NULL)
+ ViaXX[baselayer] = strdup(newViaYX[baselayer]);
+ else if (newViaYY[baselayer] != NULL)
+ ViaXX[baselayer] = strdup(newViaYY[baselayer]);
+ }
+ if (ViaXY[baselayer] == NULL) {
+ if (newViaXX[baselayer] != NULL)
+ ViaXY[baselayer] = strdup(newViaXX[baselayer]);
+ else if (newViaYY[baselayer] != NULL)
+ ViaXY[baselayer] = strdup(newViaYY[baselayer]);
+ else if (newViaYX[baselayer] != NULL)
+ ViaXY[baselayer] = strdup(newViaYX[baselayer]);
+ }
+ if (ViaYX[baselayer] == NULL) {
+ if (newViaYY[baselayer] != NULL)
+ ViaYX[baselayer] = strdup(newViaYY[baselayer]);
+ else if (newViaXX[baselayer] != NULL)
+ ViaYX[baselayer] = strdup(newViaXX[baselayer]);
+ else if (newViaXY[baselayer] != NULL)
+ ViaYX[baselayer] = strdup(newViaXY[baselayer]);
+ }
+ if (ViaYY[baselayer] == NULL) {
+ if (newViaYX[baselayer] != NULL)
+ ViaYY[baselayer] = strdup(newViaYX[baselayer]);
+ else if (newViaXY[baselayer] != NULL)
+ ViaYY[baselayer] = strdup(newViaXY[baselayer]);
+ else if (newViaXX[baselayer] != NULL)
+ ViaYY[baselayer] = strdup(newViaXX[baselayer]);
+ }
}
- for (layer = 0; layer < MAX_LAYERS; layer++) {
- if (newViaX[layer] != NULL) free(newViaX[layer]);
- if (newViaY[layer] != NULL) free(newViaY[layer]);
+ for (baselayer = 0; baselayer < MAX_LAYERS; baselayer++) {
+ if (newViaXX[baselayer] != NULL) free(newViaXX[baselayer]);
+ if (newViaXY[baselayer] != NULL) free(newViaXY[baselayer]);
+ if (newViaYX[baselayer] != NULL) free(newViaYX[baselayer]);
+ if (newViaYY[baselayer] != NULL) free(newViaYY[baselayer]);
}
}
@@ -2675,15 +3463,7 @@ LefAssignLayerVias()
*------------------------------------------------------------
*/
-enum lef_sections {LEF_VERSION = 0,
- LEF_BUSBITCHARS, LEF_DIVIDERCHAR, LEF_MANUFACTURINGGRID,
- LEF_USEMINSPACING, LEF_CLEARANCEMEASURE,
- LEF_NAMESCASESENSITIVE, LEF_PROPERTYDEFS, LEF_UNITS,
- LEF_SECTION_LAYER, LEF_SECTION_VIA, LEF_SECTION_VIARULE,
- LEF_SECTION_SPACING, LEF_SECTION_SITE, LEF_PROPERTY,
- LEF_NOISETABLE, LEF_CORRECTIONTABLE, LEF_IRDROP,
- LEF_ARRAY, LEF_SECTION_TIMING, LEF_EXTENSION, LEF_MACRO,
- LEF_END};
+/* See above for "enum lef_sections {...}" */
int
LefRead(inName)
@@ -2696,7 +3476,7 @@ LefRead(inName)
int keyword, layer;
int oprecis = 100; // = 1 / manufacturing grid (microns)
float oscale;
- double xydiff, ogrid;
+ double xydiff, ogrid, minwidth;
LefList lefl;
DSEG grect;
GATE gateginfo;
@@ -2754,7 +3534,8 @@ LefRead(inName)
keyword = Lookup(token, sections);
if (keyword < 0)
{
- LefError("Unknown keyword \"%s\" in LEF file; ignoring.\n", token);
+ LefError(LEF_WARNING, "Unknown keyword \"%s\" in LEF file; ignoring.\n",
+ token);
LefEndStatement(f);
continue;
}
@@ -2787,35 +3568,39 @@ LefRead(inName)
sprintf(tsave, "%.127s", token);
lefl = LefFindLayer(token);
- if (lefl == NULL)
- {
- lefl = (LefList)calloc(1, sizeof(lefLayer));
- lefl->type = -1;
- lefl->obsType = -1;
- lefl->lefClass = CLASS_VIA;
- lefl->info.via.area.x1 = 0.0;
- lefl->info.via.area.y1 = 0.0;
- lefl->info.via.area.x2 = 0.0;
- lefl->info.via.area.y2 = 0.0;
- lefl->info.via.area.layer = -1;
- lefl->info.via.cell = (GATE)NULL;
- lefl->info.via.lr = (DSEG)NULL;
- lefl->lefName = strdup(token);
+ if (keyword == LEF_SECTION_VIARULE) {
+ char *vianame = (char *)malloc(strlen(token) + 3);
+ sprintf(vianame, "%s_0", token);
+
+ /* If the following keyword is GENERATE, then */
+ /* prepare up to four contact types to represent */
+ /* all possible orientations of top and bottom */
+ /* metal layers. If no GENERATE keyword, ignore. */
+
+ token = LefNextToken(f, TRUE);
+ if (!strcmp(token, "GENERATE")) {
+ lefl = LefNewVia(vianame);
+ lefl->next = LefInfo;
+ LefInfo = lefl;
+ LefReadLayerSection(f, tsave, keyword, lefl);
+ }
+ else {
+ LefSkipSection(f, tsave);
+ }
+ free(vianame);
+ }
+ else if (lefl == NULL)
+ {
+ lefl = LefNewVia(token);
lefl->next = LefInfo;
LefInfo = lefl;
-
LefReadLayerSection(f, tsave, keyword, lefl);
}
- else if (keyword == LEF_SECTION_VIARULE)
- /* If we've already seen this via, don't reprocess. */
- /* This deals with VIA followed by VIARULE. We */
- /* really ought to have special processing for the */
- /* VIARULE section. . . */
- LefSkipSection(f, tsave);
else
{
- LefError("Warning: Cut type \"%s\" redefined.\n", token);
+ LefError(LEF_WARNING, "Warning: Cut type \"%s\" redefined.\n",
+ token);
lefl = LefRedefined(lefl, token);
LefReadLayerSection(f, tsave, keyword, lefl);
}
@@ -2828,11 +3613,7 @@ LefRead(inName)
lefl = LefFindLayer(token);
if (lefl == (LefList)NULL)
{
- lefl = (LefList)malloc(sizeof(lefLayer));
- lefl->type = -1;
- lefl->obsType = -1;
- lefl->lefClass = CLASS_IGNORE; /* For starters */
- lefl->lefName = strdup(token);
+ lefl = LefNewRoute(token);
lefl->next = LefInfo;
LefInfo = lefl;
}
@@ -2840,7 +3621,8 @@ LefRead(inName)
{
if (lefl && lefl->type < 0)
{
- LefError("Layer %s is only defined for obstructions!\n", token);
+ LefError(LEF_ERROR, "Layer %s is only defined for"
+ " obstructions!\n", token);
LefSkipSection(f, tsave);
break;
}
@@ -2891,7 +3673,7 @@ LefRead(inName)
case LEF_END:
if (!LefParseEndStatement(f, "LIBRARY"))
{
- LefError("END statement out of context.\n");
+ LefError(LEF_ERROR, "END statement out of context.\n");
keyword = -1;
}
break;
@@ -2900,7 +3682,7 @@ LefRead(inName)
}
if (Verbose > 0) {
Fprintf(stdout, "LEF read: Processed %d lines.\n", lefCurrentLine);
- LefError(NULL); /* print statement of errors, if any */
+ LefError(LEF_ERROR, NULL); /* print statement of errors, if any */
}
/* Cleanup */
@@ -2926,6 +3708,7 @@ LefRead(inName)
gateginfo->taps = (DSEG *)malloc(sizeof(DSEG));
gateginfo->noderec = (NODE *)malloc(sizeof(NODE));
+ gateginfo->area = (float *)malloc(sizeof(float));
gateginfo->direction = (u_char *)malloc(sizeof(u_char));
gateginfo->netnum = (int *)malloc(sizeof(int));
gateginfo->node = (char **)malloc(sizeof(char *));
@@ -2938,6 +3721,7 @@ LefRead(inName)
gateginfo->next = GateInfo;
gateginfo->taps[0] = grect;
gateginfo->noderec[0] = NULL;
+ gateginfo->area[0] = 0.0;
gateginfo->netnum[0] = -1;
gateginfo->node[0] = strdup("pin");
GateInfo = gateginfo;
@@ -2953,6 +3737,185 @@ LefRead(inName)
strcpy(CIFLayer[lefl->type], lefl->lefName);
}
}
+
+ /* If VIARULE contacts are not square, generate rotated versions. */
+ /* Also check that VIARULE sizes meet minimum metal width requirements. */
+
+ for (lefl = LefInfo; lefl; lefl = lefl->next) {
+ if (lefl->lefClass == CLASS_VIA) {
+ if (lefl->info.via.generated == TRUE) {
+ DSEG viarect1, viarect2, viarect;
+ LefList altVia;
+ u_char nsq1, nsq2;
+ char *vianame;
+
+ viarect1 = lefl->info.via.lr;
+ if (viarect1 == NULL) continue;
+ viarect2 = lefl->info.via.lr->next;
+
+ minwidth = LefGetRouteWidth(viarect1->layer);
+ if ((viarect1->x2 - viarect1->x1 + EPS) < (2.0 * minwidth)) {
+ viarect1->x2 = minwidth;
+ viarect1->x1 = -minwidth;
+ }
+ if ((viarect1->y2 - viarect1->y1 + EPS) < (2.0 * minwidth)) {
+ viarect1->y2 = minwidth;
+ viarect1->y1 = -minwidth;
+ }
+ minwidth = LefGetRouteWidth(viarect2->layer);
+ if ((viarect2->x2 - viarect2->x1 + EPS) < (2.0 * minwidth)) {
+ viarect2->x2 = minwidth;
+ viarect2->x1 = -minwidth;
+ }
+ if ((viarect2->y2 - viarect2->y1 + EPS) < (2.0 * minwidth)) {
+ viarect2->y2 = minwidth;
+ viarect2->y1 = -minwidth;
+ }
+
+ nsq1 = (ABSDIFF((viarect1->x2 - viarect1->x1),
+ (viarect1->y2 - viarect1->y1)) > EPS) ? TRUE : FALSE;
+ if (viarect2)
+ nsq2 = (ABSDIFF((viarect2->x2 - viarect2->x1),
+ (viarect2->y2 - viarect2->y1)) > EPS) ? TRUE : FALSE;
+ else
+ nsq2 = FALSE;
+
+ /* If viarect is not square, then generate a via in the */
+ /* 90-degree rotated orientation. */
+
+ if (nsq1 || nsq2) {
+ vianame = strdup(lefl->lefName);
+ *(vianame + strlen(vianame) - 1) = '1';
+ altVia = LefFindLayer(vianame);
+ if (altVia != NULL) {
+ Fprintf(stderr, "Warning: Via name %s has already been "
+ "defined!\n", vianame);
+ continue;
+ }
+
+ altVia = LefNewVia(vianame);
+ altVia->info.via.generated = TRUE;
+ altVia->next = LefInfo;
+ LefInfo = altVia;
+
+ /* Copy all but lr geometry from original via */
+ altVia->lefClass = lefl->lefClass;
+ altVia->info.via.respervia = lefl->info.via.respervia;
+ altVia->info.via.area = lefl->info.via.area;
+
+ /* Create first lr geometry */
+ viarect = (DSEG)malloc(sizeof(struct dseg_));
+ *viarect = *viarect1;
+ if (nsq1) {
+ /* Swap X and Y to rotate */
+ viarect->x1 = viarect1->y1;
+ viarect->x2 = viarect1->y2;
+ viarect->y1 = viarect1->x1;
+ viarect->y2 = viarect1->x2;
+ }
+ viarect->next = altVia->info.via.lr;
+ altVia->info.via.lr = viarect;
+
+ /* Create second lr geometry (if it exists) */
+ if (viarect2) {
+ viarect = (DSEG)malloc(sizeof(struct dseg_));
+ *viarect = *viarect2;
+ if (nsq2) {
+ /* Swap X and Y to rotate */
+ viarect->x1 = viarect2->y1;
+ viarect->x2 = viarect2->y2;
+ viarect->y1 = viarect2->x1;
+ viarect->y2 = viarect2->x2;
+ }
+ viarect->next = altVia->info.via.lr;
+ altVia->info.via.lr = viarect;
+ }
+ free(vianame);
+ }
+ if (nsq1 && nsq2) {
+
+ /* If both contact metal layers are non-square, */
+ /* then create the additional vias with reversed */
+ /* orientations of the two layers. */
+
+ vianame = strdup(lefl->lefName);
+ *(vianame + strlen(vianame) - 1) = '2';
+ altVia = LefFindLayer(vianame);
+ if (altVia != NULL) {
+ Fprintf(stderr, "Warning: Via name %s has already been "
+ "defined!\n", vianame);
+ continue;
+ }
+
+ altVia = LefNewVia(vianame);
+ altVia->info.via.generated = TRUE;
+ altVia->next = LefInfo;
+ LefInfo = altVia;
+
+ /* Copy all but lr geometry from original via */
+ altVia->lefClass = lefl->lefClass;
+ altVia->info.via.respervia = lefl->info.via.respervia;
+ altVia->info.via.area = lefl->info.via.area;
+
+ /* Create first lr geometry, not rotated */
+ viarect = (DSEG)malloc(sizeof(struct dseg_));
+ *viarect = *lefl->info.via.lr;
+ viarect->next = altVia->info.via.lr;
+ altVia->info.via.lr = viarect;
+
+ /* Create second lr geometry, rotated */
+ viarect = (DSEG)malloc(sizeof(struct dseg_));
+ *viarect = *lefl->info.via.lr->next;
+ /* Swap X and Y to rotate */
+ viarect->x1 = lefl->info.via.lr->next->y1;
+ viarect->x2 = lefl->info.via.lr->next->y2;
+ viarect->y1 = lefl->info.via.lr->next->x1;
+ viarect->y2 = lefl->info.via.lr->next->x2;
+ viarect->next = altVia->info.via.lr;
+ altVia->info.via.lr = viarect;
+
+ /* Repeat in the opposite orientation */
+ *(vianame + strlen(vianame) - 1) = '3';
+ altVia = LefFindLayer(vianame);
+ if (altVia != NULL) {
+ Fprintf(stderr, "Warning: Via name %s has already been "
+ "defined!\n", vianame);
+ continue;
+ }
+
+ altVia = LefNewVia(vianame);
+ altVia->info.via.generated = TRUE;
+ altVia->next = LefInfo;
+ LefInfo = altVia;
+
+ /* Copy all but lr geometry from original via */
+ altVia->lefClass = lefl->lefClass;
+ altVia->info.via.respervia = lefl->info.via.respervia;
+ altVia->info.via.area = lefl->info.via.area;
+
+ /* Create first lr geometry, rotated */
+ viarect = (DSEG)malloc(sizeof(struct dseg_));
+ *viarect = *lefl->info.via.lr;
+ /* Swap X and Y to rotate */
+ viarect->x1 = lefl->info.via.lr->y1;
+ viarect->x2 = lefl->info.via.lr->y2;
+ viarect->y1 = lefl->info.via.lr->x1;
+ viarect->y2 = lefl->info.via.lr->x2;
+ viarect->next = altVia->info.via.lr;
+ altVia->info.via.lr = viarect;
+
+ /* Create second lr geometry, not rotated */
+ viarect = (DSEG)malloc(sizeof(struct dseg_));
+ *viarect = *lefl->info.via.lr->next;
+ viarect->next = altVia->info.via.lr;
+ altVia->info.via.lr = viarect;
+ free(vianame);
+ }
+ }
+ }
+ }
+
+ /* Find the best via(s) to use per route layer and record it (them) */
LefAssignLayerVias();
return oprecis;
diff --git a/lef.h b/lef.h
index 51da360..88536a3 100644
--- a/lef.h
+++ b/lef.h
@@ -32,6 +32,9 @@ typedef struct
#define DO_SPECIAL 1
#define ALL_SPECIAL 2 /* treat all nets as SPECIALNETS */
+/* Types of error messages */
+enum lef_error_types {LEF_ERROR = 0, LEF_WARNING, DEF_ERROR, DEF_WARNING};
+
/* Port classes */
enum port_classes {PORT_CLASS_DEFAULT = 0, PORT_CLASS_INPUT,
PORT_CLASS_OUTPUT, PORT_CLASS_TRISTATE, PORT_CLASS_BIDIRECTIONAL,
@@ -51,22 +54,45 @@ typedef struct _lefSpacingRule {
double spacing; /* minimum spacing rule, in microns */
} lefSpacingRule;
+/* Area calculation methods for finding antenna ratios. ANTENNA_ROUTE */
+/* is not a method but is used to indicate to the antenna search */
+/* routine that the search is for routing preparation and not for */
+/* calculating error. */
+
+enum area_methods {CALC_NONE = 0, CALC_AREA, CALC_SIDEAREA, CALC_AGG_AREA,
+ CALC_AGG_SIDEAREA, ANTENNA_ROUTE, ANTENNA_DISABLE};
+
/* Structure used to maintain default routing information for each */
/* routable layer type. */
typedef struct {
lefSpacingRule *spacing; /* spacing rules, ordered by width */
- double width; /* nominal route width, in microns */
- double pitchx; /* route X pitch, in microns */
- double pitchy; /* route Y pitch, in microns */
- double offsetx; /* route track offset from X origin, in microns */
- double offsety; /* route track offset from Y origin, in microns */
- double respersq; /* resistance per square */
- double areacap; /* area capacitance per square micron */
- double edgecap; /* edge capacitance per micron */
+ double width; /* nominal route width, in microns */
+ double pitchx; /* route X pitch, in microns */
+ double pitchy; /* route Y pitch, in microns */
+ double offsetx; /* route track offset from X origin, in microns */
+ double offsety; /* route track offset from Y origin, in microns */
+ double respersq; /* resistance per square */
+ double areacap; /* area capacitance per square micron */
+ double edgecap; /* edge capacitance per micron */
+ double minarea; /* minimum metal area rule */
+ double thick; /* metal layer thickness, if given */
+ double antenna; /* antenna area ratio rule */
+ u_char method; /* antenna rule calculation method */
u_char hdirection; /* horizontal direction preferred */
} lefRoute;
+/* These values may be used for "hdirection". initialize hdirection */
+/* with DIR_UNKNOWN. If the LEF file defines the pitch before the */
+/* direction and does not specify both X and Y pitches, then change to */
+/* DIR_RESOLVE to indicate that the pitch in the non-preferred */
+/* direction should be zeroed when the preferred direction is known. */
+
+#define DIR_VERTICAL (u_char)0
+#define DIR_HORIZONTAL (u_char)1
+#define DIR_UNKNOWN (u_char)2
+#define DIR_RESOLVE (u_char)3
+
/* Structure used to maintain default generation information for each */
/* via or viarule (contact) type. If "cell" is non-NULL, then the via */
/* is saved in a cell (pointed to by "cell"), and "area" describes the */
@@ -81,15 +107,19 @@ typedef struct {
/* more complicated geometry. */
double respervia; /* resistance per via */
int obsType; /* Secondary obstruction type */
+ char generated; /* Flag indicating via from VIARULE */
} lefVia;
/* Defined types for "lefClass" in the lefLayer structure */
+/* Note that the first four match TYPE records in the LEF. IGNORE has */
+/* a special meaning to qrouter, and VIA is for VIA definitions. */
-#define CLASS_ROUTE 0 /* routing layer */
-#define CLASS_VIA 1 /* via or cut layer */
+#define CLASS_ROUTE 0 /* route layer */
+#define CLASS_CUT 1 /* cut layer */
#define CLASS_MASTER 2 /* masterslice layer */
#define CLASS_OVERLAP 3 /* overlap layer */
#define CLASS_IGNORE 4 /* inactive layer */
+#define CLASS_VIA 5 /* via record */
/* Structure defining a route or via layer and matching it to a magic */
/* layer type. This structure is saved in the LefInfo list. */
@@ -131,19 +161,28 @@ int LefReadLayer(FILE *f, u_char obstruct);
LefList LefFindLayer(char *token);
LefList LefFindLayerByNum(int layer);
int LefFindLayerNum(char *token);
+void LefSetRoutePitchX(int layer, double value);
+void LefSetRoutePitchY(int layer, double value);
double LefGetRouteKeepout(int layer);
double LefGetRouteWidth(int layer);
+double LefGetRouteMinArea(int layer);
double LefGetXYViaWidth(int base, int layer, int dir, int orient);
double LefGetViaWidth(int base, int layer, int dir);
double LefGetRouteSpacing(int layer);
double LefGetRouteWideSpacing(int layer, double width);
double LefGetRoutePitch(int layer);
+double LefGetRoutePitchX(int layer);
+double LefGetRoutePitchY(int layer);
double LefGetRouteOffset(int layer);
+double LefGetRouteThickness(int layer);
+double LefGetRouteAreaRatio(int layer);
+u_char LefGetRouteAntennaMethod(int layer);
int LefGetRouteRCvalues(int layer, double *areacap, double *edgecap,
double *respersq);
int LefGetViaResistance(int layer, double *respervia);
char *LefGetRouteName(int layer);
int LefGetRouteOrientation(int layer);
+int LefGetMaxRouteLayer(void);
int LefGetMaxLayer(void);
GATE LefFindInstance(char *name);
@@ -151,8 +190,10 @@ void LefHashCell(GATE gateginfo);
int LefRead(char *inName);
void LefAssignLayerVias();
+void LefWriteGeneratedVias(FILE *f, double oscale, int defvias);
+
-void LefError(char *fmt, ...); /* Variable argument procedure requires */
- /* parameter list. */
+void LefError(int type, char *fmt, ...); /* Variable argument procedure */
+ /* requires parameter list. */
#endif /* _LEFINT_H */
diff --git a/mask.c b/mask.c
index 3a2fd03..2a72449 100644
--- a/mask.c
+++ b/mask.c
@@ -46,11 +46,10 @@ int compNets(NET *a, NET *b)
// 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;
+ if ((p->flags & NET_CRITICAL) || (q->flags & NET_CRITICAL)) {
+ if (!(p->flags & NET_CRITICAL)) return 1;
+ else if (!(q->flags & NET_CRITICAL)) return -1;
+ else return (p->netorder < q->netorder) ? -1 : 1;
}
// Otherwise sort by number of nodes
@@ -83,13 +82,13 @@ int altCompNets(NET *a, NET *b)
// 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;
+ if ((p->flags & NET_CRITICAL) || (q->flags & NET_CRITICAL)) {
+ if (!(p->flags & NET_CRITICAL)) return 1;
+ else if (!(q->flags & NET_CRITICAL)) return -1;
+ else return (p->netorder < q->netorder) ? -1 : 1;
}
+
// Otherwise sort as described above.
pwidth = p->xmax - p->xmin;
@@ -142,12 +141,10 @@ void create_netorder(u_char method)
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;
- }
+ net = DefFindNet(cn->name);
+ if (net) {
+ net->netorder = i++;
+ net->flags |= NET_CRITICAL;
}
}
@@ -344,7 +341,7 @@ void defineRouteTree(NET net)
void initMask(void)
{
- RMask = (u_char *)calloc(NumChannelsX[0] * NumChannelsY[0],
+ RMask = (u_char *)calloc(NumChannelsX * NumChannelsY,
sizeof(u_char));
if (!RMask) {
fprintf(stderr, "Out of memory 3.\n");
@@ -374,9 +371,9 @@ create_vbranch_mask(int x, int y1, int y2, u_char slack, u_char halo)
gy2 = y2 + slack;
}
if (gx1 < 0) gx1 = 0;
- if (gx2 >= NumChannelsX[0]) gx2 = NumChannelsX[0] - 1;
+ if (gx2 >= NumChannelsX) gx2 = NumChannelsX - 1;
if (gy1 < 0) gy1 = 0;
- if (gy2 >= NumChannelsY[0]) gy2 = NumChannelsY[0] - 1;
+ if (gy2 >= NumChannelsY) gy2 = NumChannelsY - 1;
for (i = gx1; i <= gx2; i++)
for (j = gy1; j <= gy2; j++)
@@ -384,10 +381,10 @@ create_vbranch_mask(int x, int y1, int y2, u_char slack, u_char halo)
for (v = 1; v < halo; v++) {
if (gx1 > 0) gx1--;
- if (gx2 < NumChannelsX[0] - 1) gx2++;
+ if (gx2 < NumChannelsX - 1) gx2++;
if (y1 > y2) {
- if (gy1 < NumChannelsY[0] - 1) gy1++;
- if (gy2 < NumChannelsY[0] - 1) gy2++;
+ if (gy1 < NumChannelsY - 1) gy1++;
+ if (gy2 < NumChannelsY - 1) gy2++;
}
else {
if (gy1 > 0) gy1--;
@@ -423,9 +420,9 @@ create_hbranch_mask(int y, int x1, int x2, u_char slack, u_char halo)
gx2 = x2 + slack;
}
if (gx1 < 0) gx1 = 0;
- if (gx2 >= NumChannelsX[0]) gx2 = NumChannelsX[0] - 1;
+ if (gx2 >= NumChannelsX) gx2 = NumChannelsX - 1;
if (gy1 < 0) gy1 = 0;
- if (gy2 >= NumChannelsY[0]) gy2 = NumChannelsY[0] - 1;
+ if (gy2 >= NumChannelsY) gy2 = NumChannelsY - 1;
for (i = gx1; i <= gx2; i++)
for (j = gy1; j <= gy2; j++)
@@ -433,10 +430,10 @@ create_hbranch_mask(int y, int x1, int x2, u_char slack, u_char halo)
for (v = 1; v < halo; v++) {
if (gy1 > 0) gy1--;
- if (gy2 < NumChannelsY[0] - 1) gy2++;
+ if (gy2 < NumChannelsY - 1) gy2++;
if (x1 > x2) {
- if (gx1 < NumChannelsX[0] - 1) gx1++;
- if (gx2 < NumChannelsX[0] - 1) gx2++;
+ if (gx1 < NumChannelsX - 1) gx1++;
+ if (gx2 < NumChannelsX - 1) gx2++;
}
else {
if (gx1 > 0) gx1--;
@@ -513,27 +510,27 @@ void createBboxMask(NET net, u_char halo)
for (i = 1; i <= halo; i++) {
gx1 = xmin - i;
- if (gx1 >= 0 && gx1 < NumChannelsX[0])
+ if (gx1 >= 0 && gx1 < NumChannelsX)
for (j = ymin - i; j <= ymax + i; j++)
- if (j >= 0 && j < NumChannelsY[0])
+ if (j >= 0 && j < NumChannelsY)
RMASK(gx1, j) = (u_char)i;
gx2 = xmax + i;
- if (gx2 >= 0 && gx2 < NumChannelsX[0])
+ if (gx2 >= 0 && gx2 < NumChannelsX)
for (j = ymin - i; j <= ymax + i; j++)
- if (j >= 0 && j < NumChannelsY[0])
+ if (j >= 0 && j < NumChannelsY)
RMASK(gx2, j) = (u_char)i;
gy1 = ymin - i;
- if (gy1 >= 0 && gy1 < NumChannelsY[0])
+ if (gy1 >= 0 && gy1 < NumChannelsY)
for (j = xmin - i; j <= xmax + i; j++)
- if (j >= 0 && j < NumChannelsX[0])
+ if (j >= 0 && j < NumChannelsX)
RMASK(j, gy1) = (u_char)i;
gy2 = ymax + i;
- if (gy2 >= 0 && gy2 < NumChannelsY[0])
+ if (gy2 >= 0 && gy2 < NumChannelsY)
for (j = xmin - i; j <= xmax + i; j++)
- if (j >= 0 && j < NumChannelsX[0])
+ if (j >= 0 && j < NumChannelsX)
RMASK(j, gy2) = (u_char)i;
}
}
@@ -637,10 +634,16 @@ void createMask(NET net, u_char slack, u_char halo)
xmin = oxmin;
xmax = oxmax;
+ // Avoid faulting if the min/max values were never set
+ if (xmin > xmax) {
+ xmin = 0;
+ xmax = NumChannelsX - 1;
+ }
+
for (i = xmin - slack; i <= xmax + slack; i++) {
- if (i < 0 || i >= NumChannelsX[0]) continue;
+ if (i < 0 || i >= NumChannelsX) continue;
for (j = ycent - slack; j <= ycent + slack; j++) {
- if (j < 0 || j >= NumChannelsY[0]) continue;
+ if (j < 0 || j >= NumChannelsY) continue;
RMASK(i, j) = (u_char)0;
}
}
@@ -649,19 +652,19 @@ void createMask(NET net, u_char slack, u_char halo)
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 (j < 0 || j >= NumChannelsX) continue;
if (gy1 >= 0)
RMASK(j, gy1) = (u_char)i;
- if (gy2 < NumChannelsY[0])
+ if (gy2 < NumChannelsY)
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 (j < 0 || j >= NumChannelsY) continue;
if (gx1 >= 0)
RMASK(gx1, j) = (u_char)i;
- if (gx2 < NumChannelsX[0])
+ if (gx2 < NumChannelsX)
RMASK(gx2, j) = (u_char)i;
}
}
@@ -673,10 +676,16 @@ void createMask(NET net, u_char slack, u_char halo)
ymin = oymin;
ymax = oymax;
+ // Avoid faulting if the min/max values were never set
+ if (ymin > ymax) {
+ ymin = 0;
+ ymax = NumChannelsY - 1;
+ }
+
for (i = xcent - slack; i <= xcent + slack; i++) {
- if (i < 0 || i >= NumChannelsX[0]) continue;
+ if (i < 0 || i >= NumChannelsX) continue;
for (j = ymin - slack; j <= ymax + slack; j++) {
- if (j < 0 || j >= NumChannelsY[0]) continue;
+ if (j < 0 || j >= NumChannelsY) continue;
RMASK(i, j) = (u_char)0;
}
}
@@ -685,19 +694,19 @@ void createMask(NET net, u_char slack, u_char halo)
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 (j < 0 || j >= NumChannelsY) continue;
if (gx1 >= 0)
RMASK(gx1, j) = (u_char)i;
- if (gx2 < NumChannelsX[0])
+ if (gx2 < NumChannelsX)
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 (j < 0 || j >= NumChannelsX) continue;
if (gy1 >= 0)
RMASK(j, gy1) = (u_char)i;
- if (gy2 < NumChannelsY[0])
+ if (gy2 < NumChannelsY)
RMASK(j, gy2) = (u_char)i;
}
}
@@ -797,7 +806,7 @@ void createMask(NET net, u_char slack, u_char halo)
void fillMask(u_char value) {
memset((void *)RMask, (int)value,
- (size_t)(NumChannelsX[0] * NumChannelsY[0]
+ (size_t)(NumChannelsX * NumChannelsY
* sizeof(u_char)));
}
diff --git a/mask.h b/mask.h
index 6540d00..453e7d4 100644
--- a/mask.h
+++ b/mask.h
@@ -13,5 +13,6 @@ 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);
+extern void create_netorder(u_char method);
#endif /* _MASKINT_H */
diff --git a/maze.c b/maze.c
index 6cb38c5..737e3f7 100644
--- a/maze.c
+++ b/maze.c
@@ -151,10 +151,10 @@ int set_powerbus_to_net(int netnum)
PROUTE *Pr;
rval = 0;
- if ((netnum == VDD_NET) || (netnum == GND_NET)) {
+ if ((netnum == VDD_NET) || (netnum == GND_NET) || (netnum == ANTENNA_NET)) {
for (lay = 0; lay < Num_layers; lay++)
- for (x = 0; x < NumChannelsX[lay]; x++)
- for (y = 0; y < NumChannelsY[lay]; y++)
+ for (x = 0; x < NumChannelsX; x++)
+ for (y = 0; y < NumChannelsY; y++)
if ((OBSVAL(x, y, lay) & NETNUM_MASK) == netnum) {
Pr = &OBS2VAL(x, y, lay);
// Skip locations that have been purposefully disabled
@@ -370,7 +370,8 @@ int set_node_to_net(NODE node, int newflags, POINT *pushlist,
/* net is a power bus, just return. */
if ((node->taps == NULL) && (node->extend == NULL)) {
- if ((node->netnum == VDD_NET) || (node->netnum == GND_NET))
+ if ((node->netnum == VDD_NET) || (node->netnum == GND_NET) ||
+ (node->netnum == ANTENNA_NET))
return result;
}
@@ -722,11 +723,14 @@ int set_route_to_net_recursive(NET net, ROUTE rt, int newflags,
}
}
}
- else {
+ else if (rt->start.route) {
result = set_route_to_net_recursive(net, rt->start.route, newflags,
pushlist, bbox, stage);
if (result < 0) return result;
}
+ else
+ Fprintf(stderr, "Error: Route start information not recorded, cannot walk.\n");
+
if (rt->flags & RT_END_NODE) {
for (route = net->routes; route; route = route->next) {
if (!(route->flags & RT_START_NODE) && (route->start.route == rt)) {
@@ -741,11 +745,13 @@ int set_route_to_net_recursive(NET net, ROUTE rt, int newflags,
}
}
}
- else {
+ else if (rt->end.route) {
result = set_route_to_net_recursive(net, rt->end.route, newflags,
pushlist, bbox, stage);
if (result < 0) return result;
}
+ else
+ Fprintf(stderr, "Error: Route end information not recorded, cannot walk.\n");
return result;
}
@@ -879,13 +885,13 @@ NETLIST find_colliding(NET net, int *ripnum)
while (1) {
orignet = OBSVAL(x, y, lay) & ROUTED_NET_MASK;
- if (orignet == DRC_BLOCKAGE) {
+ if ((orignet & DRC_BLOCKAGE) == DRC_BLOCKAGE) {
/* If original position was a DRC-related blockage, */
/* find out which net or nets would be in conflict. */
if (needblock[lay] & (ROUTEBLOCKX | VIABLOCKX)) {
- if (x < NumChannelsX[lay] - 1) {
+ if (x < NumChannelsX - 1) {
orignet = OBSVAL(x + 1, y, lay) & ROUTED_NET_MASK;
if (!(orignet & NO_NET)) {
orignet &= NETNUM_MASK;
@@ -903,7 +909,7 @@ NETLIST find_colliding(NET net, int *ripnum)
}
}
if (needblock[lay] & (ROUTEBLOCKY | VIABLOCKY)) {
- if (y < NumChannelsY[lay] - 1) {
+ if (y < NumChannelsY - 1) {
orignet = OBSVAL(x, y + 1, lay) & ROUTED_NET_MASK;
if (!(orignet & NO_NET)) {
orignet &= NETNUM_MASK;
@@ -1012,11 +1018,11 @@ void analyze_route_overwrite(int x, int y, int lay, int netnum)
/* Check on all sides to see if position is orphaned */
- if ((x < NumChannelsX[0] - 1) && (OBSVAL(x + 1, y, lay) & NETNUM_MASK) == netnum)
+ if ((x < NumChannelsX - 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)
+ else if ((y < NumChannelsY - 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;
@@ -1121,6 +1127,44 @@ void remove_routes(ROUTE netroutes, u_char flagged)
}
/*--------------------------------------------------------------*/
+/* Clear a DRC blockage. Normally, just remove the */
+/* DRC_BLOCKAGE flag from Obs[]. However, more than one net */
+/* may set a block on the position, so the lower four bits */
+/* (OBSTRUCT_MASK) holds the reference count. */
+/*--------------------------------------------------------------*/
+
+void clear_drc_blockage(x, y, lay)
+{
+ int blockcount;
+
+ blockcount = OBSVAL(x, y, lay) & OBSTRUCT_MASK;
+ OBSVAL(x, y, lay) &= ~OBSTRUCT_MASK;
+ if (blockcount > 0)
+ OBSVAL(x, y, lay) |= (blockcount - 1);
+ else
+ OBSVAL(x, y, lay) &= ~DRC_BLOCKAGE;
+}
+
+/*--------------------------------------------------------------*/
+/*--------------------------------------------------------------*/
+
+void set_drc_blockage(x, y, lay)
+{
+ int blockcount, obsval;
+
+ obsval = OBSVAL(x, y, lay);
+ if ((obsval & DRC_BLOCKAGE) == DRC_BLOCKAGE) {
+ blockcount = OBSVAL(x, y, lay) & OBSTRUCT_MASK;
+ OBSVAL(x, y, lay) &= ~OBSTRUCT_MASK;
+ OBSVAL(x, y, lay) |= (blockcount + 1);
+ }
+ else if ((obsval & NETNUM_MASK) == 0) {
+ OBSVAL(x, y, lay) &= ~OBSTRUCT_MASK;
+ OBSVAL(x, y, lay) |= DRC_BLOCKAGE;
+ }
+}
+
+/*--------------------------------------------------------------*/
/* ripup_net --- */
/* */
/* Rip up the entire network located at position x, y, lay. */
@@ -1169,7 +1213,8 @@ u_char ripup_net(NET net, u_char restore, u_char flagged, u_char retain)
// net and route associated with the incorrect net.
analyze_route_overwrite(x, y, lay, oldnet);
- // return FALSE; // Something went wrong
+ if ((rt == NULL) || (rt->segments == NULL))
+ return FALSE; // Something went wrong
}
// Reset the net number to zero along this route for
@@ -1197,20 +1242,20 @@ u_char ripup_net(NET net, u_char restore, u_char flagged, u_char retain)
if (needblock[lay] & (ROUTEBLOCKX | VIABLOCKX)) {
if ((x > 0) && ((OBSVAL(x - 1, y, lay) &
DRC_BLOCKAGE) == DRC_BLOCKAGE))
- OBSVAL(x - 1, y, lay) &= ~DRC_BLOCKAGE;
- else if ((x < NumChannelsX[lay] - 1) &&
+ clear_drc_blockage(x - 1, y, lay);
+ else if ((x < NumChannelsX - 1) &&
((OBSVAL(x + 1, y, lay) &
DRC_BLOCKAGE) == DRC_BLOCKAGE))
- OBSVAL(x + 1, y, lay) &= ~DRC_BLOCKAGE;
+ clear_drc_blockage(x + 1, y, lay);
}
if (needblock[lay] & (ROUTEBLOCKY | VIABLOCKY)) {
if ((y > 0) && ((OBSVAL(x, y - 1, lay) &
DRC_BLOCKAGE) == DRC_BLOCKAGE))
- OBSVAL(x, y - 1, lay) &= ~DRC_BLOCKAGE;
- else if ((y < NumChannelsY[lay] - 1) &&
+ clear_drc_blockage(x, y - 1, lay);
+ else if ((y < NumChannelsY - 1) &&
((OBSVAL(x, y + 1, lay) &
DRC_BLOCKAGE) == DRC_BLOCKAGE))
- OBSVAL(x, y + 1, lay) &= ~DRC_BLOCKAGE;
+ clear_drc_blockage(x, y + 1, lay);
}
}
@@ -1379,7 +1424,7 @@ POINT eval_pt(GRIDP *ept, u_char flags, u_char stage)
Pr->prdata.cost = MAXRT;
thiscost += ConflictCost;
}
- else if (stage && (netnum == DRC_BLOCKAGE)) {
+ else if (stage && ((netnum & DRC_BLOCKAGE) == DRC_BLOCKAGE)) {
if ((newpt.lay < Pinlayers) && nodeptr && (nodeptr->nodesav != NULL))
return NULL; // But cannot route over terminals!
@@ -1390,7 +1435,7 @@ POINT eval_pt(GRIDP *ept, u_char flags, u_char stage)
// route here if any of them are on the noripup list.
if (needblock[newpt.lay] & (ROUTEBLOCKX | VIABLOCKX)) {
- if (newpt.x < NumChannelsX[newpt.lay] - 1) {
+ if (newpt.x < NumChannelsX - 1) {
netnum = OBSVAL(newpt.x + 1, newpt.y, newpt.lay) & ROUTED_NET_MASK;
if (!(netnum & NO_NET)) {
netnum &= NETNUM_MASK;
@@ -1415,7 +1460,7 @@ POINT eval_pt(GRIDP *ept, u_char flags, u_char stage)
}
}
if (needblock[newpt.lay] & (ROUTEBLOCKY | VIABLOCKY)) {
- if (newpt.y < NumChannelsY[newpt.lay] - 1) {
+ if (newpt.y < NumChannelsY - 1) {
netnum = OBSVAL(newpt.x, newpt.y + 1, newpt.lay) & ROUTED_NET_MASK;
if (!(netnum & NO_NET)) {
netnum &= NETNUM_MASK;
@@ -1578,20 +1623,16 @@ void writeback_segment(SEG seg, int netnum)
dir = OBSVAL(seg->x1, seg->y1, seg->layer + 1) & (BLOCKED_MASK | PINOBSTRUCTMASK);
OBSVAL(seg->x1, seg->y1, seg->layer + 1) = netnum | dir;
if (needblock[seg->layer + 1] & VIABLOCKX) {
- if ((seg->x1 < (NumChannelsX[seg->layer + 1] - 1)) &&
- (OBSVAL(seg->x1 + 1, seg->y1, seg->layer + 1) & NETNUM_MASK) == 0)
- OBSVAL(seg->x1 + 1, seg->y1, seg->layer + 1) = DRC_BLOCKAGE;
- if ((seg->x1 > 0) &&
- (OBSVAL(seg->x1 - 1, seg->y1, seg->layer + 1) & NETNUM_MASK) == 0)
- OBSVAL(seg->x1 - 1, seg->y1, seg->layer + 1) = DRC_BLOCKAGE;
+ if (seg->x1 < (NumChannelsX - 1))
+ set_drc_blockage(seg->x1 + 1, seg->y1, seg->layer + 1);
+ if (seg->x1 > 0)
+ set_drc_blockage(seg->x1 - 1, seg->y1, seg->layer + 1);
}
if (needblock[seg->layer + 1] & VIABLOCKY) {
- if ((seg->y1 < (NumChannelsY[seg->layer + 1] - 1)) &&
- (OBSVAL(seg->x1, seg->y1 + 1, seg->layer + 1) & NETNUM_MASK) == 0)
- OBSVAL(seg->x1, seg->y1 + 1, seg->layer + 1) = DRC_BLOCKAGE;
- if ((seg->y1 > 0) &&
- (OBSVAL(seg->x1, seg->y1 - 1, seg->layer + 1) & NETNUM_MASK) == 0)
- OBSVAL(seg->x1, seg->y1 - 1, seg->layer + 1) = DRC_BLOCKAGE;
+ if (seg->y1 < (NumChannelsY - 1))
+ set_drc_blockage(seg->x1, seg->y1 + 1, seg->layer + 1);
+ if (seg->y1 > 0)
+ set_drc_blockage(seg->x1, seg->y1 - 1, seg->layer + 1);
}
// If position itself is an offset route, then make the route position
@@ -1605,23 +1646,23 @@ void writeback_segment(SEG seg, int netnum)
lnode = NODEIPTR(seg->x1, seg->y1, seg->layer);
dist = lnode->offset;
if (lnode->flags & NI_OFFSET_EW) {
- if ((dist > 0) && (seg->x1 < (NumChannelsX[seg->layer] - 1))) {
- OBSVAL(seg->x1 + 1, seg->y1, seg->layer) |= DRC_BLOCKAGE;
- OBSVAL(seg->x1 + 1, seg->y1, seg->layer + 1) |= DRC_BLOCKAGE;
+ if ((dist > 0) && (seg->x1 < (NumChannelsX - 1))) {
+ set_drc_blockage(seg->x1 + 1, seg->y1, seg->layer);
+ set_drc_blockage(seg->x1 + 1, seg->y1, seg->layer + 1);
}
if ((dist < 0) && (seg->x1 > 0)) {
- OBSVAL(seg->x1 - 1, seg->y1, seg->layer) |= DRC_BLOCKAGE;
- OBSVAL(seg->x1 - 1, seg->y1, seg->layer + 1) |= DRC_BLOCKAGE;
+ set_drc_blockage(seg->x1 - 1, seg->y1, seg->layer);
+ set_drc_blockage(seg->x1 - 1, seg->y1, seg->layer + 1);
}
}
else if (lnode->flags & NI_OFFSET_NS) {
- if ((dist > 0) && (seg->y1 < (NumChannelsY[seg->layer] - 1))) {
- OBSVAL(seg->x1, seg->y1 + 1, seg->layer) |= DRC_BLOCKAGE;
- OBSVAL(seg->x1, seg->y1 + 1, seg->layer + 1) |= DRC_BLOCKAGE;
+ if ((dist > 0) && (seg->y1 < (NumChannelsY - 1))) {
+ set_drc_blockage(seg->x1, seg->y1 + 1, seg->layer);
+ set_drc_blockage(seg->x1, seg->y1 + 1, seg->layer + 1);
}
if ((dist < 0) && (seg->y1 > 0)) {
- OBSVAL(seg->x1, seg->y1 - 1, seg->layer) |= DRC_BLOCKAGE;
- OBSVAL(seg->x1, seg->y1 - 1, seg->layer + 1) |= DRC_BLOCKAGE;
+ set_drc_blockage(seg->x1, seg->y1 - 1, seg->layer);
+ set_drc_blockage(seg->x1, seg->y1 - 1, seg->layer + 1);
}
}
}
@@ -1631,12 +1672,10 @@ void writeback_segment(SEG seg, int netnum)
dir = OBSVAL(i, seg->y1, seg->layer) & (BLOCKED_MASK | PINOBSTRUCTMASK);
OBSVAL(i, seg->y1, seg->layer) = netnum | dir;
if (needblock[seg->layer] & ROUTEBLOCKY) {
- if ((seg->y1 < (NumChannelsY[seg->layer] - 1)) &&
- (OBSVAL(i, seg->y1 + 1, seg->layer) & NETNUM_MASK) == 0)
- OBSVAL(i, seg->y1 + 1, seg->layer) = DRC_BLOCKAGE;
- if ((seg->y1 > 0) &&
- (OBSVAL(i, seg->y1 - 1, seg->layer) & NETNUM_MASK) == 0)
- OBSVAL(i, seg->y1 - 1, seg->layer) = DRC_BLOCKAGE;
+ if (seg->y1 < (NumChannelsY - 1))
+ set_drc_blockage(i, seg->y1 + 1, seg->layer);
+ if (seg->y1 > 0)
+ set_drc_blockage(i, seg->y1 - 1, seg->layer);
}
// Check position on each side for an offset tap on a different net, and
@@ -1647,14 +1686,14 @@ void writeback_segment(SEG seg, int netnum)
// cause a DRC error. Could be refined. . .
layer = (seg->layer == 0) ? 0 : seg->layer - 1;
- if (seg->y1 < (NumChannelsY[layer] - 1)) {
+ if (seg->y1 < (NumChannelsY - 1)) {
sobs = OBSVAL(i, seg->y1 + 1, layer);
if ((sobs & OFFSET_TAP) && !(sobs & ROUTED_NET)) {
lnode = NODEIPTR(i, seg->y1 + 1, layer);
if (lnode->flags & NI_OFFSET_NS) {
dist = lnode->offset;
if (dist < 0) {
- OBSVAL(i, seg->y1 + 1, layer) |= DRC_BLOCKAGE;
+ set_drc_blockage(i, seg->y1 + 1, layer);
}
}
}
@@ -1666,37 +1705,50 @@ void writeback_segment(SEG seg, int netnum)
if (lnode->flags & NI_OFFSET_NS) {
dist = lnode->offset;
if (dist > 0) {
- OBSVAL(i, seg->y1 - 1, layer) |= DRC_BLOCKAGE;
+ set_drc_blockage(i, seg->y1 - 1, layer);
}
}
}
}
if (i == seg->x2) break;
}
+
+ /* Check top of route for vertical routes */
+
+ if (seg->y1 != seg->y2) {
+ dir = OBSVAL(seg->x2, seg->y2, seg->layer) & (BLOCKED_MASK | PINOBSTRUCTMASK);
+ OBSVAL(seg->x2, seg->y2, seg->layer) = netnum | dir;
+ if (needblock[seg->layer] & ROUTEBLOCKY) {
+ if (seg->y2 < (NumChannelsY - 1))
+ set_drc_blockage(seg->x2, seg->y2 + 1, seg->layer);
+ if (seg->y2 > 0)
+ set_drc_blockage(seg->x2, seg->y2 - 1, seg->layer);
+ }
+ }
+
+
for (i = seg->y1; ; i += (seg->y2 > seg->y1) ? 1 : -1) {
dir = OBSVAL(seg->x1, i, seg->layer) & (BLOCKED_MASK | PINOBSTRUCTMASK);
OBSVAL(seg->x1, i, seg->layer) = netnum | dir;
if (needblock[seg->layer] & ROUTEBLOCKX) {
- if ((seg->x1 < (NumChannelsX[seg->layer] - 1)) &&
- (OBSVAL(seg->x1 + 1, i, seg->layer) & NETNUM_MASK) == 0)
- OBSVAL(seg->x1 + 1, i, seg->layer) = DRC_BLOCKAGE;
- if ((seg->x1 > 0) &&
- (OBSVAL(seg->x1 - 1, i, seg->layer) & NETNUM_MASK) == 0)
- OBSVAL(seg->x1 - 1, i, seg->layer) = DRC_BLOCKAGE;
+ if (seg->x1 < (NumChannelsX - 1))
+ set_drc_blockage(seg->x1 + 1, i, seg->layer);
+ if (seg->x1 > 0)
+ set_drc_blockage(seg->x1 - 1, i, seg->layer);
}
// Check position on each side for an offset tap on a different net, and
// mark the position unroutable (see above).
layer = (seg->layer == 0) ? 0 : seg->layer - 1;
- if (seg->x1 < (NumChannelsX[layer] - 1)) {
+ if (seg->x1 < (NumChannelsX - 1)) {
sobs = OBSVAL(seg->x1 + 1, i, layer);
if ((sobs & OFFSET_TAP) && !(sobs & ROUTED_NET)) {
lnode = NODEIPTR(seg->x1 + 1, i, layer);
if (lnode->flags & NI_OFFSET_EW) {
dist = lnode->offset;
if (dist < 0) {
- OBSVAL(seg->x1 + 1, i, layer) |= DRC_BLOCKAGE;
+ set_drc_blockage(seg->x1 + 1, i, layer);
}
}
}
@@ -1708,13 +1760,26 @@ void writeback_segment(SEG seg, int netnum)
if (lnode->flags & NI_OFFSET_EW) {
dist = lnode->offset;
if (dist > 0) {
- OBSVAL(seg->x1 - 1, i, layer) |= DRC_BLOCKAGE;
+ set_drc_blockage(seg->x1 - 1, i, layer);
}
}
}
}
if (i == seg->y2) break;
}
+
+ /* Check end of route for horizontal routes */
+
+ if (seg->x1 != seg->x2) {
+ dir = OBSVAL(seg->x2, seg->y2, seg->layer) & (BLOCKED_MASK | PINOBSTRUCTMASK);
+ OBSVAL(seg->x2, seg->y2, seg->layer) = netnum | dir;
+ if (needblock[seg->layer] & ROUTEBLOCKX) {
+ if (seg->x2 < (NumChannelsX - 1))
+ set_drc_blockage(seg->x2 + 1, seg->y2, seg->layer);
+ if (seg->x2 > 0)
+ set_drc_blockage(seg->x2 - 1, seg->y2, seg->layer);
+ }
+ }
}
/*--------------------------------------------------------------*/
@@ -1735,16 +1800,53 @@ route_set_connections(net, route)
u_char found, match;
int x, y;
+ /* Reset start/end node flags */
+ route->flags &= ~(RT_START_NODE | RT_END_NODE);
+
/* 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) {
+ if ((lnode != NULL) && (lnode->nodesav != NULL)) {
+ route->start.node = lnode->nodesav;
+ route->flags |= RT_START_NODE;
+ found = TRUE;
+ }
+ }
+
+ /* For routes that were just imported from DEF, check if the */
+ /* route overshot a pin terminal by rounding off a non-grid */
+ /* coordinate. */
+
+ if (!found && (route->flags & RT_CHECK) && (seg->layer < Pinlayers)) {
+ if (seg->x1 == seg->x2) {
+ x = seg->x1;
+ if (seg->y1 < seg->y2)
+ y = seg->y1 + 1;
+ else
+ y = seg->y1 - 1;
+ }
+ else {
+ y = seg->y1;
+ if (seg->x1 < seg->x2)
+ x = seg->x1 + 1;
+ else
+ x = seg->x1 - 1;
+ }
+ lnode = NODEIPTR(x, y, seg->layer);
+ if ((lnode != NULL) && (lnode->nodesav != NULL) &&
+ (lnode->nodesav->netnum == net->netnum) &&
+ ((x != seg->x2) || (y != seg->y2))) {
route->start.node = lnode->nodesav;
route->flags |= RT_START_NODE;
found = TRUE;
+ /* Diagnostic */
+ Fprintf(stderr, "Coordinate %d %d corrected to %d %d\n",
+ seg->x1, seg->y1, x, y);
+ seg->x1 = x;
+ seg->y1 = y;
}
}
@@ -1785,7 +1887,8 @@ route_set_connections(net, route)
}
if (!found) {
- Fprintf(stderr, "Error: Failure to find route start node/route!\n");
+ Fprintf(stderr, "Error: Failure to find route start node/route on net %s!\n",
+ net->netname);
}
/* Does last route segment connect to a node? */
@@ -1799,12 +1902,46 @@ route_set_connections(net, route)
for (; seg->next; seg = seg->next);
if (seg->layer < Pinlayers) {
lnode = NODEIPTR(seg->x2, seg->y2, seg->layer);
- if (lnode != NULL) {
+ if ((lnode != NULL) && (lnode->nodesav != NULL)) {
route->end.node = lnode->nodesav;
route->flags |= RT_END_NODE;
found = TRUE;
}
}
+
+ /* For routes that were just imported from DEF, check if */
+ /* the route overshot a pin terminal by rounding off a */
+ /* non-grid coordinate. */
+
+ if (!found && (route->flags & RT_CHECK) && (seg->layer < Pinlayers)) {
+ if (seg->x1 == seg->x2) {
+ x = seg->x2;
+ if (seg->y1 < seg->y2)
+ y = seg->y2 - 1;
+ else
+ y = seg->y2 + 1;
+ }
+ else {
+ y = seg->y2;
+ if (seg->x1 < seg->x2)
+ x = seg->x2 - 1;
+ else
+ x = seg->x2 + 1;
+ }
+ lnode = NODEIPTR(x, y, seg->layer);
+ if ((lnode != NULL) && (lnode->nodesav != NULL) &&
+ (lnode->nodesav->netnum == net->netnum) &&
+ ((x != seg->x1) || (y != seg->y1))) {
+ route->start.node = lnode->nodesav;
+ route->flags |= RT_END_NODE;
+ found = TRUE;
+ /* Diagnostic */
+ Fprintf(stderr, "Coordinate %d %d corrected to %d %d\n",
+ seg->x2, seg->y2, x, y);
+ seg->x2 = x;
+ seg->y2 = y;
+ }
+ }
}
/* Does last route segment connect to a route? */
@@ -1844,8 +1981,12 @@ route_set_connections(net, route)
}
if (!found) {
- Fprintf(stderr, "Error: Failure to find route end node/route!\n");
+ Fprintf(stderr, "Error: Failure to find route end node/route on net %s!\n",
+ net->netname);
}
+
+ /* Clear RT_CHECK flag after processing */
+ if (route->flags & RT_CHECK) route->flags &= ~RT_CHECK;
}
/*--------------------------------------------------------------*/
@@ -1957,6 +2098,8 @@ int commit_proute(ROUTE rt, GRIDP *ept, u_char stage)
lrppre = lrprev->next;
if (lrppre == NULL) break;
stackheight = 0;
+ /* Advance lrcur if jogs were inserted */
+ while (lrprev != lrcur->next) lrcur = lrcur->next;
a = lrcur;
b = lrprev;
while (a->layer != b->layer) {
@@ -1980,7 +2123,7 @@ int commit_proute(ROUTE rt, GRIDP *ept, u_char stage)
// lowest cost, and make sure the position below that
// is available.
- if (cx < NumChannelsX[cl] - 1) {
+ if (cx < NumChannelsX - 1) {
dx = cx + 1; // Check to the right
pri = &OBS2VAL(dx, cy, cl);
pflags = pri->flags;
@@ -2049,7 +2192,7 @@ int commit_proute(ROUTE rt, GRIDP *ept, u_char stage)
}
}
- if (cy < NumChannelsY[cl] - 1) {
+ if (cy < NumChannelsY - 1) {
dy = cy + 1; // Check north
pri = &OBS2VAL(cx, dy, cl);
pflags = pri->flags;
@@ -2171,7 +2314,7 @@ int commit_proute(ROUTE rt, GRIDP *ept, u_char stage)
mincost = MAXRT;
dl = lrprev->layer;
- if (cx < NumChannelsX[cl] - 1) {
+ if (cx < NumChannelsX - 1) {
dx = cx + 1; // Check to the right
pri = &OBS2VAL(dx, cy, cl);
pflags = pri->flags;
@@ -2217,7 +2360,7 @@ int commit_proute(ROUTE rt, GRIDP *ept, u_char stage)
}
}
- if (cy < NumChannelsY[cl] - 1) {
+ if (cy < NumChannelsY - 1) {
dy = cy + 1; // Check north
pri = &OBS2VAL(cx, dy, cl);
pflags = pri->flags;
@@ -2349,6 +2492,224 @@ int commit_proute(ROUTE rt, GRIDP *ept, u_char stage)
}
}
}
+
+ /* Handle minimum metal area rule for stacked contacts */
+
+ else if (StackedContacts > 0) {
+
+ /* Search for all stacked contacts. For each via position inside */
+ /* a stack, excluding top and bottom, determine if a minimum */
+ /* metal area is violated. If so, then find an unused */
+ /* neighboring grid and extend to that side. If no unused */
+ /* neighboring grids exist, then fail. */
+
+ POINT lrppre;
+ PROUTE *pri, *pri2;
+ int violations = 1, checks;
+ int i, cx, cy, cl, o, orient;
+ int mincost, minx = -1, miny = -1, collide, cost;
+ double min_area[MAX_LAYERS];
+ u_char need_check[MAX_LAYERS];
+
+ /* Register the minimum metal area rule for each via base layer */
+
+ checks = 0;
+ for (i = 0; i < Num_layers; i++) {
+ min_area[i] = LefGetRouteMinArea(i);
+ if (i == Num_layers - 1) {
+ if (min_area[i] <= LefGetViaWidth(i - 1, i, 0) * LefGetViaWidth(i - 1, i, 1))
+ need_check[i] = (u_char)0;
+ else {
+ need_check[i] = (u_char)1;
+ checks++;
+ }
+ }
+ else {
+ if (min_area[i] <= LefGetViaWidth(i, i, 0) * LefGetViaWidth(i, i, 1))
+ need_check[i] = (u_char)0;
+ else {
+ need_check[i] = (u_char)1;
+ checks++;
+ }
+ }
+ }
+
+ if (checks == 0) violations = 0; // No minimum area violations possible.
+
+ while (violations != 0) { // Keep doing until all min. area violations are gone
+ violations = 0;
+ lrcur = lrend;
+ lrprev = lrend->next;
+
+ while (lrprev != NULL) {
+ lrppre = lrprev->next;
+ if (lrppre == NULL) break;
+ collide = FALSE;
+ while ((lrcur->layer != lrprev->layer) && (lrprev->layer != lrppre->layer)
+ && (need_check[lrprev->layer] == (u_char)1)) {
+ // Isolated via inside stack found
+
+ violations++;
+ cx = lrprev->x1;
+ cy = lrprev->y1;
+ cl = lrprev->layer;
+ mincost = MAXRT;
+
+ // Check all four positions around the contact for a
+ // free position to occupy. Positions in the preferred
+ // direction of the route layer take precedence.
+
+ o = LefGetRouteOrientation(cl);
+ for (orient = 0; orient < 2; orient++) {
+ if (o == orient) {
+ if (cy < NumChannelsY - 1) {
+ dy = cy + 1; // Check north
+ pri = &OBS2VAL(cx, dy, cl);
+ pflags = pri->flags;
+ cost = pri->prdata.cost;
+ if (collide && !(pflags & (PR_COST | PR_SOURCE)) &&
+ (pri->prdata.net < MAXNETNUM)) {
+ pflags = 0;
+ cost = ConflictCost;
+ }
+ if (pflags & PR_COST) {
+ pflags &= ~PR_COST;
+ if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE &&
+ cost < mincost) {
+ mincost = cost;
+ minx = cx;
+ miny = dy;
+ }
+ }
+ }
+
+ if (cy > 0) {
+ dy = cy - 1; // Check south
+ pri = &OBS2VAL(cx, dy, cl);
+ pflags = pri->flags;
+ cost = pri->prdata.cost;
+ if (collide && !(pflags & (PR_COST | PR_SOURCE)) &&
+ (pri->prdata.net < MAXNETNUM)) {
+ pflags = 0;
+ cost = ConflictCost;
+ }
+ if (pflags & PR_COST) {
+ pflags &= ~PR_COST;
+ if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE &&
+ cost < mincost) {
+ mincost = cost;
+ minx = cx;
+ miny = dy;
+ }
+ }
+ }
+ }
+ else {
+ if (cx < NumChannelsX - 1) {
+ dx = cx + 1; // Check to the right
+ pri = &OBS2VAL(dx, cy, cl);
+ pflags = pri->flags;
+ cost = pri->prdata.cost;
+ if (collide && !(pflags & (PR_COST | PR_SOURCE)) &&
+ (pri->prdata.net < MAXNETNUM)) {
+ pflags = 0;
+ cost = ConflictCost;
+ }
+ if (pflags & PR_COST) {
+ pflags &= ~PR_COST;
+ if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE &&
+ cost < mincost) {
+ mincost = cost;
+ minx = dx;
+ miny = cy;
+ }
+ }
+ }
+
+ if (cx > 0) {
+ dx = cx - 1; // Check to the left
+ pri = &OBS2VAL(dx, cy, cl);
+ pflags = pri->flags;
+ cost = pri->prdata.cost;
+ if (collide && !(pflags & (PR_COST | PR_SOURCE)) &&
+ (pri->prdata.net < MAXNETNUM)) {
+ pflags = 0;
+ cost = ConflictCost;
+ }
+ if (pflags & PR_COST) {
+ pflags &= ~PR_COST;
+ if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE &&
+ cost < mincost) {
+ mincost = cost;
+ minx = dx;
+ miny = cy;
+ }
+ }
+ }
+ }
+ }
+
+ // Was there an available position? If so, modify
+ // records to route to and from this position.
+
+ if (mincost < MAXRT) {
+
+ newlr = (POINT)malloc(sizeof(struct point_));
+ newlr->x1 = minx;
+ newlr->y1 = miny;
+ newlr->layer = cl;
+
+ newlr2 = (POINT)malloc(sizeof(struct point_));
+ newlr2->x1 = cx;
+ newlr2->y1 = cy;
+ newlr2->layer = cl;
+
+ lrprev->next = newlr;
+ newlr->next = newlr2;
+ newlr2->next = lrppre;
+
+ break; /* Found a solution; done. */
+ }
+
+ else if (stage == 0) {
+ // On the first stage, we call it an error and move
+ // on to the next net. This is a bit conservative,
+ // but it happens rarely.
+
+ if (Verbose > 0)
+ Fprintf(stderr, "Failed to reserve sufficient area "
+ "at grid point %d %d.\n",
+ lrcur->x1, lrcur->y1);
+ violations = 0;
+ rval = 0;
+ goto cleanup;
+ }
+ else {
+ if (collide == TRUE) {
+ Fprintf(stderr, "Failed to reserve sufficient area "
+ "at grid point %d %d; position may "
+ "not be routable.\n",
+ lrcur->x1, lrcur->y1);
+ violations = 0;
+ rval = 0;
+ goto cleanup;
+ }
+
+ // On the second stage, we will run through the
+ // search again, but allow overwriting other
+ // nets, which will be treated like other colliding
+ // nets in the regular route path search.
+
+ collide = TRUE;
+ }
+ }
+ lrcur = lrprev;
+ lrprev = lrppre;
+ }
+ }
+ }
+
+ /* Done handling stacked contacts */
lrend = lrtop;
lrcur = lrtop;
@@ -2575,7 +2936,10 @@ int writeback_route(ROUTE rt)
lay2 = (seg->segtype & ST_VIA) ? seg->layer + 1 : seg->layer;
dir1 = OBSVAL(seg->x1, seg->y1, seg->layer) & PINOBSTRUCTMASK;
- dir2 = OBSVAL(seg->x2, seg->y2, lay2) & PINOBSTRUCTMASK;
+ if (lay2 < Num_layers)
+ dir2 = OBSVAL(seg->x2, seg->y2, lay2) & PINOBSTRUCTMASK;
+ else
+ dir2 = 0;
writeback_segment(seg, netnum);
diff --git a/node.c b/node.c
index 5b13dc1..7de614d 100644
--- a/node.c
+++ b/node.c
@@ -27,13 +27,35 @@
/*--------------------------------------------------------------*/
NODEINFO
-SetNodeinfo(int gridx, int gridy, int layer)
+SetNodeinfo(int gridx, int gridy, int layer, NODE node)
{
+ DPOINT dp;
NODEINFO *lnodeptr;
lnodeptr = &NODEIPTR(gridx, gridy, layer);
if (*lnodeptr == NULL) {
*lnodeptr = (NODEINFO)calloc(1, sizeof(struct nodeinfo_));
+
+ /* Make sure this position is in the list of node's taps. Add */
+ /* it if it is not there. */
+
+ for (dp = (DPOINT)node->taps; dp; dp = dp->next)
+ if (dp->gridx == gridx && dp->gridy == gridy && dp->layer == layer)
+ break;
+ if (dp == NULL)
+ for (dp = (DPOINT)node->extend; dp; dp = dp->next)
+ if (dp->gridx == gridx && dp->gridy == gridy && dp->layer == layer)
+ break;
+ if (dp == NULL) {
+ dp = (DPOINT)malloc(sizeof(struct dpoint_));
+ dp->gridx = gridx;
+ dp->gridy = gridy;
+ dp->layer = layer;
+ dp->x = (gridx * PitchX) + Xlowerbound;
+ dp->y = (gridy * PitchY) + Ylowerbound;
+ dp->next = node->extend;
+ node->extend = dp;
+ }
}
return *lnodeptr;
}
@@ -87,7 +109,7 @@ count_reachable_taps()
double dx, dy;
for (l = 0; l < Num_layers; l++) {
- for (j = 0; j < NumChannelsX[l] * NumChannelsY[l]; j++) {
+ for (j = 0; j < NumChannelsX * NumChannelsY; j++) {
if (Nodeinfo[l][j]) {
node = Nodeinfo[l][j]->nodeloc;
if (node != NULL) {
@@ -111,23 +133,23 @@ count_reachable_taps()
if (node->numtaps == 0) {
/* Will try more than one via if available */
- for (orient = 0; orient < 2; orient++) {
+ for (orient = 0; orient < 4; orient += 2) {
for (ds = g->taps[i]; ds; ds = ds->next) {
deltax = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 0, orient);
deltay = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 1, orient);
- gridx = (int)((ds->x1 - Xlowerbound) / PitchX[ds->layer]) - 1;
+ gridx = (int)((ds->x1 - Xlowerbound) / PitchX) - 1;
while (1) {
- dx = (gridx * PitchX[ds->layer]) + Xlowerbound;
- if (dx > ds->x2 || gridx >= NumChannelsX[ds->layer]) break;
+ dx = (gridx * PitchX) + Xlowerbound;
+ if (dx > ds->x2 || gridx >= NumChannelsX) break;
if (((dx - ds->x1 + EPS) > deltax) &&
((ds->x2 - dx + EPS) > deltax)) {
gridy = (int)((ds->y1 - Ylowerbound)
- / PitchY[ds->layer]) - 1;
+ / PitchY) - 1;
while (1) {
- dy = (gridy * PitchY[ds->layer]) + Ylowerbound;
- if (dy > ds->y2 || gridy >= NumChannelsY[ds->layer])
+ dy = (gridy * PitchY) + Ylowerbound;
+ if (dy > ds->y2 || gridy >= NumChannelsY)
break;
if (((dy - ds->y1 + EPS) > deltay) &&
@@ -139,13 +161,13 @@ count_reachable_taps()
// Grid position is clear for placing a via
- if (orient == 0)
- Fprintf(stderr, "Tap position (%g, %g)"
+ if ((orient == 0) && (Verbose > 1))
+ Fprintf(stdout, "Tap position (%g, %g)"
" appears to be technically routable"
" so it is being forced routable.\n",
dx, dy);
- else
- Fprintf(stderr, "Tap position (%g, %g)"
+ else if (Verbose > 1)
+ Fprintf(stdout, "Tap position (%g, %g)"
" appears to be technically routable"
" with alternate via, so it is being"
" forced routable.\n", dx, dy);
@@ -154,13 +176,15 @@ count_reachable_taps()
(OBSVAL(gridx, gridy, ds->layer)
& BLOCKED_MASK)
| (u_int)node->netnum;
- lnode = SetNodeinfo(gridx, gridy, ds->layer);
+ lnode = SetNodeinfo(gridx, gridy, ds->layer,
+ node);
lnode->nodeloc = node;
lnode->nodesav = node;
- /* If we got to orient = 1, mark NI_NO_VIAX */
- if (orient == 1) lnode->flags |= NI_NO_VIAX;
-
+ /* If we got to orient = 2, mark NI_NO_VIAX */
+ if (orient == 2) lnode->flags |= NI_NO_VIAX;
+ /* This is a bit harsh, but should work */
+ else lnode->flags |= NI_NO_VIAY;
node->numtaps++;
}
}
@@ -183,30 +207,29 @@ count_reachable_taps()
int dir, mask, tapx, tapy, tapl;
/* Will try more than one via if available */
- for (orient = 0; orient < 2; orient++) {
+ for (orient = 0; orient < 4; orient += 2) {
/* Initialize mindist to a large value */
mask = 0;
- mindist = PitchX[Num_layers - 1] + PitchY[Num_layers - 1];
+ mindist = PitchX + PitchY;
dir = 0; /* Indicates no solution found */
for (ds = g->taps[i]; ds; ds = ds->next) {
deltax = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 0, orient);
deltay = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 1, orient);
- gridx = (int)((ds->x1 - Xlowerbound) / PitchX[ds->layer]) - 1;
+ gridx = (int)((ds->x1 - Xlowerbound) / PitchX) - 1;
while (1) {
- dx = (gridx * PitchX[ds->layer]) + Xlowerbound;
- if (dx > ds->x2 || gridx >= NumChannelsX[ds->layer]) break;
+ dx = (gridx * PitchX) + Xlowerbound;
+ if (dx > ds->x2 || gridx >= NumChannelsX) break;
if (((dx - ds->x1 + EPS) > -deltax) &&
((ds->x2 - dx + EPS) > -deltax)) {
- gridy = (int)((ds->y1 - Ylowerbound)
- / PitchY[ds->layer]) - 1;
+ gridy = (int)((ds->y1 - Ylowerbound) / PitchY) - 1;
while (1) {
- dy = (gridy * PitchY[ds->layer]) + Ylowerbound;
- if (dy > ds->y2 || gridy >= NumChannelsY[ds->layer])
+ dy = (gridy * PitchY) + Ylowerbound;
+ if (dy > ds->y2 || gridy >= NumChannelsY)
break;
// Check that the grid position is inside the
@@ -307,22 +330,23 @@ count_reachable_taps()
if (mask != 0) {
// Grid position is clear for placing a via
- Fprintf(stderr, "Tap position (%d, %d) appears to be"
- " technically routable with an offset, so"
- " it is being forced routable.\n",
- tapx, tapy);
+ if (Verbose > 1)
+ Fprintf(stdout, "Tap position (%d, %d) appears to be"
+ " technically routable with an offset, so"
+ " it is being forced routable.\n",
+ tapx, tapy);
OBSVAL(tapx, tapy, tapl) =
(OBSVAL(tapx, tapy, tapl) & BLOCKED_MASK)
| mask | (u_int)node->netnum;
- lnode = SetNodeinfo(tapx, tapy, tapl);
+ lnode = SetNodeinfo(tapx, tapy, tapl, node);
lnode->nodeloc = node;
lnode->nodesav = node;
lnode->stub = dist;
lnode->flags |= dir;
- /* If we got to orient = 1 then mark NI_NO_VIAX */
- if (orient == 1) lnode->flags |= NI_NO_VIAX;
+ /* If we got to orient = 2 then mark NI_NO_VIAX */
+ if (orient == 2) lnode->flags |= NI_NO_VIAX;
node->numtaps++;
}
@@ -367,22 +391,27 @@ count_reachable_taps()
void check_variable_pitch(int l, int *hptr, int *vptr)
{
int o, hnum, vnum;
- double vpitch, hpitch, wvia;
+ double vpitch, hpitch, wvia, wviax, wviay;
o = LefGetRouteOrientation(l);
- // Pick the best via size for the layer. Usually this means the
- // via whose base is at layer - 1, because the top metal layer
- // will either have the same width or a larger width.
-
- // Note that when "horizontal" (o = 1) is passed to LefGetViaWidth,
+ // Note that when "horizontal" (o = 1) is passed to LefGetXYViaWidth,
// it returns the via width top-to-bottom (orient meaning is
- // reversed for LefGetViaWidth), which is what we want. . .
+ // reversed for LefGetXYViaWidth), which is what we want. . .
- if (l == 0)
- wvia = LefGetViaWidth(l, l, o);
- else
- wvia = LefGetViaWidth(l - 1, l, o);
+ // Try both via orientations and choose the best, assuming that it is
+ // a lot easier to rotate and shift vias around than it is to lose
+ // half the routing grid.
+
+ if (l == 0) {
+ wviax = LefGetXYViaWidth(l, l, o, 0);
+ wviay = LefGetXYViaWidth(l, l, o, 3);
+ }
+ else {
+ wviax = LefGetXYViaWidth(l - 1, l, o, 0);
+ wviay = LefGetXYViaWidth(l - 1, l, o, 3);
+ }
+ wvia = (wviax < wviay) ? wviax : wviay;
if (o == 1) { // Horizontal route
vpitch = LefGetRoutePitch(l);
@@ -399,12 +428,12 @@ void check_variable_pitch(int l, int *hptr, int *vptr)
}
vnum = 1;
- while (vpitch > PitchY[l] + EPS) {
+ while (vpitch > PitchY + EPS) {
vpitch /= 2.0;
vnum++;
}
hnum = 1;
- while (hpitch > PitchX[l] + EPS) {
+ while (hpitch > PitchX + EPS) {
hpitch /= 2.0;
hnum++;
}
@@ -448,9 +477,9 @@ void create_obstructions_from_variable_pitch(void)
if (hnum > 1 && vnum == 1) vnum++;
if (vnum > 1 || hnum > 1) {
- for (x = 0; x < NumChannelsX[l]; x++) {
+ for (x = 0; x < NumChannelsX; x++) {
if (x % hnum == 0) continue;
- for (y = 0; y < NumChannelsY[l]; y++) {
+ for (y = 0; y < NumChannelsY; y++) {
if (y % vnum == 0) continue;
// If the grid position itself is a node, don't restrict
@@ -467,11 +496,11 @@ void create_obstructions_from_variable_pitch(void)
else if ((y > 0) && ((lnode = NODEIPTR(x , y - 1, l)) != NULL) &&
(lnode->nodeloc != NULL))
OBSVAL(x, y, l) = BLOCKED_MASK & ~BLOCKED_S;
- else if ((x < NumChannelsX[l] - 1)
+ else if ((x < NumChannelsX - 1)
&& ((lnode = NODEIPTR(x + 1, y, l)) != NULL) &&
(lnode->nodeloc != NULL))
OBSVAL(x, y, l) = BLOCKED_MASK & ~BLOCKED_E;
- else if ((y < NumChannelsY[l] - 1)
+ else if ((y < NumChannelsY - 1)
&& ((lnode = NODEIPTR(x, y + 1, l)) != NULL) &&
(lnode->nodeloc != NULL))
OBSVAL(x, y, l) = BLOCKED_MASK & ~BLOCKED_N;
@@ -493,7 +522,7 @@ void create_obstructions_from_variable_pitch(void)
static void
disable_gridpos(int x, int y, int lay)
{
- int apos = OGRID(x, y, lay);
+ int apos = OGRID(x, y);
Obs[lay][apos] = (u_int)(NO_NET | OBSTRUCT_MASK);
if (Nodeinfo[lay][apos]) {
@@ -517,7 +546,7 @@ count_pinlayers(void)
Pinlayers = 0;
for (l = 0; l < Num_layers; l++) {
- for (j = 0; j < NumChannelsX[l] * NumChannelsY[l]; j++) {
+ for (j = 0; j < NumChannelsX * NumChannelsY; j++) {
if (Nodeinfo[l][j]) {
Pinlayers = l + 1;
break;
@@ -542,15 +571,13 @@ count_pinlayers(void)
/*--------------------------------------------------------------*/
static void
-check_obstruct(int gridx, int gridy, DSEG ds, double dx, double dy)
+check_obstruct(int gridx, int gridy, DSEG ds, double dx, double dy, double delta)
{
u_int *obsptr;
float dist;
- NODEINFO lnode;
obsptr = &(OBSVAL(gridx, gridy, ds->layer));
dist = OBSINFO(gridx, gridy, ds->layer);
- lnode = NODEIPTR(gridx, gridy, ds->layer);
// Grid point is inside obstruction + halo.
*obsptr |= NO_NET;
@@ -560,7 +587,6 @@ check_obstruct(int gridx, int gridy, DSEG ds, double dx, double dy)
*obsptr |= OBSTRUCT_MASK;
else {
-
// Make more detailed checks in each direction
if (dy <= ds->y1) {
@@ -579,6 +605,7 @@ check_obstruct(int gridx, int gridy, DSEG ds, double dx, double dy)
}
else *obsptr |= OBSTRUCT_MASK;
}
+
if (dx <= ds->x1) {
if ((*obsptr & (OBSTRUCT_MASK & ~OBSTRUCT_E)) == 0) {
if ((dist == 0) || ((ds->x1 - dx) < dist))
@@ -595,7 +622,7 @@ check_obstruct(int gridx, int gridy, DSEG ds, double dx, double dy)
}
else *obsptr |= OBSTRUCT_MASK;
}
- }
+ }
}
/*--------------------------------------------------------------*/
@@ -604,14 +631,17 @@ check_obstruct(int gridx, int gridy, DSEG ds, double dx, double dy)
/* whether the obstruction is wide or narrow metal, if the */
/* spacing rules are graded according to metal width, and if a */
/* via placed at the position is or is not symmetric in X and Y */
+/* "orient" is the via orientation, of which there are four; */
+/* however, as this only concerns the via bottom layer, the */
+/* two orientations are represented by orient = 0 and 2. */
/*--------------------------------------------------------------*/
-static double get_via_clear(int lay, int horiz, DSEG rect) {
+static double get_via_clear(int lay, int horiz, int orient, DSEG rect) {
double vdelta, v2delta, mdelta, mwidth;
- vdelta = LefGetViaWidth(lay, lay, 1 - horiz);
+ vdelta = LefGetXYViaWidth(lay, lay, 1 - horiz, orient);
if (lay > 0) {
- v2delta = LefGetViaWidth(lay - 1, lay, 1 - horiz);
+ v2delta = LefGetXYViaWidth(lay - 1, lay, 1 - horiz, orient);
if (v2delta > vdelta) vdelta = v2delta;
}
vdelta = vdelta / 2.0;
@@ -670,8 +700,8 @@ void clip_gate_taps(void)
lay = dp->layer;
if (dp->gridx < 0 || dp->gridy < 0 ||
- dp->gridx >= NumChannelsX[lay] ||
- dp->gridy >= NumChannelsY[lay]) {
+ dp->gridx >= NumChannelsX ||
+ dp->gridy >= NumChannelsY) {
Fprintf(stderr, "Tap of port of node %d of net %s"
" is outside of route area\n",
node->nodenum, node->netname);
@@ -710,7 +740,7 @@ void create_obstructions_from_gates(void)
{
GATE g;
DSEG ds;
- int i, gridx, gridy;
+ int i, gridx, gridy, orient;
double deltax, deltay, delta[MAX_LAYERS];
double dx, dy, deltaxy;
@@ -725,23 +755,34 @@ void create_obstructions_from_gates(void)
// that the position is not routable under any condition.
for (g = Nlgates; g; g = g->next) {
- for (ds = g->obs; ds; ds = ds->next) {
+ orient = 0;
+ for (ds = g->obs;; ds = ds->next) {
+ // Run through ds list twice, checking against horizontally and
+ // vertically oriented vias.
+
+ if (ds == NULL) {
+ if (orient == 2)
+ break;
+ else {
+ orient = 2;
+ ds = g->obs;
+ if (ds == NULL) break;
+ }
+ }
- deltax = get_via_clear(ds->layer, 1, ds);
- gridx = (int)((ds->x1 - Xlowerbound - deltax)
- / PitchX[ds->layer]) - 1;
+ deltax = get_via_clear(ds->layer, 1, orient, ds);
+ gridx = (int)((ds->x1 - Xlowerbound - deltax) / PitchX) - 1;
while (1) {
- dx = (gridx * PitchX[ds->layer]) + Xlowerbound;
+ dx = (gridx * PitchX) + Xlowerbound;
if ((dx + EPS) > (ds->x2 + deltax)
- || gridx >= NumChannelsX[ds->layer]) break;
+ || gridx >= NumChannelsX) break;
else if ((dx - EPS) > (ds->x1 - deltax) && gridx >= 0) {
- deltay = get_via_clear(ds->layer, 0, ds);
- gridy = (int)((ds->y1 - Ylowerbound - deltay)
- / PitchY[ds->layer]) - 1;
+ deltay = get_via_clear(ds->layer, 0, orient, ds);
+ gridy = (int)((ds->y1 - Ylowerbound - deltay) / PitchY) - 1;
while (1) {
- dy = (gridy * PitchY[ds->layer]) + Ylowerbound;
+ dy = (gridy * PitchY) + Ylowerbound;
if ((dy + EPS) > (ds->y2 + deltay)
- || gridy >= NumChannelsY[ds->layer]) break;
+ || gridy >= NumChannelsY) break;
if ((dy - EPS) > (ds->y1 - deltay) && gridy >= 0) {
double s, edist, xp, yp;
@@ -767,27 +808,10 @@ void create_obstructions_from_gates(void)
}
else edist = 0;
- if ((edist + EPS) < (s * s)) {
-
- // If it clears distance for a route layer but not
- // vias, then block vias only.
- /* (This is restrictive and unnecessary) */
- /*
- deltaxy = get_route_clear(ds->layer, ds);
- if (((dx - EPS) <= (ds->x1 - deltaxy)) ||
- ((dx + EPS) >= (ds->x2 + deltaxy)) ||
- ((dy - EPS) <= (ds->y1 - deltaxy)) ||
- ((dy + EPS) >= (ds->y2 + deltaxy))) {
- block_route(gridx, gridy, ds->layer, UP);
- block_route(gridx, gridy, ds->layer, DOWN);
- }
- else
- */
- check_obstruct(gridx, gridy, ds, dx, dy);
- }
- else {
+ if ((edist + EPS) < (s * s))
+ check_obstruct(gridx, gridy, ds, dx, dy, s);
+ else
edist = 0; // diagnostic break
- }
}
gridy++;
}
@@ -813,21 +837,19 @@ void create_obstructions_from_gates(void)
}
for (ds = g->taps[i]; ds; ds = ds->next) {
- deltax = get_via_clear(ds->layer, 1, ds);
- gridx = (int)((ds->x1 - Xlowerbound - deltax)
- / PitchX[ds->layer]) - 1;
+ deltax = get_via_clear(ds->layer, 1, orient, ds);
+ gridx = (int)((ds->x1 - Xlowerbound - deltax) / PitchX) - 1;
while (1) {
- dx = (gridx * PitchX[ds->layer]) + Xlowerbound;
+ dx = (gridx * PitchX) + Xlowerbound;
if (dx > (ds->x2 + deltax)
- || gridx >= NumChannelsX[ds->layer]) break;
+ || gridx >= NumChannelsX) break;
else if (dx >= (ds->x1 - deltax) && gridx >= 0) {
- deltay = get_via_clear(ds->layer, 0, ds);
- gridy = (int)((ds->y1 - Ylowerbound - deltay)
- / PitchY[ds->layer]) - 1;
+ deltay = get_via_clear(ds->layer, 0, orient, ds);
+ gridy = (int)((ds->y1 - Ylowerbound - deltay) / PitchY) - 1;
while (1) {
- dy = (gridy * PitchY[ds->layer]) + Ylowerbound;
+ dy = (gridy * PitchY) + Ylowerbound;
if ((dy + EPS) > (ds->y2 + deltay)
- || gridy >= NumChannelsY[ds->layer]) break;
+ || gridy >= NumChannelsY) break;
if ((dy - EPS) >= (ds->y1 - deltay) && gridy >= 0) {
double s, edist = 0.0, xp, yp;
@@ -854,24 +876,8 @@ void create_obstructions_from_gates(void)
}
else edist = 0;
- if ((edist + EPS) < (s * s)) {
-
- // If it clears distance for a route layer but not
- // vias, then block vias only.
- /* (This is restrictive and unnecessary) */
- /*
- deltaxy = get_route_clear(ds->layer, ds);
- if (((dx - EPS) < (ds->x1 - deltaxy)) ||
- ((dx + EPS) > (ds->x2 + deltaxy)) ||
- ((dy - EPS) < (ds->y1 - deltaxy)) ||
- ((dy + EPS) > (ds->y2 + deltaxy))) {
- block_route(gridx, gridy, ds->layer, UP);
- block_route(gridx, gridy, ds->layer, DOWN);
- }
- else
- */
- check_obstruct(gridx, gridy, ds, dx, dy);
- }
+ if ((edist + EPS) < (s * s))
+ check_obstruct(gridx, gridy, ds, dx, dy, s);
}
gridy++;
}
@@ -894,21 +900,20 @@ void create_obstructions_from_gates(void)
}
for (ds = UserObs; ds; ds = ds->next) {
- gridx = (int)((ds->x1 - Xlowerbound - delta[ds->layer])
- / PitchX[ds->layer]) - 1;
+ if (ds->layer >= Num_layers) continue;
+ gridx = (int)((ds->x1 - Xlowerbound - delta[ds->layer]) / PitchX) - 1;
while (1) {
- dx = (gridx * PitchX[ds->layer]) + Xlowerbound;
+ dx = (gridx * PitchX) + Xlowerbound;
if (dx > (ds->x2 + delta[ds->layer])
- || gridx >= NumChannelsX[ds->layer]) break;
+ || gridx >= NumChannelsX) break;
else if (dx >= (ds->x1 - delta[ds->layer]) && gridx >= 0) {
- gridy = (int)((ds->y1 - Ylowerbound - delta[ds->layer])
- / PitchY[ds->layer]) - 1;
+ gridy = (int)((ds->y1 - Ylowerbound - delta[ds->layer]) / PitchY) - 1;
while (1) {
- dy = (gridy * PitchY[ds->layer]) + Ylowerbound;
+ dy = (gridy * PitchY) + Ylowerbound;
if (dy > (ds->y2 + delta[ds->layer])
- || gridy >= NumChannelsY[ds->layer]) break;
+ || gridy >= NumChannelsY) break;
if (dy >= (ds->y1 - delta[ds->layer]) && gridy >= 0)
- check_obstruct(gridx, gridy, ds, dx, dy);
+ check_obstruct(gridx, gridy, ds, dx, dy, delta[i]);
gridy++;
}
@@ -1025,7 +1030,8 @@ void create_obstructions_inside_nodes(void)
DSEG ds;
u_int dir, mask, k;
int i, gridx, gridy;
- double dx, dy, xdist;
+ double dx, dy, xdist, vwx, vwy;
+ u_char o0okay, o2okay, duplicate;
float dist;
// For each node terminal (gate pin), mark each grid position with the
@@ -1048,32 +1054,34 @@ void create_obstructions_inside_nodes(void)
// First mark all areas inside node geometry boundary.
for (ds = g->taps[i]; ds; ds = ds->next) {
- gridx = (int)((ds->x1 - Xlowerbound) / PitchX[ds->layer]) - 1;
+ gridx = (int)((ds->x1 - Xlowerbound) / PitchX) - 1;
while (1) {
- dx = (gridx * PitchX[ds->layer]) + Xlowerbound;
- if (dx > ds->x2 || gridx >= NumChannelsX[ds->layer]) break;
+ dx = (gridx * PitchX) + Xlowerbound;
+ if (dx > ds->x2 || gridx >= NumChannelsX) break;
else if (dx >= ds->x1 && gridx >= 0) {
- gridy = (int)((ds->y1 - Ylowerbound) / PitchY[ds->layer]) - 1;
+ gridy = (int)((ds->y1 - Ylowerbound) / PitchY) - 1;
while (1) {
- dy = (gridy * PitchY[ds->layer]) + Ylowerbound;
- if (dy > ds->y2 || gridy >= NumChannelsY[ds->layer]) break;
+ dy = (gridy * PitchY) + Ylowerbound;
+ if (dy > ds->y2 || gridy >= NumChannelsY) break;
// Area inside defined pin geometry
if (dy > ds->y1 && gridy >= 0) {
int orignet = OBSVAL(gridx, gridy, ds->layer);
+ duplicate = FALSE;
+ lnode = NULL;
if ((orignet & ROUTED_NET_MASK & ~ROUTED_NET)
== (u_int)node->netnum) {
- // Duplicate tap point, or pre-existing
- // route. Don't re-process it if it is
- // a duplicate.
+ // Duplicate tap point, or pre-existing route.
+ // Re-process carefully. Check for alternate
+ // restrictions. This geometry may be better
+ // than the last one(s) processed.
+
if (((lnode = NODEIPTR(gridx, gridy, ds->layer)) != NULL)
- && (lnode->nodeloc != NULL)) {
- gridy++;
- continue;
- }
+ && (lnode->nodeloc != NULL))
+ duplicate = TRUE;
}
else if (!(orignet & NO_NET) &&
@@ -1176,14 +1184,48 @@ void create_obstructions_inside_nodes(void)
}
}
- OBSVAL(gridx, gridy, ds->layer)
+ if (!duplicate) {
+ OBSVAL(gridx, gridy, ds->layer)
= (OBSVAL(gridx, gridy, ds->layer)
& BLOCKED_MASK) | (u_int)node->netnum | mask;
- lnode = SetNodeinfo(gridx, gridy, ds->layer);
- lnode->nodeloc = node;
- lnode->nodesav = node;
- lnode->stub = dist;
- lnode->flags |= dir;
+ if (!lnode)
+ lnode = SetNodeinfo(gridx, gridy, ds->layer,
+ node);
+ lnode->nodeloc = node;
+ lnode->nodesav = node;
+ lnode->stub = dist;
+ lnode->flags |= dir;
+ }
+
+ /* If a horizontal or vertical via fits completely */
+ /* inside the pin but the other orientation */
+ /* doesn't, then mark as prohibiting the other */
+ /* orientation. */
+
+ vwx = LefGetXYViaWidth(ds->layer, ds->layer, 0, 0) / 2.0;
+ vwy = LefGetXYViaWidth(ds->layer, ds->layer, 1, 0) / 2.0;
+ if ((dx - vwx > ds->x1 - EPS) &&
+ (dx + vwx < ds->x2 + EPS) &&
+ (dy - vwy > ds->y1 - EPS) &&
+ (dy + vwy < ds->y2 + EPS)) {
+ o0okay = TRUE;
+ } else {
+ o0okay = FALSE;
+ }
+ vwx = LefGetXYViaWidth(ds->layer, ds->layer, 0, 2) / 2.0;
+ vwy = LefGetXYViaWidth(ds->layer, ds->layer, 1, 2) / 2.0;
+ if ((dx - vwx > ds->x1 - EPS) &&
+ (dx + vwx < ds->x2 + EPS) &&
+ (dy - vwy > ds->y1 - EPS) &&
+ (dy + vwy < ds->y2 + EPS)) {
+ o2okay = TRUE;
+ } else {
+ o2okay = FALSE;
+ }
+ if ((o0okay == TRUE) && (o2okay == FALSE))
+ lnode->flags |= NI_NO_VIAY;
+ else if ((o0okay == FALSE) && (o2okay == TRUE))
+ lnode->flags |= NI_NO_VIAX;
}
else if ((orignet & NO_NET) && ((orignet & OBSTRUCT_MASK)
!= OBSTRUCT_MASK)) {
@@ -1192,7 +1234,7 @@ void create_obstructions_inside_nodes(void)
// Check that we have not created a PINOBSTRUCT
// route directly over this point.
- if (ds->layer < Num_layers - 1) {
+ if ((!duplicate) && (ds->layer < Num_layers - 1)) {
k = OBSVAL(gridx, gridy, ds->layer + 1);
if (k & PINOBSTRUCTMASK) {
if ((k & ROUTED_NET_MASK) != (u_int)node->netnum) {
@@ -1246,29 +1288,9 @@ void create_obstructions_outside_nodes(void)
GATE g;
DSEG ds;
u_int dir, mask, k;
- int i, gridx, gridy;
- double dx, dy, deltax, deltay, xdist;
+ int i, gridx, gridy, orient;
+ double dx, dy, xdist, deltax, deltay;
float dist;
- double offmaxx[MAX_LAYERS], offmaxy[MAX_LAYERS];
-
- // Use a more conservative definition of keepout, to include via
- // widths, which may be bigger than route widths.
-
- for (i = 0; i < Num_layers; i++) {
- offmaxx[i] = PitchX[i] - LefGetRouteSpacing(i)
- - 0.5 * (LefGetRouteWidth(i) + LefGetViaWidth(i, i, 0));
- offmaxy[i] = PitchY[i] - LefGetRouteSpacing(i)
- - 0.5 * (LefGetRouteWidth(i) + LefGetViaWidth(i, i, 1));
- }
-
- // When we place vias at an offset, they have to satisfy the spacing
- // requirements for the via's top layer, as well. So take the least
- // maximum offset of each layer and the layer above it.
-
- for (i = 0; i < Num_layers - 1; i++) {
- offmaxx[i] = MIN(offmaxx[i], offmaxx[i + 1]);
- offmaxy[i] = MIN(offmaxy[i], offmaxy[i + 1]);
- }
// For each node terminal (gate pin), mark each grid position with the
// net number. This overrides any obstruction that may be placed at that
@@ -1292,31 +1314,45 @@ void create_obstructions_outside_nodes(void)
// all inside areas because the tap rectangles often overlap,
// and one rectangle's halo may be inside another tap.
- for (ds = g->taps[i]; ds; ds = ds->next) {
+ orient = 0;
+ for (ds = g->taps[i];; ds = ds->next) {
+ if (ds == NULL) {
+ if (orient == 2)
+ break;
+ else {
+ orient = 2;
+ ds = g->taps[i];
+ if (ds == NULL) break;
+ }
+ }
// Note: Should be handling get_route_clear as a less
// restrictive case, as was done above.
- deltax = get_via_clear(ds->layer, 1, ds);
- gridx = (int)((ds->x1 - Xlowerbound - deltax)
- / PitchX[ds->layer]) - 1;
+ deltax = get_via_clear(ds->layer, 1, orient, ds);
+ gridx = (int)((ds->x1 - Xlowerbound - deltax) / PitchX) - 1;
while (1) {
- dx = (gridx * PitchX[ds->layer]) + Xlowerbound;
+ dx = (gridx * PitchX) + Xlowerbound;
+
+ // Check if obstruction position is too close for
+ // a via in either orientation. The position can
+ // be marked as prohibiting one orientation or the
+ // other.
- if ((dx + EPS) > (ds->x2 + deltax) ||
- gridx >= NumChannelsX[ds->layer])
+ if (((dx + EPS) > (ds->x2 + deltax)) ||
+ (gridx >= NumChannelsX))
break;
else if ((dx - EPS) > (ds->x1 - deltax) && gridx >= 0) {
- deltay = get_via_clear(ds->layer, 0, ds);
- gridy = (int)((ds->y1 - Ylowerbound - deltay)
- / PitchY[ds->layer]) - 1;
+ deltay = get_via_clear(ds->layer, 0, orient, ds);
+ gridy = (int)((ds->y1 - Ylowerbound - deltay) / PitchY) - 1;
while (1) {
- dy = (gridy * PitchY[ds->layer]) + Ylowerbound;
- if ((dy + EPS) > (ds->y2 + deltay) ||
- gridy >= NumChannelsY[ds->layer])
+ dy = (gridy * PitchY) + Ylowerbound;
+
+ if (((dy + EPS) > (ds->y2 + deltay)) ||
+ (gridy >= NumChannelsY))
break;
// 2nd pass on area inside defined pin geometry,
@@ -1341,11 +1377,20 @@ void create_obstructions_outside_nodes(void)
else if ((orignet & NO_NET) && ((orignet & OBSTRUCT_MASK)
!= OBSTRUCT_MASK)) {
- double sdistx = LefGetViaWidth(ds->layer, ds->layer, 0)
- / 2.0 + LefGetRouteSpacing(ds->layer);
- double sdisty = LefGetViaWidth(ds->layer, ds->layer, 1)
- / 2.0 + LefGetRouteSpacing(ds->layer);
- double offd;
+ double sdistxx, sdistxy, sdistyx, sdistyy, offd;
+
+ sdistxx = LefGetXYViaWidth(ds->layer, ds->layer,
+ 0, 0) / 2.0 +
+ LefGetRouteSpacing(ds->layer);
+ sdistxy = LefGetXYViaWidth(ds->layer, ds->layer,
+ 0, 2) / 2.0 +
+ LefGetRouteSpacing(ds->layer);
+ sdistyx = LefGetXYViaWidth(ds->layer, ds->layer,
+ 1, 0) / 2.0 +
+ LefGetRouteSpacing(ds->layer);
+ sdistyy = LefGetXYViaWidth(ds->layer, ds->layer,
+ 1, 2) / 2.0 +
+ LefGetRouteSpacing(ds->layer);
// Define a maximum offset we can have in X or
// Y above which the placement of a via will
@@ -1364,86 +1409,111 @@ void create_obstructions_outside_nodes(void)
// the obstruction to resolve the DRC error.
// Make sure we have marked this as a node.
- lnode = SetNodeinfo(gridx, gridy, ds->layer);
+ lnode = SetNodeinfo(gridx, gridy, ds->layer, node);
lnode->nodeloc = node;
lnode->nodesav = node;
OBSVAL(gridx, gridy, ds->layer)
= (OBSVAL(gridx, gridy, ds->layer)
& BLOCKED_MASK) | (u_int)node->netnum;
+ offd = OBSINFO(gridx, gridy, ds->layer);
if (orignet & OBSTRUCT_N) {
- offd = -(sdisty - OBSINFO(gridx, gridy, ds->layer));
- if (offd >= -offmaxy[ds->layer]) {
- OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP;
- lnode->offset = offd;
- lnode->flags |= NI_OFFSET_NS;
+ if (sdistyy - offd > EPS) {
+ lnode->flags |= NI_NO_VIAY;
+ if (sdistyx - offd > EPS) {
+ /* Cannot route cleanly, so use offset */
+ if (offd - sdistyx > PitchX / 2.0)
+ /* Offset distance is too large */
+ maxerr = 1;
+ else {
- /* If position above has obstruction, then */
- /* add up/down block to prevent vias. */
+ OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP;
+ lnode->offset = offd - sdistyx;
+ lnode->flags |= NI_OFFSET_NS;
- if ((ds->layer < Num_layers - 1) &&
- (gridy > 0) &&
- (OBSVAL(gridx, gridy - 1, ds->layer + 1)
- & OBSTRUCT_MASK))
- block_route(gridx, gridy, ds->layer, UP);
+ /* If position above has obstruction, then */
+ /* add up/down block to prevent vias. */
+
+ if ((ds->layer < Num_layers - 1) &&
+ (gridy > 0) &&
+ (OBSVAL(gridx, gridy - 1,
+ ds->layer + 1) & OBSTRUCT_MASK))
+ block_route(gridx, gridy, ds->layer, UP);
+ }
+ }
}
- else maxerr = 1;
}
else if (orignet & OBSTRUCT_S) {
- offd = sdisty - OBSINFO(gridx, gridy, ds->layer);
- if (offd <= offmaxy[ds->layer]) {
- OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP;
- lnode->offset = offd;
- lnode->flags |= NI_OFFSET_NS;
-
- /* If position above has obstruction, then */
- /* add up/down block to prevent vias. */
-
- if ((ds->layer < Num_layers - 1) &&
- (gridy < NumChannelsY[ds->layer + 1]
- - 1) &&
- (OBSVAL(gridx, gridy + 1, ds->layer + 1)
- & OBSTRUCT_MASK))
- block_route(gridx, gridy, ds->layer, UP);
+ if (sdistyy - offd > EPS) {
+ lnode->flags |= NI_NO_VIAY;
+ if (sdistyx - offd > EPS) {
+ if (offd - sdistyx > PitchX / 2.0)
+ /* Offset distance is too large */
+ maxerr = 1;
+ else {
+ OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP;
+ lnode->offset = sdistyx - offd;
+ lnode->flags |= NI_OFFSET_NS;
+
+ /* If position above has obstruction, then */
+ /* add up/down block to prevent vias. */
+
+ if ((ds->layer < Num_layers - 1) &&
+ (gridy < NumChannelsY - 1) &&
+ (OBSVAL(gridx, gridy + 1,
+ ds->layer + 1) & OBSTRUCT_MASK))
+ block_route(gridx, gridy, ds->layer, UP);
+ }
+ }
}
- else maxerr = 1;
}
else if (orignet & OBSTRUCT_E) {
- offd = -(sdistx - OBSINFO(gridx, gridy, ds->layer));
- if (offd >= -offmaxx[ds->layer]) {
- OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP;
- lnode->offset = offd;
- lnode->flags |= NI_OFFSET_EW;
+ if (sdistxx - offd > EPS) {
+ lnode->flags |= NI_NO_VIAX;
+ if (sdistxy - offd > EPS) {
+ if (offd - sdistxy > PitchY / 2.0)
+ /* Offset distance is too large */
+ maxerr = 1;
+ else {
+ OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP;
+ lnode->offset = offd - sdistxy;
+ lnode->flags |= NI_OFFSET_EW;
- /* If position above has obstruction, then */
- /* add up/down block to prevent vias. */
+ /* If position above has obstruction, then */
+ /* add up/down block to prevent vias. */
- if ((ds->layer < Num_layers - 1) &&
- (gridx > 0) &&
- (OBSVAL(gridx - 1, gridy, ds->layer + 1)
- & OBSTRUCT_MASK))
- block_route(gridx, gridy, ds->layer, UP);
+ if ((ds->layer < Num_layers - 1) &&
+ (gridx > 0) &&
+ (OBSVAL(gridx - 1, gridy,
+ ds->layer + 1) & OBSTRUCT_MASK))
+ block_route(gridx, gridy, ds->layer, UP);
+ }
+ }
}
- else maxerr = 1;
}
else if (orignet & OBSTRUCT_W) {
- offd = sdistx - OBSINFO(gridx, gridy, ds->layer);
- if (offd <= offmaxx[ds->layer]) {
- OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP;
- lnode->offset = offd;
- lnode->flags |= NI_OFFSET_EW;
-
- /* If position above has obstruction, then */
- /* add up/down block to prevent vias. */
-
- if ((ds->layer < Num_layers - 1) &&
- (gridx < NumChannelsX[ds->layer]
- - 1) &&
- (OBSVAL(gridx + 1, gridy, ds->layer + 1)
- & OBSTRUCT_MASK))
- block_route(gridx, gridy, ds->layer, UP);
+ if (sdistxx - offd > EPS) {
+ lnode->flags |= NI_NO_VIAX;
+ if (sdistxy - offd > EPS) {
+ if (offd - sdistxy > PitchY / 2.0)
+ /* Offset distance is too large */
+ maxerr = 1;
+ else {
+ OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP;
+ lnode->offset = sdistxy - offd;
+ lnode->flags |= NI_OFFSET_EW;
+
+ /* If position above has obstruction, then */
+ /* add up/down block to prevent vias. */
+
+ if ((ds->layer < Num_layers - 1) &&
+ (gridx < NumChannelsX - 1) &&
+ (OBSVAL(gridx + 1, gridy,
+ ds->layer + 1) & OBSTRUCT_MASK))
+ block_route(gridx, gridy, ds->layer, UP);
+ }
+ }
}
- else maxerr = 1;
}
if (maxerr == 1)
@@ -1573,7 +1643,7 @@ void create_obstructions_outside_nodes(void)
if ((ds->layer < Num_layers - 1) &&
gridx <
- (NumChannelsX[ds->layer] - 1)
+ (NumChannelsX - 1)
&& (OBSVAL(gridx + 1, gridy,
ds->layer + 1)
& OBSTRUCT_MASK))
@@ -1592,7 +1662,7 @@ void create_obstructions_outside_nodes(void)
if ((ds->layer < Num_layers - 1) &&
gridy <
- (NumChannelsY[ds->layer] - 1)
+ (NumChannelsY - 1)
&& (OBSVAL(gridx, gridy - 1,
ds->layer + 1)
& OBSTRUCT_MASK))
@@ -1850,7 +1920,7 @@ void create_obstructions_outside_nodes(void)
}
}
- lnode = SetNodeinfo(gridx, gridy, ds->layer);
+ lnode = SetNodeinfo(gridx, gridy, ds->layer, node);
lnode->nodeloc = node;
lnode->nodesav = node;
@@ -1937,25 +2007,36 @@ void create_obstructions_outside_nodes(void)
// Check tap to right
if ((dx > ds->x2) && (gridx <
- NumChannelsX[ds->layer] - 1)) {
+ NumChannelsX - 1)) {
offset_net = OBSVAL(gridx + 1, gridy, ds->layer);
if (offset_net == 0 || offset_net == othernet) {
- xdist = 0.5 * LefGetViaWidth(ds->layer,
- ds->layer, 0);
+ xdist = 0.5 * LefGetXYViaWidth(ds->layer,
+ ds->layer, 0, orient);
dist = ds->x2 - dx + xdist +
LefGetRouteSpacing(ds->layer);
- mask = OFFSET_TAP;
- dir = NI_OFFSET_EW;
- OBSVAL(gridx, gridy, ds->layer) |= mask;
- lnode->offset = dist;
- lnode->flags |= dir;
- no_offsets = FALSE;
-
- if ((ds->layer < Num_layers - 1) &&
- (gridx > 0) &&
- (OBSVAL(gridx + 1, gridy, ds->layer + 1)
- & OBSTRUCT_MASK))
- block_route(gridx, gridy, ds->layer, UP);
+ // Only accept an alternative solution if
+ // it has a smaller offset than previously
+ // found.
+ if ((no_offsets == FALSE) ||
+ (fabs(lnode->offset) > fabs(dist))) {
+ mask = OFFSET_TAP;
+ dir = NI_OFFSET_EW;
+ OBSVAL(gridx, gridy, ds->layer) |= mask;
+ lnode->offset = dist;
+ lnode->flags &= ~(NI_OFFSET_NS);
+ lnode->flags |= dir;
+ no_offsets = FALSE;
+
+ if ((ds->layer < Num_layers - 1) &&
+ (gridx > 0) &&
+ (OBSVAL(gridx + 1, gridy,
+ ds->layer + 1) & OBSTRUCT_MASK))
+ block_route(gridx, gridy, ds->layer, UP);
+ else if ((ds->layer < Num_layers - 1) &&
+ (gridx > 0) &&
+ (dist > PitchX / 2))
+ block_route(gridx, gridy, ds->layer, UP);
+ }
}
}
@@ -1964,47 +2045,64 @@ void create_obstructions_outside_nodes(void)
if ((dx < ds->x1) && (gridx > 0)) {
offset_net = OBSVAL(gridx - 1, gridy, ds->layer);
if (offset_net == 0 || offset_net == othernet) {
- xdist = 0.5 * LefGetViaWidth(ds->layer,
- ds->layer, 0);
+ xdist = 0.5 * LefGetXYViaWidth(ds->layer,
+ ds->layer, 0, orient);
dist = ds->x1 - dx - xdist -
LefGetRouteSpacing(ds->layer);
- mask = OFFSET_TAP;
- dir = NI_OFFSET_EW;
- OBSVAL(gridx, gridy, ds->layer) |= mask;
- lnode->offset = dist;
- lnode->flags |= dir;
- no_offsets = FALSE;
-
- if ((ds->layer < Num_layers - 1) &&
- gridx < (NumChannelsX[ds->layer] - 1) &&
- (OBSVAL(gridx - 1, gridy, ds->layer + 1)
- & OBSTRUCT_MASK))
- block_route(gridx, gridy, ds->layer, UP);
+ if ((no_offsets == FALSE) ||
+ (fabs(lnode->offset) > fabs(dist))) {
+ mask = OFFSET_TAP;
+ dir = NI_OFFSET_EW;
+ OBSVAL(gridx, gridy, ds->layer) |= mask;
+ lnode->offset = dist;
+ lnode->flags &= ~(NI_OFFSET_NS);
+ lnode->flags |= dir;
+ no_offsets = FALSE;
+
+ if ((ds->layer < Num_layers - 1) && gridx <
+ (NumChannelsX - 1) &&
+ (OBSVAL(gridx - 1, gridy,
+ ds->layer + 1) & OBSTRUCT_MASK))
+ block_route(gridx, gridy, ds->layer, UP);
+ else if ((ds->layer < Num_layers - 1) &&
+ gridx <
+ (NumChannelsX - 1) &&
+ (dist < -PitchX / 2))
+ block_route(gridx, gridy, ds->layer, UP);
+ }
}
}
// Check tap up
if ((dy > ds->y2) && (gridy <
- NumChannelsY[ds->layer] - 1)) {
+ NumChannelsY - 1)) {
offset_net = OBSVAL(gridx, gridy + 1, ds->layer);
if (offset_net == 0 || offset_net == othernet) {
- xdist = 0.5 * LefGetViaWidth(ds->layer,
- ds->layer, 1);
+ xdist = 0.5 * LefGetXYViaWidth(ds->layer,
+ ds->layer, 1, orient);
dist = ds->y2 - dy + xdist +
LefGetRouteSpacing(ds->layer);
- mask = OFFSET_TAP;
- dir = NI_OFFSET_NS;
- OBSVAL(gridx, gridy, ds->layer) |= mask;
- lnode->offset = dist;
- lnode->flags |= dir;
- no_offsets = FALSE;
-
- if ((ds->layer < Num_layers - 1) &&
- (gridy > 0) &&
- (OBSVAL(gridx, gridy + 1, ds->layer + 1)
- & OBSTRUCT_MASK))
- block_route(gridx, gridy, ds->layer, UP);
+ if ((no_offsets == FALSE) ||
+ (fabs(lnode->offset) > fabs(dist))) {
+ mask = OFFSET_TAP;
+ dir = NI_OFFSET_NS;
+ OBSVAL(gridx, gridy, ds->layer) |= mask;
+ lnode->offset = dist;
+ lnode->flags &= ~(NI_OFFSET_EW);
+ lnode->flags |= dir;
+ no_offsets = FALSE;
+
+ if ((ds->layer < Num_layers - 1) &&
+ (gridy > 0) && (OBSVAL(gridx,
+ gridy + 1, ds->layer + 1)
+ & OBSTRUCT_MASK))
+ block_route(gridx, gridy, ds->layer, UP);
+ else if ((ds->layer < Num_layers - 1) &&
+ (gridy > 0) &&
+ (dist > PitchY / 2))
+ block_route(gridx, gridy, ds->layer, UP);
+ }
}
}
@@ -2013,30 +2111,49 @@ void create_obstructions_outside_nodes(void)
if ((dy < ds->y1) && (gridy > 0)) {
offset_net = OBSVAL(gridx, gridy - 1, ds->layer);
if (offset_net == 0 || offset_net == othernet) {
- xdist = 0.5 * LefGetViaWidth(ds->layer,
- ds->layer, 1);
+ xdist = 0.5 * LefGetXYViaWidth(ds->layer,
+ ds->layer, 1, orient);
dist = ds->y1 - dy - xdist -
LefGetRouteSpacing(ds->layer);
- mask = OFFSET_TAP;
- dir = NI_OFFSET_NS;
- OBSVAL(gridx, gridy, ds->layer) |= mask;
- lnode->offset = dist;
- lnode->flags |= dir;
- no_offsets = FALSE;
-
- if ((ds->layer < Num_layers - 1) &&
- gridx < (NumChannelsX[ds->layer] - 1) &&
- (OBSVAL(gridx, gridy - 1, ds->layer + 1)
- & OBSTRUCT_MASK))
- block_route(gridx, gridy, ds->layer, UP);
+ if ((no_offsets == FALSE) ||
+ (fabs(lnode->offset) > fabs(dist))) {
+ mask = OFFSET_TAP;
+ dir = NI_OFFSET_NS;
+ OBSVAL(gridx, gridy, ds->layer) |= mask;
+ lnode->offset = dist;
+ lnode->flags &= ~(NI_OFFSET_EW);
+ lnode->flags |= dir;
+ no_offsets = FALSE;
+
+ if ((ds->layer < Num_layers - 1) &&
+ gridx <
+ (NumChannelsX - 1) &&
+ (OBSVAL(gridx, gridy - 1,
+ ds->layer + 1) & OBSTRUCT_MASK))
+ block_route(gridx, gridy, ds->layer, UP);
+ else if ((ds->layer < Num_layers - 1) &&
+ gridx <
+ (NumChannelsX - 1) &&
+ (dist < -PitchY / 2))
+ block_route(gridx, gridy, ds->layer, UP);
+ }
}
}
- // No offsets were possible, so disable the
- // position
+ // No offsets were possible. If orient is 0
+ // then mark as NI_NO_VIAX and try again with
+ // orient 2. If orient is 2 and no offsets
+ // are possible, then disable the position.
- if (no_offsets == TRUE)
- disable_gridpos(gridx, gridy, ds->layer);
+ if (no_offsets == TRUE) {
+ if (orient == 2) {
+ // Maybe no need to revert the flag?
+ lnode->flags &= ~NI_NO_VIAX;
+ disable_gridpos(gridx, gridy, ds->layer);
+ }
+ else
+ lnode->flags |= NI_NO_VIAX;
+ }
}
else
disable_gridpos(gridx, gridy, ds->layer);
@@ -2055,7 +2172,8 @@ void create_obstructions_outside_nodes(void)
(othernet == (u_int)node->netnum))) {
lnode = NODEIPTR(gridx, gridy, ds->layer);
- xdist = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 0);
+ xdist = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer,
+ 0, orient);
if ((dy + xdist + LefGetRouteSpacing(ds->layer) >
ds->y1) && (dy + xdist < ds->y1)) {
if ((dx - xdist < ds->x2) &&
@@ -2066,7 +2184,8 @@ void create_obstructions_outside_nodes(void)
= (OBSVAL(gridx, gridy, ds->layer)
& BLOCKED_MASK) |
node->netnum | STUBROUTE;
- lnode = SetNodeinfo(gridx, gridy, ds->layer);
+ lnode = SetNodeinfo(gridx, gridy, ds->layer,
+ node);
lnode->nodeloc = node;
lnode->nodesav = node;
lnode->stub = ds->y1 - dy;
@@ -2083,7 +2202,8 @@ void create_obstructions_outside_nodes(void)
= (OBSVAL(gridx, gridy, ds->layer)
& BLOCKED_MASK) |
node->netnum | STUBROUTE;
- lnode = SetNodeinfo(gridx, gridy, ds->layer);
+ lnode = SetNodeinfo(gridx, gridy, ds->layer,
+ node);
lnode->nodeloc = node;
lnode->nodesav = node;
lnode->stub = ds->y2 - dy;
@@ -2091,7 +2211,8 @@ void create_obstructions_outside_nodes(void)
}
}
- xdist = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 1);
+ xdist = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer,
+ 1, orient);
if ((dx + xdist + LefGetRouteSpacing(ds->layer) >
ds->x1) && (dx + xdist < ds->x1)) {
if ((dy - xdist < ds->y2) &&
@@ -2102,7 +2223,8 @@ void create_obstructions_outside_nodes(void)
= (OBSVAL(gridx, gridy, ds->layer)
& BLOCKED_MASK) |
node->netnum | STUBROUTE;
- lnode = SetNodeinfo(gridx, gridy, ds->layer);
+ lnode = SetNodeinfo(gridx, gridy, ds->layer,
+ node);
lnode->nodeloc = node;
lnode->nodesav = node;
lnode->stub = ds->x1 - dx;
@@ -2119,7 +2241,8 @@ void create_obstructions_outside_nodes(void)
= (OBSVAL(gridx, gridy, ds->layer)
& BLOCKED_MASK) |
node->netnum | STUBROUTE;
- lnode = SetNodeinfo(gridx, gridy, ds->layer);
+ lnode = SetNodeinfo(gridx, gridy, ds->layer,
+ node);
lnode->nodeloc = node;
lnode->nodesav = node;
lnode->stub = ds->x2 - dx;
@@ -2163,31 +2286,34 @@ void tap_to_tap_interactions(void)
double dx, dy;
float dist;
- double deltax[MAX_LAYERS];
- double deltay[MAX_LAYERS];
+ double deltaxx[MAX_LAYERS];
+ double deltaxy[MAX_LAYERS];
+ double deltayx[MAX_LAYERS];
+ double deltayy[MAX_LAYERS];
for (i = 0; i < Num_layers; i++) {
- deltax[i] = 0.5 * LefGetViaWidth(i, i, 0) + LefGetRouteSpacing(i);
- deltay[i] = 0.5 * LefGetViaWidth(i, i, 1) + LefGetRouteSpacing(i);
+ deltaxx[i] = 0.5 * LefGetXYViaWidth(i, i, 0, 0) + LefGetRouteSpacing(i);
+ deltayx[i] = 0.5 * LefGetXYViaWidth(i, i, 1, 0) + LefGetRouteSpacing(i);
+ deltaxy[i] = 0.5 * LefGetXYViaWidth(i, i, 0, 2) + LefGetRouteSpacing(i);
+ deltayy[i] = 0.5 * LefGetXYViaWidth(i, i, 1, 2) + LefGetRouteSpacing(i);
}
for (g = Nlgates; g; g = g->next) {
for (i = 0; i < g->nodes; i++) {
net = g->netnum[i];
- if (net != 0) {
-
+ if (net > 0) {
for (ds = g->taps[i]; ds; ds = ds->next) {
- mingridx = (int)((ds->x1 - Xlowerbound) / PitchX[ds->layer]) - 1;
+ mingridx = (int)((ds->x1 - Xlowerbound) / PitchX) - 1;
if (mingridx < 0) mingridx = 0;
- maxgridx = (int)((ds->x2 - Xlowerbound) / PitchX[ds->layer]) + 2;
- if (maxgridx >= NumChannelsX[ds->layer])
- maxgridx = NumChannelsX[ds->layer] - 1;
- mingridy = (int)((ds->y1 - Ylowerbound) / PitchY[ds->layer]) - 1;
+ maxgridx = (int)((ds->x2 - Xlowerbound) / PitchX) + 2;
+ if (maxgridx >= NumChannelsX)
+ maxgridx = NumChannelsX - 1;
+ mingridy = (int)((ds->y1 - Ylowerbound) / PitchY) - 1;
if (mingridy < 0) mingridy = 0;
- maxgridy = (int)((ds->y2 - Ylowerbound) / PitchY[ds->layer]) + 2;
- if (maxgridy >= NumChannelsY[ds->layer])
- maxgridy = NumChannelsY[ds->layer] - 1;
+ maxgridy = (int)((ds->y2 - Ylowerbound) / PitchY) + 2;
+ if (maxgridy >= NumChannelsY)
+ maxgridy = NumChannelsY - 1;
for (gridx = mingridx; gridx <= maxgridx; gridx++) {
for (gridy = mingridy; gridy <= maxgridy; gridy++) {
@@ -2200,8 +2326,8 @@ void tap_to_tap_interactions(void)
orignet &= ROUTED_NET_MASK;
if (orignet != net) {
- dx = (gridx * PitchX[ds->layer]) + Xlowerbound;
- dy = (gridy * PitchY[ds->layer]) + Ylowerbound;
+ dx = (gridx * PitchX) + Xlowerbound;
+ dy = (gridy * PitchY) + Ylowerbound;
lnode = NODEIPTR(gridx, gridy, ds->layer);
dist = (lnode) ? lnode->offset : 0.0;
@@ -2210,10 +2336,10 @@ void tap_to_tap_interactions(void)
/* at (gridx, gridy) and offset as specified. */
/* Expanded by metal spacing requirement. */
- de.x1 = dx - deltax[ds->layer];
- de.x2 = dx + deltax[ds->layer];
- de.y1 = dy - deltay[ds->layer];
- de.y2 = dy + deltay[ds->layer];
+ de.x1 = dx - deltaxx[ds->layer];
+ de.x2 = dx + deltaxx[ds->layer];
+ de.y1 = dy - deltayx[ds->layer];
+ de.y2 = dy + deltayx[ds->layer];
if (lnode->flags & NI_OFFSET_NS) {
de.y1 += dist;
@@ -2238,6 +2364,75 @@ void tap_to_tap_interactions(void)
disable_gridpos(gridx, gridy, ds->layer);
}
}
+
+ /* Does the distance to the tap prohibit a specific */
+ /* via orientation? */
+ if ((orignet & (~(BLOCKED_N | BLOCKED_S | BLOCKED_E | BLOCKED_W)))
+ == 0) {
+ lnode = NODEIPTR(gridx, gridy, ds->layer);
+ /* Positions belonging to nodes should have */
+ /* already been handled. */
+ if (lnode == NULL) {
+ dx = (gridx * PitchX) + Xlowerbound;
+ dy = (gridy * PitchY) + Ylowerbound;
+
+ /* For a horizontally-oriented via on ds->layer */
+ de.x1 = dx - deltaxx[ds->layer];
+ de.x2 = dx + deltaxx[ds->layer];
+ de.y1 = dy - deltayx[ds->layer];
+ de.y2 = dy + deltayx[ds->layer];
+
+ if (ds->x2 > de.x1 && ds->x1 < de.x2) {
+ /* Check north and south */
+ if ((ds->y1 < de.y2 && ds->y2 > de.y2) ||
+ (ds->y2 > de.y1 && ds->y1 < de.y1)) {
+ /* prohibit horizontal via */
+ lnode = SetNodeinfo(gridx, gridy, ds->layer,
+ g->noderec[i]);
+ lnode->flags |= NI_NO_VIAX;
+ }
+ }
+
+ if (ds->y2 > de.y1 && ds->y1 < de.y2) {
+ /* Check east and west*/
+ if ((ds->x1 < de.x2 && ds->x2 > de.x2) ||
+ (ds->x2 > de.x1 && ds->x1 < de.x1)) {
+ /* prohibit horizontal via */
+ lnode = SetNodeinfo(gridx, gridy, ds->layer,
+ g->noderec[i]);
+ lnode->flags |= NI_NO_VIAX;
+ }
+ }
+
+ /* For a vertically-oriented via on ds->layer */
+ de.x1 = dx - deltaxy[ds->layer];
+ de.x2 = dx + deltaxy[ds->layer];
+ de.y1 = dy - deltayy[ds->layer];
+ de.y2 = dy + deltayy[ds->layer];
+
+ if (ds->x2 > de.x1 && ds->x1 < de.x2) {
+ /* Check north and south */
+ if ((ds->y1 < de.y2 && ds->y2 > de.y2) ||
+ (ds->y2 > de.y1 && ds->y1 < de.y1)) {
+ /* prohibit horizontal via */
+ lnode = SetNodeinfo(gridx, gridy, ds->layer,
+ g->noderec[i]);
+ lnode->flags |= NI_NO_VIAY;
+ }
+ }
+
+ if (ds->y2 > de.y1 && ds->y1 < de.y2) {
+ /* Check east and west*/
+ if ((ds->x1 < de.x2 && ds->x2 > de.x2) ||
+ (ds->x2 > de.x1 && ds->x1 < de.x1)) {
+ /* prohibit horizontal via */
+ lnode = SetNodeinfo(gridx, gridy, ds->layer,
+ g->noderec[i]);
+ lnode->flags |= NI_NO_VIAY;
+ }
+ }
+ }
+ }
}
}
}
@@ -2276,15 +2471,15 @@ make_routable(NODE node)
for (i = 0; i < g->nodes; i++) {
if (g->noderec[i] == node) {
for (ds = g->taps[i]; ds; ds = ds->next) {
- gridx = (int)((ds->x1 - Xlowerbound) / PitchX[ds->layer]) - 1;
+ gridx = (int)((ds->x1 - Xlowerbound) / PitchX) - 1;
while (1) {
- dx = (gridx * PitchX[ds->layer]) + Xlowerbound;
- if (dx > ds->x2 || gridx >= NumChannelsX[ds->layer]) break;
+ dx = (gridx * PitchX) + Xlowerbound;
+ if (dx > ds->x2 || gridx >= NumChannelsX) break;
else if (dx >= ds->x1 && gridx >= 0) {
- gridy = (int)((ds->y1 - Ylowerbound) / PitchY[ds->layer]) - 1;
+ gridy = (int)((ds->y1 - Ylowerbound) / PitchY) - 1;
while (1) {
- dy = (gridy * PitchY[ds->layer]) + Ylowerbound;
- if (dy > ds->y2 || gridy >= NumChannelsY[ds->layer]) break;
+ dy = (gridy * PitchY) + Ylowerbound;
+ if (dy > ds->y2 || gridy >= NumChannelsY) break;
// Area inside defined pin geometry
@@ -2293,7 +2488,8 @@ make_routable(NODE node)
if (orignet & NO_NET) {
OBSVAL(gridx, gridy, ds->layer) = g->netnum[i];
- lnode = SetNodeinfo(gridx, gridy, ds->layer);
+ lnode = SetNodeinfo(gridx, gridy, ds->layer,
+ g->noderec[i]);
lnode->nodeloc = node;
lnode->nodesav = node;
return;
@@ -2335,6 +2531,7 @@ void adjust_stub_lengths(void)
double dx, dy, wx, wy, s;
float dist;
u_char errbox;
+ int orient = 0;
// For each node terminal (gate pin), look at the surrounding grid points.
// If any define a stub route or an offset, check if the stub geometry
@@ -2356,26 +2553,38 @@ void adjust_stub_lengths(void)
node = g->noderec[i];
if (node == NULL) continue;
- // Work through each rectangle in the tap geometry
-
- for (ds = g->taps[i]; ds; ds = ds->next) {
- wx = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 0);
- wy = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 1);
+ // Work through each rectangle in the tap geometry twice. The
+ // second sweep checks for errors created by geometry that
+ // interacts with stub routes created by the first sweep, and
+ // also for geometry that interacts with vias in 90 degree
+ // orientation.
+
+ orient = 0;
+ for (ds = g->taps[i];; ds = ds->next) {
+ if (ds == NULL) {
+ if (orient == 0) {
+ orient = 2;
+ ds = g->taps[i];
+ if (ds == NULL) break;
+ }
+ else
+ break;
+ }
+ wx = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 0, orient);
+ wy = 0.5 * LefGetXYViaWidth(ds->layer, ds->layer, 1, orient);
s = LefGetRouteSpacing(ds->layer);
- gridx = (int)((ds->x1 - Xlowerbound - PitchX[ds->layer])
- / PitchX[ds->layer]) - 1;
+ gridx = (int)((ds->x1 - Xlowerbound - PitchX) / PitchX) - 1;
while (1) {
- dx = (gridx * PitchX[ds->layer]) + Xlowerbound;
- if (dx > (ds->x2 + PitchX[ds->layer]) ||
- gridx >= NumChannelsX[ds->layer]) break;
- else if (dx >= (ds->x1 - PitchX[ds->layer]) && gridx >= 0) {
- gridy = (int)((ds->y1 - Ylowerbound - PitchY[ds->layer])
- / PitchY[ds->layer]) - 1;
+ dx = (gridx * PitchX) + Xlowerbound;
+ if (dx > (ds->x2 + PitchX) ||
+ gridx >= NumChannelsX) break;
+ else if (dx >= (ds->x1 - PitchX) && gridx >= 0) {
+ gridy = (int)((ds->y1 - Ylowerbound - PitchY) / PitchY) - 1;
while (1) {
- dy = (gridy * PitchY[ds->layer]) + Ylowerbound;
- if (dy > (ds->y2 + PitchY[ds->layer]) ||
- gridy >= NumChannelsY[ds->layer]) break;
- if (dy >= (ds->y1 - PitchY[ds->layer]) && gridy >= 0) {
+ dy = (gridy * PitchY) + Ylowerbound;
+ if (dy > (ds->y2 + PitchY) ||
+ gridy >= NumChannelsY) break;
+ if (dy >= (ds->y1 - PitchY) && gridy >= 0) {
orignet = OBSVAL(gridx, gridy, ds->layer);
@@ -2391,7 +2600,7 @@ void adjust_stub_lengths(void)
// Even if it's on the same net, we need to check
// if the stub is to this node, otherwise it is not
// an issue.
- if (lnode->nodesav != node) {
+ if ((!lnode) || (lnode->nodesav != node)) {
gridy++;
continue;
}
@@ -2610,16 +2819,13 @@ void adjust_stub_lengths(void)
OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP;
if (LefGetRouteOrientation(ds->layer) == 1) {
lnode->flags = NI_OFFSET_NS | NI_STUB_EW;
- // lnode->offset = lnode->stub; // ?
if (lnode->stub > 0) {
- lnode->offset = de.y2 - dy - wy;
- if (lnode->offset > s - lnode->offset)
- lnode->offset -= s;
+ lnode->offset = lnode->stub - wy;
+ if (lnode->offset < 0) lnode->offset = 0;
}
else {
- lnode->offset = de.y1 - dy + wy;
- if (-lnode->offset > s + lnode->offset)
- lnode->offset += s;
+ lnode->offset = lnode->stub + wy;
+ if (lnode->offset > 0) lnode->offset = 0;
}
lnode->stub = de.x2 - dx;
errbox = FALSE;
@@ -2659,16 +2865,13 @@ void adjust_stub_lengths(void)
OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP;
if (LefGetRouteOrientation(ds->layer) == 1) {
lnode->flags = NI_OFFSET_NS | NI_STUB_EW;
- // lnode->offset = lnode->stub; // ?
if (lnode->stub > 0) {
- lnode->offset = de.y2 - dy - wy;
- if (lnode->offset > s - lnode->offset)
- lnode->offset -= s;
+ lnode->offset = lnode->stub - wy;
+ if (lnode->offset < 0) lnode->offset = 0;
}
else {
- lnode->offset = de.y1 - dy + wy;
- if (-lnode->offset > s + lnode->offset)
- lnode->offset += s;
+ lnode->offset = lnode->stub + wy;
+ if (lnode->offset > 0) lnode->offset = 0;
}
lnode->stub = de.x1 - dx;
errbox = FALSE;
@@ -2708,16 +2911,13 @@ void adjust_stub_lengths(void)
OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP;
if (LefGetRouteOrientation(ds->layer) == 0) {
lnode->flags = NI_OFFSET_EW | NI_STUB_NS;
- // lnode->offset = lnode->stub; // ?
if (lnode->stub > 0) {
- lnode->offset = de.x2 - dx - wx;
- if (lnode->offset > s - lnode->offset)
- lnode->offset -= s;
+ lnode->offset = lnode->stub - wx;
+ if (lnode->offset < 0) lnode->offset = 0;
}
else {
- lnode->offset = de.x1 - dx + wx;
- if (-lnode->offset > s + lnode->offset)
- lnode->offset += s;
+ lnode->offset = lnode->stub + wx;
+ if (lnode->offset > 0) lnode->offset = 0;
}
lnode->stub = de.y2 - dy;
errbox = FALSE;
@@ -2757,16 +2957,13 @@ void adjust_stub_lengths(void)
OBSVAL(gridx, gridy, ds->layer) |= OFFSET_TAP;
if (LefGetRouteOrientation(ds->layer) == 0) {
lnode->flags = NI_OFFSET_EW | NI_STUB_NS;
- // lnode->offset = lnode->stub; // ?
if (lnode->stub > 0) {
- lnode->offset = de.x2 - dx - wx;
- if (lnode->offset > s - lnode->offset)
- lnode->offset -= s;
+ lnode->offset = lnode->stub - wx;
+ if (lnode->offset < 0) lnode->offset = 0;
}
else {
- lnode->offset = de.x1 - dx + wx;
- if (-lnode->offset > s + lnode->offset)
- lnode->offset += s;
+ lnode->offset = lnode->stub + wx;
+ if (lnode->offset > 0) lnode->offset = 0;
}
lnode->stub = de.y1 - dy + wy;
errbox = FALSE;
@@ -2830,7 +3027,7 @@ block_route(int x, int y, int lay, u_char dir)
switch (dir) {
case NORTH:
- if (y == NumChannelsY[lay] - 1) return;
+ if (y == NumChannelsY - 1) return;
by = y + 1;
break;
case SOUTH:
@@ -2838,7 +3035,7 @@ block_route(int x, int y, int lay, u_char dir)
by = y - 1;
break;
case EAST:
- if (x == NumChannelsX[lay] - 1) return;
+ if (x == NumChannelsX - 1) return;
bx = x + 1;
break;
case WEST:
@@ -2905,10 +3102,11 @@ find_route_blocks()
GATE g;
NODEINFO lnode;
DSEG ds;
- struct dseg_ dt;
+ struct dseg_ dt, lds;
int i, gridx, gridy;
double dx, dy, w, v, s, u;
double dist;
+ int orient = 0; /* Need to check orient = 2! */
for (g = Nlgates; g; g = g->next) {
for (i = 0; i < g->nodes; i++) {
@@ -2917,142 +3115,159 @@ find_route_blocks()
// Work through each rectangle in the tap geometry
for (ds = g->taps[i]; ds; ds = ds->next) {
- w = 0.5 * LefGetRouteWidth(ds->layer);
- v = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 0);
- s = LefGetRouteSpacing(ds->layer);
+ lds = *ds; /* Make local copy of tap rect */
+
+ /* Trim to array bounds and reject if out-of-bounds */
+ gridx = (int)((lds.x1 - Xlowerbound) / PitchX);
+ if (gridx >= NumChannelsX) continue;
+ if (gridx < 0) lds.x1 = Xlowerbound;
+
+ gridx = (int)((lds.x2 - Xlowerbound) / PitchX);
+ if (gridx < 0) continue;
+ if (gridx >= NumChannelsX)
+ lds.x2 = Xlowerbound + (NumChannelsX * PitchX);
+
+ gridy = (int)((lds.y1 - Ylowerbound) / PitchY);
+ if (gridy >= NumChannelsY) continue;
+ if (gridy < 0) lds.y1 = Ylowerbound;
+
+ gridy = (int)((lds.y2 - Ylowerbound) / PitchY);
+ if (gridy < 0) continue;
+ if (gridy >= NumChannelsY)
+ lds.y2 = Ylowerbound + (NumChannelsY * PitchY);
+
+ w = 0.5 * LefGetRouteWidth(lds.layer);
+ v = 0.5 * LefGetXYViaWidth(lds.layer, lds.layer, 0, orient);
+ s = LefGetRouteSpacing(lds.layer);
// Look west
- gridx = (int)((ds->x1 - Xlowerbound) / PitchX[ds->layer]);
- dx = (gridx * PitchX[ds->layer]) + Xlowerbound;
- dist = ds->x1 - dx - w;
+ gridx = (int)((lds.x1 - Xlowerbound) / PitchX);
+ dx = (gridx * PitchX) + Xlowerbound;
+ dist = lds.x1 - dx - w;
if (dist > 0 && dist < s && gridx >= 0) {
dt.x1 = dt.x2 = dx;
- dt.y1 = ds->y1;
- dt.y2 = ds->y2;
+ dt.y1 = lds.y1;
+ dt.y2 = lds.y2;
// Check for other taps covering this edge
// (to do)
// Find all grid points affected
- gridy = (int)((ds->y1 - Ylowerbound - PitchY[ds->layer]) /
- PitchY[ds->layer]);
- dy = (gridy * PitchY[ds->layer]) + Ylowerbound;
- while (dy < ds->y1 - s) {
- dy += PitchY[ds->layer];
+ gridy = (int)((lds.y1 - Ylowerbound - PitchY) / PitchY);
+ dy = (gridy * PitchY) + Ylowerbound;
+ while (dy < lds.y1 - s) {
+ dy += PitchY;
gridy++;
}
- while (dy < ds->y2 + s) {
- lnode = NODEIPTR(gridx, gridy, ds->layer);
- u = ((OBSVAL(gridx, gridy, ds->layer) & STUBROUTE)
+ while (dy < lds.y2 + s) {
+ lnode = NODEIPTR(gridx, gridy, lds.layer);
+ u = ((OBSVAL(gridx, gridy, lds.layer) & STUBROUTE)
&& (lnode->flags & NI_STUB_EW)) ? v : w;
- if (dy + EPS < ds->y2 - u)
- block_route(gridx, gridy, ds->layer, NORTH);
- if (dy - EPS > ds->y1 + u)
- block_route(gridx, gridy, ds->layer, SOUTH);
- dy += PitchY[ds->layer];
+ if (dy + EPS < lds.y2 - u)
+ block_route(gridx, gridy, lds.layer, NORTH);
+ if (dy - EPS > lds.y1 + u)
+ block_route(gridx, gridy, lds.layer, SOUTH);
+ dy += PitchY;
gridy++;
}
}
// Look east
- gridx = (int)(1.0 + (ds->x2 - Xlowerbound) / PitchX[ds->layer]);
- dx = (gridx * PitchX[ds->layer]) + Xlowerbound;
- dist = dx - ds->x2 - w;
- if (dist > 0 && dist < s && gridx < NumChannelsX[ds->layer]) {
+ gridx = (int)(1.0 + (lds.x2 - Xlowerbound) / PitchX);
+ dx = (gridx * PitchX) + Xlowerbound;
+ dist = dx - lds.x2 - w;
+ if (dist > 0 && dist < s && gridx < NumChannelsX) {
dt.x1 = dt.x2 = dx;
- dt.y1 = ds->y1;
- dt.y2 = ds->y2;
+ dt.y1 = lds.y1;
+ dt.y2 = lds.y2;
// Check for other taps covering this edge
// (to do)
// Find all grid points affected
- gridy = (int)((ds->y1 - Ylowerbound - PitchY[ds->layer]) /
- PitchY[ds->layer]);
- dy = (gridy * PitchY[ds->layer]) + Ylowerbound;
- while (dy < ds->y1 - s) {
- dy += PitchY[ds->layer];
+ gridy = (int)((lds.y1 - Ylowerbound - PitchY) / PitchY);
+ dy = (gridy * PitchY) + Ylowerbound;
+ while (dy < lds.y1 - s) {
+ dy += PitchY;
gridy++;
}
- while (dy < ds->y2 + s) {
- lnode = NODEIPTR(gridx, gridy, ds->layer);
- u = ((OBSVAL(gridx, gridy, ds->layer) & STUBROUTE)
+ while (dy < lds.y2 + s) {
+ lnode = NODEIPTR(gridx, gridy, lds.layer);
+ u = ((OBSVAL(gridx, gridy, lds.layer) & STUBROUTE)
&& (lnode->flags & NI_STUB_EW)) ? v : w;
- if (dy + EPS < ds->y2 - u)
- block_route(gridx, gridy, ds->layer, NORTH);
- if (dy - EPS > ds->y1 + u)
- block_route(gridx, gridy, ds->layer, SOUTH);
- dy += PitchY[ds->layer];
+ if (dy + EPS < lds.y2 - u)
+ block_route(gridx, gridy, lds.layer, NORTH);
+ if (dy - EPS > lds.y1 + u)
+ block_route(gridx, gridy, lds.layer, SOUTH);
+ dy += PitchY;
gridy++;
}
}
// Look south
- gridy = (int)((ds->y1 - Ylowerbound) / PitchY[ds->layer]);
- dy = (gridy * PitchY[ds->layer]) + Ylowerbound;
- dist = ds->y1 - dy - w;
+ gridy = (int)((lds.y1 - Ylowerbound) / PitchY);
+ dy = (gridy * PitchY) + Ylowerbound;
+ dist = lds.y1 - dy - w;
if (dist > 0 && dist < s && gridy >= 0) {
- dt.x1 = ds->x1;
- dt.x2 = ds->x2;
+ dt.x1 = lds.x1;
+ dt.x2 = lds.x2;
dt.y1 = dt.y2 = dy;
// Check for other taps covering this edge
// (to do)
// Find all grid points affected
- gridx = (int)((ds->x1 - Xlowerbound - PitchX[ds->layer]) /
- PitchX[ds->layer]);
- dx = (gridx * PitchX[ds->layer]) + Xlowerbound;
- while (dx < ds->x1 - s) {
- dx += PitchX[ds->layer];
+ gridx = (int)((lds.x1 - Xlowerbound - PitchX) / PitchX);
+ dx = (gridx * PitchX) + Xlowerbound;
+ while (dx < lds.x1 - s) {
+ dx += PitchX;
gridx++;
}
- while (dx < ds->x2 + s) {
- lnode = NODEIPTR(gridx, gridy, ds->layer);
- u = ((OBSVAL(gridx, gridy, ds->layer) & STUBROUTE)
+ while (dx < lds.x2 + s) {
+ lnode = NODEIPTR(gridx, gridy, lds.layer);
+ u = ((OBSVAL(gridx, gridy, lds.layer) & STUBROUTE)
&& (lnode->flags & NI_STUB_NS)) ? v : w;
- if (dx + EPS < ds->x2 - u)
- block_route(gridx, gridy, ds->layer, EAST);
- if (dx - EPS > ds->x1 + u)
- block_route(gridx, gridy, ds->layer, WEST);
- dx += PitchX[ds->layer];
+ if (dx + EPS < lds.x2 - u)
+ block_route(gridx, gridy, lds.layer, EAST);
+ if (dx - EPS > lds.x1 + u)
+ block_route(gridx, gridy, lds.layer, WEST);
+ dx += PitchX;
gridx++;
}
}
// Look north
- gridy = (int)(1.0 + (ds->y2 - Ylowerbound) / PitchY[ds->layer]);
- dy = (gridy * PitchY[ds->layer]) + Ylowerbound;
- dist = dy - ds->y2 - w;
- if (dist > 0 && dist < s && gridy < NumChannelsY[ds->layer]) {
- dt.x1 = ds->x1;
- dt.x2 = ds->x2;
+ gridy = (int)(1.0 + (lds.y2 - Ylowerbound) / PitchY);
+ dy = (gridy * PitchY) + Ylowerbound;
+ dist = dy - lds.y2 - w;
+ if (dist > 0 && dist < s && gridy < NumChannelsY) {
+ dt.x1 = lds.x1;
+ dt.x2 = lds.x2;
dt.y1 = dt.y2 = dy;
// Check for other taps covering this edge
// (to do)
// Find all grid points affected
- gridx = (int)((ds->x1 - Xlowerbound - PitchX[ds->layer]) /
- PitchX[ds->layer]);
- dx = (gridx * PitchX[ds->layer]) + Xlowerbound;
- while (dx < ds->x1 - s) {
- dx += PitchX[ds->layer];
+ gridx = (int)((lds.x1 - Xlowerbound - PitchX) / PitchX);
+ dx = (gridx * PitchX) + Xlowerbound;
+ while (dx < lds.x1 - s) {
+ dx += PitchX;
gridx++;
}
- while (dx < ds->x2 + s) {
- lnode = NODEIPTR(gridx, gridy, ds->layer);
- u = ((OBSVAL(gridx, gridy, ds->layer) & STUBROUTE)
+ while (dx < lds.x2 + s) {
+ lnode = NODEIPTR(gridx, gridy, lds.layer);
+ u = ((OBSVAL(gridx, gridy, lds.layer) & STUBROUTE)
&& (lnode->flags & NI_STUB_NS)) ? v : w;
- if (dx + EPS < ds->x2 - u)
- block_route(gridx, gridy, ds->layer, EAST);
- if (dx - EPS > ds->x1 + u)
- block_route(gridx, gridy, ds->layer, WEST);
- dx += PitchX[ds->layer];
+ if (dx + EPS < lds.x2 - u)
+ block_route(gridx, gridy, lds.layer, EAST);
+ if (dx - EPS > lds.x1 + u)
+ block_route(gridx, gridy, lds.layer, WEST);
+ dx += PitchX;
gridx++;
}
}
diff --git a/node.h b/node.h
index 7ffe42c..e44de43 100644
--- a/node.h
+++ b/node.h
@@ -8,9 +8,9 @@
#define GND_NET 1
#define VDD_NET 2
-#define MIN_NET_NUMBER 3
+#define ANTENNA_NET 3
+#define MIN_NET_NUMBER 4
-void create_netorder(u_char method);
void find_bounding_box(NET net);
void defineRouteTree(NET);
void print_nodes(char *filename);
diff --git a/output.c b/output.c
index 4fe49a2..056deb6 100644
--- a/output.c
+++ b/output.c
@@ -30,6 +30,46 @@
int Pathon = -1;
+struct _savepath {
+ u_char active;
+ int x;
+ int y;
+ int orient;
+} path_delayed;
+
+/*--------------------------------------------------------------*/
+/* Output a list of failed nets. */
+/*--------------------------------------------------------------*/
+
+int write_failed(char *filename)
+{
+ FILE *ffail;
+ NET net;
+ NETLIST nl;
+ int failcount;
+
+ failcount = countlist(FailedNets);
+ if (failcount == 0) {
+ Fprintf(stdout, "There are no failing net routes.\n");
+ return 0;
+ }
+
+ ffail = fopen(filename, "w");
+ if (ffail == NULL) {
+ Fprintf(stderr, "Could not open file %s for writing.\n", filename);
+ return 1;
+ }
+ fprintf(ffail, "%d nets failed to route:\n", failcount);
+
+ for (nl = FailedNets; nl; nl = nl->next) {
+ net = nl->net;
+ fprintf(ffail, " %s\n", net->netname);
+ }
+
+ fclose(ffail);
+ return 0;
+}
+
/*--------------------------------------------------------------*/
/* Write the output annotated DEF file. */
/*--------------------------------------------------------------*/
@@ -51,14 +91,11 @@ int write_def(char *filename)
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
+ // Output a list of the failed nets
- while (FailedNets) {
- net = FailedNets->net;
+ for (nl = FailedNets; nl; nl = nl->next) {
+ net = nl->net;
Fprintf(stdout, " %s\n", net->netname);
- nl = FailedNets->next;
- free(FailedNets);
- FailedNets = nl;
}
Fprintf(stdout, "\n");
}
@@ -79,7 +116,7 @@ int write_def(char *filename)
static void
pathstart(FILE *cmd, int layer, int x, int y, u_char special, double oscale,
- double invscale, u_char horizontal)
+ double invscale, u_char horizontal, NODEINFO node)
{
if (Pathon == 1) {
Fprintf( stderr, "pathstart(): Major error. Started a new "
@@ -94,11 +131,25 @@ pathstart(FILE *cmd, int layer, int x, int y, u_char special, double oscale,
fprintf(cmd, "\n NEW ");
if (special) {
double wvia;
+ int vtype = 0; /* Need to get via type from node record! */
+
+ if (node != NULL) {
+ if ((node->flags & NI_NO_VIAX) && (!(node->flags & NI_VIA_X)))
+ vtype = 2;
+ else if (node->flags & NI_VIA_Y)
+ vtype = 2;
+ }
+ else {
+ /* Assume via orientation matches default route direction. */
+ /* NOTE: Need to mark the actual orientation somehow. . . */
+ int ob = LefGetRouteOrientation((layer > 0) ? (layer - 1) : layer);
+ if (ob == 1) vtype = 2;
+ }
- wvia = LefGetViaWidth(layer, layer, horizontal);
+ wvia = LefGetXYViaWidth(layer, layer, horizontal, vtype);
if (layer > 0) {
double wvia2;
- wvia2 = LefGetViaWidth(layer - 1, layer, horizontal);
+ wvia2 = LefGetXYViaWidth(layer - 1, layer, horizontal, vtype);
if (wvia2 > wvia) wvia = wvia2;
}
@@ -124,7 +175,7 @@ pathstart(FILE *cmd, int layer, int x, int y, u_char special, double oscale,
static void
pathto(FILE *cmd, int x, int y, int horizontal, int lastx, int lasty,
- double invscale)
+ double invscale, u_char nextvia)
{
if (Pathon <= 0) {
Fprintf(stderr, "pathto(): Major error. Added to a "
@@ -139,9 +190,19 @@ pathto(FILE *cmd, int x, int y, int horizontal, int lastx, int lasty,
if ((x != lastx) && (y != lasty)) {
if (horizontal)
- pathto(cmd, lastx, y, FALSE, lastx, lasty, invscale);
+ pathto(cmd, lastx, y, FALSE, lastx, lasty, invscale, 0);
else
- pathto(cmd, x, lasty, TRUE, lastx, lasty, invscale);
+ pathto(cmd, x, lasty, TRUE, lastx, lasty, invscale, 0);
+ }
+
+ if (nextvia) {
+ /* Punt on output until via is output, because via may have an */
+ /* offset position that needs to be applied to the route. */
+ path_delayed.active = 1;
+ path_delayed.x = x;
+ path_delayed.y = y;
+ path_delayed.orient = horizontal;
+ return;
}
fprintf(cmd, "( ");
@@ -169,30 +230,13 @@ pathto(FILE *cmd, int x, int y, int horizontal, int lastx, int lasty,
static void
pathvia(FILE *cmd, int layer, int x, int y, int lastx, int lasty,
- int gridx, int gridy, double invscale)
+ char *vianame, double invscale)
{
- char *s;
- char checkersign = (gridx + gridy + layer) & 0x01;
- NODEINFO lnode;
-
- 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 the position is a node, then the via type may be switched if */
- /* there is a prohibition declared in the flags. */
-
- if (layer < Pinlayers) {
- if (((lnode = NODEIPTR(gridx, gridy, layer)) != NULL)
- && (lnode->nodesav != NULL)) {
- if ((lnode->flags & NI_NO_VIAX) && (s == ViaX[layer]))
- s = ViaY[layer];
- if ((lnode->flags & NI_NO_VIAY) && (s == ViaY[layer]))
- s = ViaX[layer];
- }
+ if (path_delayed.active == 1) {
+ /* Output the last path */
+ pathto(cmd, path_delayed.x, path_delayed.y, path_delayed.orient,
+ path_delayed.x, path_delayed.y, invscale, 0);
+ path_delayed.active = 0;
}
if (Pathon <= 0) {
@@ -211,11 +255,11 @@ pathvia(FILE *cmd, int layer, int x, int y, int lastx, int lasty,
// route to the via.
if (x != lastx)
- pathto(cmd, x, lasty, TRUE, lastx, lasty, invscale);
+ pathto(cmd, x, lasty, TRUE, lastx, lasty, invscale, 0);
if (y != lasty)
- pathto(cmd, x, y, FALSE, x, lasty, invscale);
+ pathto(cmd, x, y, FALSE, x, lasty, invscale, 0);
}
- fprintf(cmd, "%s ", s);
+ fprintf(cmd, "%s ", vianame);
Pathon = 0;
} /* pathvia() */
@@ -563,6 +607,59 @@ void print_nlnets( char *filename )
} /* print_nlnets() */
/*--------------------------------------------------------------*/
+/* link_up_seg --- */
+/* */
+/* As part of cleanup_net (below), when removing unneeded vias, */
+/* it may be necessary to check if a segment is being used to */
+/* connect to another route of a net, in which case removing */
+/* the segment would break the net. If that is the case, then */
+/* keep the segment by linking it to the end of the route that */
+/* was connected to it. */
+/* */
+/* Return 1 (true) if the segment was linked to another route, */
+/* so the caller knows whether or not to free the segment. */
+/* */
+/* "rt" is the route that the segment was connected to. For */
+/* the sake of efficiency, it does not need to be checked. */
+/*--------------------------------------------------------------*/
+
+u_char link_up_seg(NET net, SEG seg, int viabase, ROUTE srt)
+{
+ ROUTE rt;
+ SEG segf, segl;
+ int x, y;
+
+ for (rt = net->routes; rt; rt = rt->next) {
+ if (rt == srt) continue;
+ segf = rt->segments;
+ if ((segf->x1 == seg->x1) && (segf->y1 == seg->y1) &&
+ ((segf->layer == viabase) || (segf->layer == viabase + 1))) {
+ /* Reverse seg and prepend it to the route */
+ seg->next = rt->segments;
+ rt->segments = seg;
+ x = seg->x1;
+ y = seg->y1;
+ seg->x1 = seg->x2;
+ seg->y1 = seg->y2;
+ seg->x2 = x;
+ seg->y2 = y;
+ return (u_char)1;
+ }
+
+ /* Move to the last segment of the route */
+ for (segl = segf; segl && segl->next; segl = segl->next);
+
+ if (segl && (segl->x2 == seg->x1) && (segl->y2 == seg->y1) &&
+ ((segl->layer == viabase) || (segl->layer == viabase + 1))) {
+ /* Append seg to the route */
+ segl->next = seg;
+ return (u_char)1;
+ }
+ }
+ return (u_char)0;
+}
+
+/*--------------------------------------------------------------*/
/* cleanup_net -- */
/* */
/* Special handling for layers where needblock[] is non-zero, */
@@ -576,16 +673,16 @@ void print_nlnets( char *filename )
/* */
/* Note that the ensuing change in connectivity can violate */
/* the route endpoints and thereby mess up the delay output */
-/* routine unless route_set_connections() is re-run on the */
-/* modified routes. */
+/* routine and/or the antenna violation finding routine unless */
+/* route_set_connections() is re-run on the modified routes. */
/*--------------------------------------------------------------*/
-static void cleanup_net(NET net)
+void cleanup_net(NET net)
{
- SEG segf, segl, seg;
+ SEG segf, segl, seg, segp;
ROUTE rt, rt2;
NODEINFO lnode;
- int lf, ll, lf2, ll2;
+ int lf, ll, lf2, ll2, viabase;
u_char fcheck, lcheck, needfix;
u_char xcheckf, ycheckf, xcheckl, ycheckl;
@@ -806,6 +903,120 @@ static void cleanup_net(NET net)
}
}
}
+
+ /* One case not covered by the checks above: If the second or */
+ /* penultimate segment is a via and the final segment is one */
+ /* track in length and connects to a via, then the same */
+ /* replacement can be made. The other routes do not need to be */
+ /* checked, as it is sufficient to check that the grid is */
+ /* occupied at that point on two metal layers with the same net. */
+
+ /* NOTE: Another route could be connecting to the via on the */
+ /* penultimate segment, and removing it would cause an open net. */
+ /* Check for this case and resolve if needed. */
+
+ if ((fcheck == FALSE) && (lcheck == FALSE)) {
+ int wlen, oval0, oval1, oval2;
+
+ segf = rt->segments;
+ if ((segf == NULL) || (segf->next == NULL)) continue;
+ seg = segf->next;
+ if ((segf->segtype == ST_WIRE) && (seg->segtype == ST_VIA)) {
+ if ((segf->x1 - segf->x2) == 0) {
+ wlen = segf->y1 - segf->y2;
+ if ((wlen == 1) || (wlen == -1)) {
+ oval1 = OBSVAL(segf->x1, segf->y1, seg->layer) & ROUTED_NET_MASK;
+ oval2 = OBSVAL(segf->x1, segf->y1, seg->layer + 1) & ROUTED_NET_MASK;
+ if (oval1 == oval2) {
+ /* Check false case in which (layer + 1) is a min area stub */
+ segp = seg->next;
+ if (segp && (segp->x2 == segf->x1) && (segp->y2 == segf->y1))
+ continue;
+ /* Remove via and change wire layer */
+ needfix = TRUE;
+ segf->next = seg->next;
+ viabase = segf->layer;
+ segf->layer = (viabase == seg->layer) ? seg->layer + 1 :
+ seg->layer;
+ if (!link_up_seg(net, seg, viabase, rt)) free(seg);
+ }
+ }
+ }
+ else if ((segf->y1 - segf->y2) == 0) {
+ wlen = segf->x1 - segf->x2;
+ if ((wlen == 1) || (wlen == -1)) {
+ oval1 = OBSVAL(segf->x1, segf->y1, seg->layer) & ROUTED_NET_MASK;
+ oval2 = OBSVAL(segf->x1, segf->y1, seg->layer + 1) & ROUTED_NET_MASK;
+ if (oval1 == oval2) {
+ /* Check false case in which (layer + 1) is a min area stub */
+ segp = seg->next;
+ if (segp && (segp->x2 == segf->x1) && (segp->y2 == segf->y1))
+ continue;
+ /* Remove via and change wire layer */
+ needfix = TRUE;
+ segf->next = seg->next;
+ viabase = segf->layer;
+ segf->layer = (viabase == seg->layer) ? seg->layer + 1 :
+ seg->layer;
+ if (!link_up_seg(net, seg, viabase, rt)) free(seg);
+ }
+ }
+ }
+ }
+ segp = NULL;
+ for (seg = rt->segments; seg && seg->next && seg->next->next; seg = seg->next)
+ segp = seg;
+ if ((seg == NULL) || (seg->next == NULL)) continue;
+ segl = seg->next;
+ if ((segl->segtype == ST_WIRE) && (seg->segtype == ST_VIA)) {
+ if ((segl->x1 - segl->x2) == 0) {
+ wlen = segl->y1 - segl->y2;
+ if ((wlen == 1) || (wlen == -1)) {
+ oval1 = OBSVAL(segl->x2, segl->y2, seg->layer) & ROUTED_NET_MASK;
+ oval2 = OBSVAL(segl->x2, segl->y2, seg->layer + 1) & ROUTED_NET_MASK;
+ if (oval1 == oval2) {
+ /* Check false case in which (layer + 1) is a min area stub */
+ if (segp && (segp->x1 == segl->x2) && (segp->y1 == segl->y2))
+ continue;
+ /* Remove via and change wire layer */
+ needfix = TRUE;
+ seg->next = NULL;
+ seg->segtype = ST_WIRE;
+ viabase = seg->layer;
+ seg->layer = (viabase == segl->layer) ? viabase + 1 : viabase;
+ seg->x1 = segl->x1;
+ seg->y1 = segl->y1;
+ seg->x2 = segl->x2;
+ seg->y2 = segl->y2;
+ if (!link_up_seg(net, segl, viabase, rt)) free(segl);
+ }
+ }
+ }
+ else if ((segl->y1 - segl->y2) == 0) {
+ wlen = segl->x1 - segl->x2;
+ if ((wlen == 1) || (wlen == -1)) {
+ oval1 = OBSVAL(segl->x2, segl->y2, seg->layer) & ROUTED_NET_MASK;
+ oval2 = OBSVAL(segl->x2, segl->y2, seg->layer + 1) & ROUTED_NET_MASK;
+ if (oval1 == oval2) {
+ /* Check false case in which (layer + 1) is a min area stub */
+ if (segp && (segp->x1 == segl->x2) && (segp->y1 == segl->y2))
+ continue;
+ /* Remove via and change wire layer */
+ needfix = TRUE;
+ viabase = seg->layer;
+ seg->next = NULL;
+ seg->segtype = ST_WIRE;
+ seg->layer = (viabase == segl->layer) ? viabase + 1 : viabase;
+ seg->x1 = segl->x1;
+ seg->y1 = segl->y1;
+ seg->x2 = segl->x2;
+ seg->y2 = segl->y2;
+ if (!link_up_seg(net, segl, viabase, rt)) free(segl);
+ }
+ }
+ }
+ }
+ }
}
if (needfix == TRUE)
for (rt = net->routes; rt; rt = rt->next)
@@ -841,7 +1052,7 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
int lastx = -1, lasty = -1, lastlay;
int horizontal;
float offset1, offset2, stub, offset;
- u_char cancel, segtype;
+ u_char cancel, segtype, nextvia;
double invscale = (double)(1.0 / (double)iscale);
/* If the STUB flag is set, then we need to write out the net name */
@@ -851,112 +1062,14 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
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) {
+
+ path_delayed.active = 0;
+
if (rt->segments && !(rt->flags & RT_OUTPUT)) {
horizontal = FALSE;
cancel = FALSE;
@@ -966,6 +1079,7 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
lastseg = saveseg = seg;
layer = seg->layer;
if (seg) {
+ nextvia = (seg->next) ? ((seg->next->segtype == ST_VIA) ? 1 : 0) : 0;
// It is rare but possible to have a stub route off of an
// endpoint via, so check this case, and use the layer type
@@ -983,12 +1097,12 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
" at %d %d (%d)\n", stub,
seg->x1, seg->y1, layer);
- dc = Xlowerbound + (double)seg->x1 * PitchX[layer];
+ dc = Xlowerbound + (double)seg->x1 * PitchX;
x = (int)((REPS(dc)) * oscale);
if (lnode->flags & NI_STUB_EW)
dc += stub;
x2 = (int)((REPS(dc)) * oscale);
- dc = Ylowerbound + (double)seg->y1 * PitchY[layer];
+ dc = Ylowerbound + (double)seg->y1 * PitchY;
y = (int)((REPS(dc)) * oscale);
if (lnode->flags & NI_STUB_NS)
dc += stub;
@@ -1008,13 +1122,12 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
// ones. If necessary, a flag can be added to
// distinguish routes from taps.
- if ((x < x2) && (seg->x1 < (NumChannelsX[layer] - 1))) {
+ if ((x < x2) && (seg->x1 < (NumChannelsX - 1))) {
tdir = OBSVAL(seg->x1 + 1, seg->y1, layer);
if ((tdir & ROUTED_NET_MASK) ==
(net->netnum | ROUTED_NET)) {
- if (stub + LefGetRouteKeepout(layer) >= PitchX[layer]) {
- dc = Xlowerbound + (double)(seg->x1 + 1)
- * PitchX[layer];
+ if (stub + LefGetRouteKeepout(layer) >= PitchX) {
+ dc = Xlowerbound + (double)(seg->x1 + 1) * PitchX;
x2 = (int)((REPS(dc)) * oscale);
}
}
@@ -1023,9 +1136,8 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
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];
+ if (-stub + LefGetRouteKeepout(layer) >= PitchX) {
+ dc = Xlowerbound + (double)(seg->x1 - 1) * PitchX;
x2 = (int)((REPS(dc)) * oscale);
}
}
@@ -1066,13 +1178,12 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
// other route, then lengthen it to close up the
// distance and resolve the error.
- if ((y < y2) && (seg->y1 < (NumChannelsY[layer] - 1))) {
+ if ((y < y2) && (seg->y1 < (NumChannelsY - 1))) {
tdir = OBSVAL(seg->x1, seg->y1 + 1, layer);
if ((tdir & ROUTED_NET_MASK) ==
(net->netnum | ROUTED_NET)) {
- if (stub + LefGetRouteKeepout(layer) >= PitchY[layer]) {
- dc = Ylowerbound + (double)(seg->y1 + 1)
- * PitchY[layer];
+ if (stub + LefGetRouteKeepout(layer) >= PitchY) {
+ dc = Ylowerbound + (double)(seg->y1 + 1) * PitchY;
y2 = (int)((REPS(dc)) * oscale);
}
}
@@ -1081,9 +1192,8 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
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];
+ if (-stub + LefGetRouteKeepout(layer) >= PitchY) {
+ dc = Ylowerbound + (double)(seg->y1 - 1) * PitchY;
y2 = (int)((REPS(dc)) * oscale);
}
}
@@ -1119,8 +1229,9 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
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);
+ pathstart(Cmd, layer, x2, y2, special, oscale, invscale, horizontal,
+ lnode);
+ pathto(Cmd, x, y, horizontal, x2, y2, invscale, nextvia);
}
lastx = x;
lasty = y;
@@ -1131,6 +1242,7 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
prevseg = NULL;
lastseg = NULL;
for (seg = rt->segments; seg; seg = seg->next) {
+ nextvia = (seg->next) ? ((seg->next->segtype == ST_VIA) ? 1 : 0) : 0;
layer = seg->layer;
// Check for offset terminals at either point
@@ -1139,6 +1251,7 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
offset2 = 0.0;
dir1 = 0;
dir2 = 0;
+ lnode1 = lnode2 = NULL;
if (seg->segtype & ST_OFFSET_START) {
dir1 = OBSVAL(seg->x1, seg->y1, seg->layer) & OFFSET_TAP;
@@ -1224,16 +1337,16 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
// and are redundant between CIFLayer[] from the
// config file and lefInfo.
- dc = Xlowerbound + (double)seg->x1 * PitchX[layer];
+ dc = Xlowerbound + (double)seg->x1 * PitchX;
if ((dir1 & OFFSET_TAP) && (lnode1->flags & NI_OFFSET_EW)) dc += offset1;
x = (int)((REPS(dc)) * oscale);
- dc = Ylowerbound + (double)seg->y1 * PitchY[layer];
+ dc = Ylowerbound + (double)seg->y1 * PitchY;
if ((dir1 & OFFSET_TAP) && (lnode1->flags & NI_OFFSET_NS)) dc += offset1;
y = (int)((REPS(dc)) * oscale);
- dc = Xlowerbound + (double)seg->x2 * PitchX[layer];
+ dc = Xlowerbound + (double)seg->x2 * PitchX;
if ((dir2 & OFFSET_TAP) && (lnode2->flags & NI_OFFSET_EW)) dc += offset2;
x2 = (int)((REPS(dc)) * oscale);
- dc = Ylowerbound + (double)seg->y2 * PitchY[layer];
+ dc = Ylowerbound + (double)seg->y2 * PitchY;
if ((dir2 & OFFSET_TAP) && (lnode2->flags & NI_OFFSET_NS)) dc += offset2;
y2 = (int)((REPS(dc)) * oscale);
segtype = seg->segtype & ~(ST_OFFSET_START | ST_OFFSET_END);
@@ -1273,12 +1386,26 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
/* Add bend and connect to offset via */
int vertical = (horizontal) ? FALSE : TRUE;
pathstart(Cmd, seg->layer, lastx, lasty, special,
- oscale, invscale, vertical);
- pathto(Cmd, x, y, vertical, lastx, lasty, invscale);
+ oscale, invscale, vertical, lnode2);
+ pathto(Cmd, x, y, vertical, lastx, lasty, invscale, nextvia);
+ }
+ else if (lastseg && (lastseg->segtype & ST_VIA) &&
+ (lastx != x) && (lasty == y) &&
+ (LefGetRouteOrientation(seg->layer) == 1)) {
+ /* Via offset in direction of route (horizontal) */
+ pathstart(Cmd, seg->layer, lastx, y, special, oscale,
+ invscale, horizontal, lnode2);
+ }
+ else if (lastseg && (lastseg->segtype & ST_VIA) &&
+ (lastx == x) && (lasty != y) &&
+ (LefGetRouteOrientation(seg->layer) == 0)) {
+ /* Via offset in direction of route (vertical) */
+ pathstart(Cmd, seg->layer, x, lasty, special, oscale,
+ invscale, horizontal, lnode2);
}
else {
pathstart(Cmd, seg->layer, x, y, special, oscale,
- invscale, horizontal);
+ invscale, horizontal, lnode2);
}
lastx = x;
lasty = y;
@@ -1296,17 +1423,26 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
horizontal = FALSE;
}
if (special == (u_char)0) {
- pathto(Cmd, x2, y2, horizontal, lastx, lasty, invscale);
+ pathto(Cmd, x2, y2, horizontal, lastx, lasty, invscale, nextvia);
lastx = x2;
lasty = y2;
}
+ // Check for path segments that are used for minimum metal
+ // area requirements so that they do not become false
+ // positives for inter-via special nets.
+
+ if (lastseg && seg->next && (lastseg->x1 == seg->next->x2) &&
+ (lastseg->y1 == seg->next->y2))
+ seg->segtype |= ST_MINMETAL;
+
// If a segment is 1 track long, there is a via on either
// end, and the needblock flag is set for the layer, then
// draw a stub route along the length of the track.
if (horizontal && needblock[seg->layer] & VIABLOCKX) {
- if (ABSDIFF(seg->x2, seg->x1) == 1) {
+ if ((ABSDIFF(seg->x2, seg->x1) == 1) &&
+ !(seg->segtype & ST_MINMETAL)) {
if ((lastseg && lastseg->segtype == ST_VIA) ||
(seg->next && seg->next->segtype == ST_VIA)) {
if (special == (u_char)0) {
@@ -1316,15 +1452,16 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
else {
if (Pathon != -1) Pathon = 0;
pathstart(Cmd, layer, x, y, special, oscale,
- invscale, horizontal);
- pathto(Cmd, x2, y2, horizontal, x, y, invscale);
+ invscale, horizontal, lnode2);
+ pathto(Cmd, x2, y2, horizontal, x, y, invscale, 0);
lastlay = layer;
}
}
}
}
else if (!horizontal && needblock[seg->layer] & VIABLOCKY) {
- if (ABSDIFF(seg->y2, seg->y1) == 1) {
+ if ((ABSDIFF(seg->y2, seg->y1) == 1) &&
+ !(seg->segtype & ST_MINMETAL)) {
if ((lastseg && lastseg->segtype == ST_VIA) ||
(seg->next && seg->next->segtype == ST_VIA)) {
if (special == (u_char)0) {
@@ -1334,25 +1471,36 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
else {
if (Pathon != -1) Pathon = 0;
pathstart(Cmd, layer, x, y, special, oscale,
- invscale, horizontal);
- pathto(Cmd, x2, y2, horizontal, x, y, invscale);
+ invscale, horizontal, lnode2);
+ pathto(Cmd, x2, y2, horizontal, x, y, invscale, 0);
lastlay = layer;
}
}
}
}
break;
+
case ST_VIA:
rt->flags |= RT_OUTPUT;
if (special == (u_char)0) {
double viaoffx, viaoffy;
+ double w0, w1, dc, altwx, altwy;
+ float offsetx, offsety;
int vx = 0;
int vy = 0;
+ int flags;
u_int tdirpp, tdirp, tdirn;
u_char viaNL, viaNM, viaNU;
u_char viaSL, viaSM, viaSU;
u_char viaEL, viaEM, viaEU;
u_char viaWL, viaWM, viaWU;
+ u_char rteNL, rteNU;
+ u_char rteSL, rteSU;
+ u_char rteEL, rteEU;
+ u_char rteWL, rteWU;
+ char *s;
+ char checkersign;
+ int ob, ot;
if (lastseg == NULL) {
// Make sure last position is valid
@@ -1360,197 +1508,702 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
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;
+ // If vias need to be rotated then they do so on a
+ // checkerboard pattern.
+ checkersign = (char)((seg->x1 + seg->y1) & 0x01);
+
+ // Get the default orientation of the via
+ ob = LefGetRouteOrientation(layer);
+ ot = LefGetRouteOrientation(layer + 1);
+ if (ob == 0 && ot == 1)
+ s = ViaYX[layer];
+ else if (ob == 1 && ot == 0)
+ s = ViaXY[layer];
+ else if (ob == 0 && ot == 0)
+ s = ViaYY[layer];
+ else
+ s = ViaXX[layer];
+
+ // If via is on a pin and rotation is restricted, then
+ // set the rotation accordingly.
+
+ flags = 0;
+ if (layer < Pinlayers) {
+ if ((lnode = NODEIPTR(seg->x1, seg->y1, layer)) != NULL) {
+ if (lnode->flags & NI_NO_VIAX) {
+ flags = NI_NO_VIAX;
+ if (s == ViaXY[layer])
+ s = ViaYY[layer];
+ else if (s == ViaXX[layer])
+ s = ViaYX[layer];
+ }
+ if (lnode->flags & NI_NO_VIAY) {
+ flags = NI_NO_VIAY;
+ if (s == ViaYX[layer])
+ s = ViaXX[layer];
+ else if (s == ViaYY[layer])
+ s = ViaXY[layer];
+ }
+ /* Mark the node with which via direction was used */
+ if ((s == ViaYY[layer]) || (s == ViaYX[layer]))
+ lnode->flags |= NI_VIA_Y;
+ else
+ lnode->flags |= NI_VIA_X;
+ }
+ }
- // Check for via to west
- if (seg->x1 > 0) {
- tdir = OBSVAL(seg->x1 - 1, seg->y1, layer)
+ // Check for vias between adjacent but different nets
+ // that need rotation and/or position offsets to avoid
+ // a DRC spacing error
+
+ viaEL = viaEM = viaEU = 0;
+ viaWL = viaWM = viaWU = 0;
+ viaNL = viaNM = viaNU = 0;
+ viaSL = viaSM = viaSU = 0;
+ rteEL = rteEU = rteWL = rteWU = 0;
+ rteNL = rteNU = rteSL = rteSU = 0;
+
+ // Check for via/route to west
+ if (seg->x1 > 0) {
+ tdir = OBSVAL(seg->x1 - 1, seg->y1, layer)
& ROUTED_NET_MASK;
- if (((tdir & NO_NET) == 0) && (tdir != 0) &&
+ if (((tdir & NO_NET) == 0) && (tdir != 0) &&
(tdir != (net->netnum | ROUTED_NET))) {
+ rteWL = 1;
+ if (layer > 0) {
+ tdirn = OBSVAL(seg->x1 - 1, seg->y1, layer - 1)
+ & ROUTED_NET_MASK;
+ if (tdir == tdirn) viaWL = 1;
+ }
+ }
- if (layer < Num_layers - 1) {
- tdirp = OBSVAL(seg->x1 - 1, seg->y1, layer + 1)
+ if (layer < Num_layers - 1) {
+ tdirp = OBSVAL(seg->x1 - 1, seg->y1, layer + 1)
& ROUTED_NET_MASK;
- if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
+ 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)
+ rteWU = 1;
+ if (layer < Num_layers - 2) {
+ tdirpp = OBSVAL(seg->x1 - 1, seg->y1, layer + 2)
& ROUTED_NET_MASK;
- if (tdirp == tdirpp) viaWU = 1;
- }
- }
- if (tdir == tdirp) viaWM = 1;
- }
-
- if (layer > 0) {
- tdirn = OBSVAL(seg->x1 - 1, seg->y1, layer - 1)
- & ROUTED_NET_MASK;
- if (tdir == tdirn) viaWL = 1;
+ if (tdirp == tdirpp) viaWU = 1;
}
}
+ if (rteWL && (tdir == tdirp)) viaWM = 1;
}
+ }
- // Check for via to east
- if (seg->x1 < NumChannelsX[layer] - 1) {
- tdir = OBSVAL(seg->x1 + 1, seg->y1, layer)
+ // Check for via/route to east
+ if (seg->x1 < NumChannelsX - 1) {
+ tdir = OBSVAL(seg->x1 + 1, seg->y1, layer)
& ROUTED_NET_MASK;
- if (((tdir & NO_NET) == 0) && (tdir != 0) &&
+ if (((tdir & NO_NET) == 0) && (tdir != 0) &&
(tdir != (net->netnum | ROUTED_NET))) {
+ rteEL = 1;
+ if (layer > 0) {
+ tdirn = OBSVAL(seg->x1 + 1, seg->y1, layer - 1)
+ & ROUTED_NET_MASK;
+ if (tdir == tdirn) viaEL = 1;
+ }
+ }
- if (layer < Num_layers - 1) {
- tdirp = OBSVAL(seg->x1 + 1, seg->y1, layer + 1)
+ if (layer < Num_layers - 1) {
+ tdirp = OBSVAL(seg->x1 + 1, seg->y1, layer + 1)
& ROUTED_NET_MASK;
- if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
+ 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)
+ rteEU = 1;
+ if (layer < Num_layers - 2) {
+ tdirpp = OBSVAL(seg->x1 + 1, seg->y1, layer + 2)
& ROUTED_NET_MASK;
- if (tdirp == tdirpp) viaEU = 1;
- }
- }
- if (tdir == tdirp) viaEM = 1;
- }
-
- if (layer > 0) {
- tdirn = OBSVAL(seg->x1 + 1, seg->y1, layer - 1)
- & ROUTED_NET_MASK;
- if (tdir == tdirn) viaEL = 1;
+ if (tdirp == tdirpp) viaEU = 1;
}
}
+ if (rteEL && (tdir == tdirp)) viaEM = 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)
+ // Check for via/route to south
+ if (seg->y1 > 0) {
+ tdir = OBSVAL(seg->x1, seg->y1 - 1, layer)
& ROUTED_NET_MASK;
- if (((tdir & NO_NET) == 0) && (tdir != 0) &&
+ if (((tdir & NO_NET) == 0) && (tdir != 0) &&
(tdir != (net->netnum | ROUTED_NET))) {
+ rteSL = 1;
+ if (layer > 0) {
+ tdirn = OBSVAL(seg->x1, seg->y1 - 1, layer - 1)
+ & ROUTED_NET_MASK;
+ if (tdir == tdirn) viaSL = 1;
+ }
+ }
- if (layer < Num_layers - 1) {
- tdirp = OBSVAL(seg->x1, seg->y1 - 1, layer + 1)
+ if (layer < Num_layers - 1) {
+ tdirp = OBSVAL(seg->x1, seg->y1 - 1, layer + 1)
& ROUTED_NET_MASK;
- if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
+ 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)
+ rteSU = 1;
+ if (layer < Num_layers - 2) {
+ tdirpp = OBSVAL(seg->x1, seg->y1 - 1, layer + 2)
& ROUTED_NET_MASK;
- if (tdirp == tdirpp) viaSU = 1;
- }
- }
- if (tdir == tdirp) viaSM = 1;
- }
-
- if (layer > 0) {
- tdirn = OBSVAL(seg->x1, seg->y1 - 1, layer - 1)
- & ROUTED_NET_MASK;
- if (tdir == tdirn) viaSL = 1;
+ if (tdirp == tdirpp) viaSU = 1;
}
}
+ if (rteSL && (tdir == tdirp)) viaSM = 1;
}
+ }
- // Check for via to north
- if (seg->y1 < NumChannelsY[layer] - 1) {
- tdir = OBSVAL(seg->x1, seg->y1 + 1, layer)
+ // Check for via/route to north
+ if (seg->y1 < NumChannelsY - 1) {
+ tdir = OBSVAL(seg->x1, seg->y1 + 1, layer)
& ROUTED_NET_MASK;
- if (((tdir & NO_NET) == 0) && (tdir != 0) &&
+ if (((tdir & NO_NET) == 0) && (tdir != 0) &&
(tdir != (net->netnum | ROUTED_NET))) {
+ rteNL = 1;
+ if (layer > 0) {
+ tdirn = OBSVAL(seg->x1, seg->y1 + 1, layer - 1)
+ & ROUTED_NET_MASK;
+ if (tdir == tdirn) viaNL = 1;
+ }
+ }
- if (layer < Num_layers - 1) {
- tdirp = OBSVAL(seg->x1, seg->y1 + 1, layer + 1)
+ if (layer < Num_layers - 1) {
+ tdirp = OBSVAL(seg->x1, seg->y1 + 1, layer + 1)
& ROUTED_NET_MASK;
- if (((tdirp & NO_NET) == 0) && (tdirp != 0) &&
+ 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)
+ rteNU = 1;
+ if (layer < Num_layers - 2) {
+ tdirpp = OBSVAL(seg->x1, seg->y1 + 1, layer + 2)
& ROUTED_NET_MASK;
- if (tdirp == tdirpp) viaNU = 1;
- }
- }
- if (tdir == tdirp) viaNM = 1;
- }
-
- if (layer > 0) {
- tdirn = OBSVAL(seg->x1, seg->y1 + 1, layer - 1)
- & ROUTED_NET_MASK;
- if (tdir == tdirn) viaNL = 1;
+ if (tdirp == tdirpp) viaNU = 1;
}
}
+ if (rteNL && (tdir == tdirp)) viaNM = 1;
}
+ }
- // Compute Y offset
- viaoffy = 0;
+ // Check for any tap offset on the neighboring via,
+ // which needs to be accounted for in the calculations.
+ offsetx = offsety = 0.0;
+ if (viaEL)
+ lnode = (layer < Pinlayers && layer > 0) ?
+ NODEIPTR(seg->x1 + 1, seg->y1, layer - 1) : NULL;
+ else if (viaWL)
+ lnode = (layer < Pinlayers && layer > 0) ?
+ NODEIPTR(seg->x1 - 1, seg->y1, layer - 1) : NULL;
+ else if (viaEM)
+ lnode = (layer < Pinlayers) ?
+ NODEIPTR(seg->x1 + 1, seg->y1, layer) : NULL;
+ else if (viaWM)
+ lnode = (layer < Pinlayers) ?
+ NODEIPTR(seg->x1 - 1, seg->y1, layer) : NULL;
+ else if (viaEU)
+ lnode = (layer < Pinlayers - 1) ?
+ NODEIPTR(seg->x1 + 1, seg->y1, layer + 1) : NULL;
+ else if (viaWU)
+ lnode = (layer < Pinlayers - 1) ?
+ NODEIPTR(seg->x1 - 1, seg->y1, layer + 1) : NULL;
+
+ if (lnode && (lnode->flags & NI_OFFSET_EW)) {
+ offsetx = lnode->offset;
+ // offsetx defined as positive in the direction away from
+ // the via under consideration.
+ if (viaWL || viaWM || viaWU) offsetx = -offsetx;
+ }
- if (viaSL) viaoffy = viaOffsetY[layer][0];
- else if (viaNL) viaoffy = -viaOffsetY[layer][0];
+ if (viaNL)
+ lnode = (layer < Pinlayers && layer > 0) ?
+ NODEIPTR(seg->x1, seg->y1 + 1, layer - 1) : NULL;
+ else if (viaSL)
+ lnode = (layer < Pinlayers && layer > 0) ?
+ NODEIPTR(seg->x1, seg->y1 - 1, layer - 1) : NULL;
+ else if (viaNM)
+ lnode = (layer < Pinlayers) ?
+ NODEIPTR(seg->x1, seg->y1 + 1, layer) : NULL;
+ else if (viaSM)
+ lnode = (layer < Pinlayers) ?
+ NODEIPTR(seg->x1, seg->y1 - 1, layer) : NULL;
+ else if (viaNU)
+ lnode = (layer < Pinlayers - 1) ?
+ NODEIPTR(seg->x1, seg->y1 + 1, layer + 1) : NULL;
+ else if (viaSU)
+ lnode = (layer < Pinlayers - 1) ?
+ NODEIPTR(seg->x1, seg->y1 - 1, layer + 1) : NULL;
+
+ if (lnode && (lnode->flags & NI_OFFSET_NS)) {
+ offsety = lnode->offset;
+ // offsety defined as positive in the direction away from
+ // the via under consideration.
+ if (viaSL || viaSM || viaSU) offsety = -offsety;
+ }
+
+ // Actions needed only if a via is on the long side and
+ // has a spacing violation.
+
+ viaoffx = viaoffy = 0.0;
+ altwx = altwy = 0.0;
+ if (ob == 1) { /* bottom (layer) route is horizontal */
+ if (viaEM || viaWM) {
+ /* Assume default rotations and calculate spacing */
+ /* Only take action if there is a spacing violation */
+
+ w1 = LefGetXYViaWidth(layer, layer, 0, 0);
+ w0 = w1;
+ dc = LefGetRouteSpacing(layer) + w1;
+ if (dc > PitchX + EPS + offsetx) {
+
+ /* via on checkerboard may be rotated */
+ if (checkersign && ((flags & NI_NO_VIAY) == 0)) {
+ /* Check spacing violation to routes N and S */
+ /* If via being checked is rotated */
+ if (rteNL || rteSL)
+ dc = LefGetRouteSpacing(layer) +
+ (LefGetXYViaWidth(layer, layer, 1, 2) +
+ LefGetRouteWidth(layer)) / 2;
+ if ((!(rteNL || rteSL))
+ || (dc <= PitchY + EPS)) {
+ /* Okay to rotate the via bottom */
+ w0 = LefGetXYViaWidth(layer, layer, 0, 2);
+ s = (ot == 1) ? ViaYX[layer] : ViaYY[layer];
+ }
+ else if (rteNL || rteSL)
+ altwx = w1 -
+ LefGetXYViaWidth(layer, layer, 0, 2);
+
+ /* Measure spacing violation to via */
+ dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
+ if (dc > PitchX + EPS + offsetx) {
+ /* Calculate offset */
+ if (viaEM)
+ viaoffx = PitchX + 2 * offsetx - dc;
+ else
+ viaoffx = dc - PitchX - 2 * offsetx;
+ }
+ }
+ else {
+ /* Measure spacing violation to rotated via */
+ w0 = LefGetXYViaWidth(layer, layer, 0, 2);
+ dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
+ if (dc > PitchX + EPS + offsetx) {
+ /* Calculate offset */
+ if (viaEM)
+ viaoffx = PitchX + 2 * offsetx - dc;
+ else
+ viaoffx = dc - PitchX - 2 * offsetx;
+ }
+ }
+ }
+ }
+ else if (viaEL || viaWL) {
+ /* Assume default rotations and calculate spacing */
+ /* Only take action if there is a spacing violation */
+
+ w0 = LefGetXYViaWidth(layer - 1, layer, 0, 0);
+ w1 = LefGetXYViaWidth(layer, layer, 0, 0);
+ dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
+ if (dc > PitchX + EPS + offsetx) {
+
+ /* via on checkerboard may be rotated */
+ if (checkersign && ((flags & NI_NO_VIAY) == 0)) {
+ /* Check spacing violation to routes N and S */
+ /* If via being checked is rotated */
+ if (rteNL || rteSL)
+ dc = LefGetRouteSpacing(layer) +
+ (LefGetXYViaWidth(layer, layer, 1, 2) +
+ LefGetRouteWidth(layer)) / 2;
+ if ((!(rteNL || rteSL))
+ || (dc <= PitchY + EPS)) {
+ /* Okay to rotate the via bottom */
+ w1 = LefGetXYViaWidth(layer, layer, 0, 2);
+ s = (ot == 1) ? ViaYX[layer] : ViaYY[layer];
+ }
+ else if (rteNL || rteSL)
+ altwx = w1 -
+ LefGetXYViaWidth(layer, layer, 0, 2);
+
+ /* Measure spacing violation to via */
+ dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
+ if (dc > PitchX + EPS + offsetx) {
+ /* Calculate offset */
+ if (viaEL)
+ viaoffx = PitchX + 2 * offsetx - dc;
+ else
+ viaoffx = dc - PitchX - 2 * offsetx;
+ }
+ }
+ else {
+ /* Measure spacing violation to rotated via */
+ w0 = LefGetXYViaWidth(layer - 1, layer, 0, 1);
+ dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
+ if (dc > PitchX + EPS + offsetx) {
+ /* Calculate offset */
+ if (viaEL)
+ viaoffx = PitchX + 2 * offsetx - dc;
+ else
+ viaoffx = dc - PitchX - 2 * offsetx;
+ }
+ }
+ }
+ }
+ } else { /* bottom route vertical */
+ if (viaNM || viaSM) {
+ /* Assume default rotations and calculate spacing */
+ /* Only take action if there is a spacing violation */
+
+ w1 = LefGetXYViaWidth(layer, layer, 1, 3);
+ w0 = w1;
+ dc = LefGetRouteSpacing(layer) + w1;
+ if (dc > PitchY + EPS + offsety) {
+
+ /* via on checkerboard may be rotated */
+ if (checkersign && ((flags & NI_NO_VIAX) == 0)) {
+ /* Check spacing violation to routes E and W */
+ /* If via being checked is rotated */
+ if (rteEL || rteWL)
+ dc = LefGetRouteSpacing(layer) +
+ (LefGetXYViaWidth(layer, layer, 0, 1) +
+ LefGetRouteWidth(layer)) / 2;
+ if ((!(rteEL || rteWL))
+ || (dc <= PitchX + EPS)) {
+ /* Okay to rotate the via bottom */
+ w0 = LefGetXYViaWidth(layer, layer, 1, 1);
+ s = (ot == 1) ? ViaXX[layer] : ViaXY[layer];
+ }
+ else if (rteEL || rteWL)
+ altwy = w1 -
+ LefGetXYViaWidth(layer, layer, 1, 1);
+
+ /* Measure spacing violation to via */
+ dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
+ if (dc > PitchY + EPS + offsety) {
+ /* Calculate offset */
+ if (viaNM)
+ viaoffy = PitchY + 2 * offsety - dc;
+ else
+ viaoffy = dc - PitchY - 2 * offsety;
+ }
+ }
+ else {
+ /* Measure spacing violation to rotated via */
+ w0 = LefGetXYViaWidth(layer, layer, 1, 1);
+ dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
+ if (dc > PitchY + EPS + offsety) {
+ /* Calculate offset */
+ if (viaNM)
+ viaoffy = PitchY + 2 * offsety - dc;
+ else
+ viaoffy = dc - PitchY - 2 * offsety;
+ }
+ }
+ }
+ }
+ else if (viaNL || viaSL) {
+ /* Assume default rotations and calculate spacing */
+ /* Only take action if there is a spacing violation */
+
+ w0 = LefGetXYViaWidth(layer - 1, layer, 1, 3);
+ w1 = LefGetXYViaWidth(layer, layer, 1, 3);
+ dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
+ if (dc > PitchY + EPS + offsety) {
+
+ /* via on checkerboard may be rotated */
+ if (checkersign && ((flags & NI_NO_VIAX) == 0)) {
+ /* Check spacing violation to routes E and W */
+ /* If via being checked is rotated */
+ if (rteEL || rteWL)
+ dc = LefGetRouteSpacing(layer) +
+ (LefGetXYViaWidth(layer, layer, 0, 1) +
+ LefGetRouteWidth(layer)) / 2;
+ if ((!(rteEL || rteWL))
+ || (dc <= PitchX + EPS)) {
+ /* Okay to rotate the via bottom */
+ w1 = LefGetXYViaWidth(layer, layer, 1, 1);
+ s = (ot == 1) ? ViaXX[layer] : ViaXY[layer];
+ }
+ else if (rteEL || rteWL)
+ altwy = w1 -
+ LefGetXYViaWidth(layer, layer, 1, 1);
+
+ /* Measure spacing violation to via */
+ dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
+ if (dc > PitchY + EPS + offsety) {
+ /* Calculate offset */
+ if (viaNL)
+ viaoffy = PitchY + 2 * offsety - dc;
+ else
+ viaoffy = dc - PitchY - 2 * offsety;
+ }
+ }
+ else {
+ /* Measure spacing violation to rotated via */
+ w0 = LefGetXYViaWidth(layer - 1, layer, 1, 2);
+ dc = LefGetRouteSpacing(layer) + (w1 + w0) / 2;
+ if (dc > PitchY + EPS + offsety) {
+ /* Calculate offset */
+ if (viaNL)
+ viaoffy = PitchY + 2 * offsety - dc;
+ else
+ viaoffy = dc - PitchY - 2 * offsety;
+ }
+ }
+ }
+ }
+ }
- if (viaSM && viaOffsetY[layer][1] > viaoffy)
- viaoffy = viaOffsetY[layer][1];
- else if (viaNM && -viaOffsetY[layer][1] < viaoffy)
- viaoffy = -viaOffsetY[layer][1];
+ if (ot == 1) { /* top route horizontal */
+ if (viaEU || viaWU) {
+ /* Assume default rotations and calculate spacing */
+ /* Only take action if there is a spacing violation */
+
+ w0 = LefGetXYViaWidth(layer + 1, layer + 1, 0, 0);
+ w1 = LefGetXYViaWidth(layer, layer + 1, 0, 0);
+ dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
+ if (dc > PitchX + EPS + offsetx) {
+
+ /* via on checkerboard may be rotated */
+ if (checkersign) {
+ /* Check spacing violation to routes N and S */
+ /* If via being checked is rotated */
+ if (rteNU || rteSU)
+ dc = LefGetRouteSpacing(layer + 1) +
+ (LefGetXYViaWidth(layer, layer + 1, 1, 1)
+ + LefGetRouteWidth(layer + 1)) / 2;
+ if ((!(rteNU || rteSU))
+ || (dc <= PitchY + EPS)) {
+ /* Okay to rotate the via top */
+ w1 = LefGetXYViaWidth(layer, layer + 1, 0, 1);
+ s = (s == ViaYX[layer]) ? ViaYY[layer] :
+ ViaXY[layer];
+ }
+ else if (rteNU || rteSU)
+ altwx = w1 -
+ LefGetXYViaWidth(layer, layer + 1, 0, 1);
+
+ /* Measure spacing violation to via */
+ dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
+ if (dc > PitchX + EPS + offsetx) {
+ /* Calculate offset */
+ if (viaEU)
+ viaoffx = PitchX + 2 * offsetx - dc;
+ else
+ viaoffx = dc - PitchX - 2 * offsetx;
+ }
+ }
+ else {
+ /* Measure spacing violation to rotated via */
+ w0 = LefGetXYViaWidth(layer + 1, layer + 1, 0, 2);
+ dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
+ if (dc > PitchX + EPS + offsetx) {
+ /* Calculate offset */
+ if (viaEU)
+ viaoffx = PitchX + 2 * offsetx - dc;
+ else
+ viaoffx = dc - PitchX - 2 * offsetx;
+ }
+ }
+ }
+ }
+ else if (viaEM || viaWM) {
+ /* Assume default rotations and calculate spacing */
+ /* Only take action if there is a spacing violation */
+
+ w1 = LefGetXYViaWidth(layer, layer + 1, 0, 0);
+ w0 = w1;
+ dc = LefGetRouteSpacing(layer + 1) + w1;
+ if (dc > PitchX + EPS + offsetx) {
+
+ /* via on checkerboard may be rotated */
+ if (checkersign) {
+ /* Check spacing violation to routes N and S */
+ /* If via being checked is rotated */
+ if (rteNU || rteSU)
+ dc = LefGetRouteSpacing(layer) +
+ (LefGetXYViaWidth(layer, layer + 1, 1, 1)
+ + LefGetRouteWidth(layer)) / 2;
+ if ((!(rteNU || rteSU)) || (dc <= PitchY + EPS)) {
+ /* Okay to rotate the via top */
+ w0 = LefGetXYViaWidth(layer, layer + 1, 0, 1);
+ s = (s == ViaYX[layer]) ? ViaYY[layer] :
+ ViaXY[layer];
+ }
+ else if (rteNU || rteSU)
+ altwx = w1 -
+ LefGetXYViaWidth(layer, layer + 1, 0, 1);
+
+ /* Measure spacing violation to via */
+ dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
+ if (dc > PitchX + EPS + offsetx) {
+ /* Calculate offset */
+ if (viaEM)
+ viaoffx = PitchX + 2 * offsetx - dc;
+ else
+ viaoffx = dc - PitchX - 2 * offsetx;
+ }
+ }
+ else {
+ /* Measure spacing violation to rotated via */
+ w0 = LefGetXYViaWidth(layer, layer + 1, 0, 1);
+ dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
+ if (dc > PitchX + EPS + offsetx) {
+ /* Calculate offset */
+ if (viaEM)
+ viaoffx = PitchX + 2 * offsetx - dc;
+ else
+ viaoffx = dc - PitchX - 2 * offsetx;
+ }
+ }
+ }
+ }
+ } else { /* top route vertical */
+ if (viaNU || viaSU) {
+ /* Assume default rotations and calculate spacing */
+ /* Only take action if there is a spacing violation */
+
+ w0 = LefGetXYViaWidth(layer + 1, layer + 1, 1, 3);
+ w1 = LefGetXYViaWidth(layer, layer + 1, 1, 3);
+ dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
+ if (dc > PitchY + EPS + offsety) {
+
+ /* via on checkerboard may be rotated */
+ if (checkersign) {
+ /* Check spacing violation to routes E and W */
+ /* If via being checked is rotated */
+ if (rteEU || rteWU)
+ dc = LefGetRouteSpacing(layer + 1) +
+ (LefGetXYViaWidth(layer, layer + 1, 0, 2)
+ + LefGetRouteWidth(layer + 1)) / 2;
+ if ((!(rteEU || rteWU))
+ || (dc <= PitchX + EPS)) {
+ /* Okay to rotate the via top */
+ w1 = LefGetXYViaWidth(layer, layer + 1, 1, 2);
+ s = (s == ViaYY[layer]) ? ViaYX[layer] :
+ ViaXX[layer];
+ }
+ else if (rteEU || rteWU)
+ altwy = w1 -
+ LefGetXYViaWidth(layer, layer + 1, 1, 2);
+
+ /* Measure spacing violation to via */
+ dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
+ if (dc > PitchY + EPS + offsety) {
+ /* Calculate offset */
+ if (viaNU)
+ viaoffy = PitchY + 2 * offsety - dc;
+ else
+ viaoffy = dc - PitchY - 2 * offsety;
+ }
+ }
+ else {
+ /* Measure spacing violation to rotated via */
+ w0 = LefGetXYViaWidth(layer + 1, layer + 1, 1, 1);
+ dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
+ if (dc > PitchY + EPS + offsety) {
+ /* Calculate offset */
+ if (viaNU)
+ viaoffy = PitchY + 2 * offsety - dc;
+ else
+ viaoffy = dc - PitchY - 2 * offsety;
+ }
+ }
+ }
+ }
+ else if (viaNM || viaSM) {
+ /* Assume default rotations and calculate spacing */
+ /* Only take action if there is a spacing violation */
+
+ w1 = LefGetXYViaWidth(layer, layer + 1, 1, 3);
+ w0 = w1;
+ dc = LefGetRouteSpacing(layer + 1) + w1;
+ if (dc > PitchY + EPS + offsety) {
+
+ /* via on checkerboard may be rotated */
+ if (checkersign) {
+ /* Check spacing violation to routes E and W */
+ /* If via being checked is rotated */
+ if (rteEU || rteWU)
+ dc = LefGetRouteSpacing(layer + 1) +
+ (LefGetXYViaWidth(layer, layer + 1, 0, 2)
+ + LefGetRouteWidth(layer + 1)) / 2;
+ if ((!(rteEU || rteWU))
+ || (dc <= PitchX + EPS)) {
+ /* Okay to rotate the via top */
+ w1 = LefGetXYViaWidth(layer, layer + 1, 1, 2);
+ s = (s == ViaYY[layer]) ? ViaYX[layer] :
+ ViaXX[layer];
+ }
+ else if (rteEU || rteWU)
+ altwy = w1 -
+ LefGetXYViaWidth(layer, layer + 1, 1, 2);
+
+ /* Measure spacing violation to via */
+ dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
+ if (dc > PitchY + EPS + offsety) {
+ /* Calculate offset */
+ if (viaNM)
+ viaoffy = PitchY + 2 * offsety - dc;
+ else
+ viaoffy = dc - PitchY - 2 * offsety;
+ }
+ }
+ else {
+ /* Measure spacing violation to rotated via */
+ w0 = LefGetXYViaWidth(layer, layer + 1, 1, 2);
+ dc = LefGetRouteSpacing(layer + 1) + (w1 + w0) / 2;
+ if (dc > PitchY + EPS + offsety) {
+ /* Calculate offset */
+ if (viaNM)
+ viaoffy = PitchY + 2 * offsety - dc;
+ else
+ viaoffy = dc - PitchY - 2 * offsety;
+ }
+ }
+ }
+ }
+ }
- if (viaSU && viaOffsetY[layer][2] > viaoffy)
- viaoffy = viaOffsetY[layer][2];
- else if (viaNU && -viaOffsetY[layer][2] < viaoffy)
- viaoffy = -viaOffsetY[layer][2];
+ /* If a via is constrained by routes on the side */
+ /* and cannot be rotated, then the calculations on */
+ /* the via in the next track will not take that */
+ /* into consideration, and not leave enough space. */
+ /* So this via must offset more to make up the */
+ /* difference. */
- vy = (int)((REPS(viaoffy)) * oscale);
+ if (altwx > 0.0) {
+ if (viaoffx < 0) altwx = -altwx;
+ viaoffx += altwx;
+ }
+ if (altwy > 0.0) {
+ if (viaoffy < 0) altwy = -altwy;
+ viaoffy += altwy;
}
- // via-to-via interactions are symmetric, so move each
- // via half the distance (?)
+ /* When offset, each via moves by half the distance. */
+ viaoffx /= 2;
+ viaoffy /= 2;
- pathvia(Cmd, layer, x + vx, y + vy, lastx, lasty,
- seg->x1, seg->y1, invscale);
+ vx = (int)((REPS(viaoffx)) * oscale);
+ vy = (int)((REPS(viaoffy)) * oscale);
- lastx = x;
- lasty = y;
+ /* If via is offset in the direction of the last */
+ /* route segment, then move the last route segment */
+ /* position to the via center. */
+ if ((path_delayed.active == 1) && (vy != 0) &&
+ (path_delayed.orient == 0))
+ path_delayed.y = y + vy;
+
+ else if ((path_delayed.active == 1) && (vx != 0) &&
+ (path_delayed.orient == 1))
+ path_delayed.x = x + vx;
+
+ pathvia(Cmd, layer, x + vx, y + vy, lastx, lasty, s, invscale);
+
+ lastx = x + vx;
+ lasty = y + vy;
lastlay = -1;
}
break;
@@ -1608,20 +2261,20 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
if (prevseg->segtype & ST_VIA) {
- dc = Xlowerbound + (double)seg->x1 * PitchX[layer];
+ dc = Xlowerbound + (double)seg->x1 * PitchX;
x = (int)((REPS(dc)) * oscale);
- dc = Ylowerbound + (double)seg->y1 * PitchY[layer];
+ dc = Ylowerbound + (double)seg->y1 * PitchY;
y = (int)((REPS(dc)) * oscale);
- dc = Xlowerbound + (double)prevseg->x1 * PitchX[layer];
+ dc = Xlowerbound + (double)prevseg->x1 * PitchX;
x2 = (int)((REPS(dc)) * oscale);
- dc = Ylowerbound + (double)prevseg->y1 * PitchY[layer];
+ dc = Ylowerbound + (double)prevseg->y1 * PitchY;
y2 = (int)((REPS(dc)) * oscale);
// Setup is (via, 1 track route, via with offset)
if (prevseg->x1 != seg->x1) {
- if ((PitchX[lastseg->layer] -
+ if ((PitchX -
0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 1) -
0.5 * LefGetViaWidth(prevseg->layer, lastseg->layer, 1) -
(prevseg->x1 - seg->x1) * offset)
@@ -1632,15 +2285,15 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
}
else {
pathstart(Cmd, lastseg->layer, x, y,
- (u_char)1, oscale, invscale, 1);
- pathto(Cmd, x2, y2, 1, x, y, invscale);
+ (u_char)1, oscale, invscale, 1, lnode);
+ pathto(Cmd, x2, y2, 1, x, y, invscale, 0);
lastx = x2;
lasty = y2;
}
}
}
else if (prevseg->y1 != seg->y1) {
- if ((PitchY[lastseg->layer] -
+ if ((PitchY -
0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 0) -
0.5 * LefGetViaWidth(prevseg->layer, lastseg->layer, 0)
- (prevseg->y1 - seg->y1) * offset)
@@ -1651,8 +2304,8 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
}
else {
pathstart(Cmd, lastseg->layer, x, y,
- (u_char)1, oscale, invscale, 0);
- pathto(Cmd, x2, y2, 0, x, y, invscale);
+ (u_char)1, oscale, invscale, 0, lnode);
+ pathto(Cmd, x2, y2, 0, x, y, invscale, 0);
lastx = x2;
lasty = y2;
}
@@ -1661,7 +2314,7 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
}
else { // Metal route bends at next track
if (prevseg->x1 != seg->x1) {
- if ((PitchX[lastseg->layer] -
+ if ((PitchX -
0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 1) -
0.5 * LefGetRouteWidth(prevseg->layer) -
(prevseg->x1 - seg->x1) * offset)
@@ -1672,15 +2325,15 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
}
else {
pathstart(Cmd, lastseg->layer, x, y,
- (u_char)1, oscale, invscale, 1);
- pathto(Cmd, x2, y2, 1, x, y, invscale);
+ (u_char)1, oscale, invscale, 1, lnode);
+ pathto(Cmd, x2, y2, 1, x, y, invscale, 0);
lastx = x2;
lasty = y2;
}
}
}
else if (prevseg->y1 != seg->y1) {
- if ((PitchY[lastseg->layer] -
+ if ((PitchY -
0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 0) -
0.5 * LefGetRouteWidth(prevseg->layer) -
(prevseg->y1 - seg->y1) * offset)
@@ -1691,8 +2344,8 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
}
else {
pathstart(Cmd, lastseg->layer, x, y,
- (u_char)1, oscale, invscale, 0);
- pathto(Cmd, x2, y2, 0, x, y, invscale);
+ (u_char)1, oscale, invscale, 0, lnode);
+ pathto(Cmd, x2, y2, 0, x, y, invscale, 0);
lastx = x2;
lasty = y2;
}
@@ -1715,14 +2368,14 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
" at %d %d (%d)\n",
stub, seg->x2, seg->y2, layer);
- dc = Xlowerbound + (double)seg->x2 * PitchX[layer];
+ dc = Xlowerbound + (double)seg->x2 * PitchX;
if (lnode->flags & NI_OFFSET_EW)
dc += offset;
x = (int)((REPS(dc)) * oscale);
if (lnode->flags & NI_STUB_EW)
dc += stub;
x2 = (int)((REPS(dc)) * oscale);
- dc = Ylowerbound + (double)seg->y2 * PitchY[layer];
+ dc = Ylowerbound + (double)seg->y2 * PitchY;
if (lnode->flags & NI_OFFSET_NS)
dc += offset;
y = (int)((REPS(dc)) * oscale);
@@ -1738,13 +2391,12 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
// other route, then lengthen it to close up the
// distance and resolve the error.
- if ((x < x2) && (seg->x2 < (NumChannelsX[layer] - 1))) {
+ if ((x < x2) && (seg->x2 < (NumChannelsX - 1))) {
tdir = OBSVAL(seg->x2 + 1, seg->y2, layer);
if ((tdir & ROUTED_NET_MASK) ==
(net->netnum | ROUTED_NET)) {
- if (stub + LefGetRouteKeepout(layer) >= PitchX[layer]) {
- dc = Xlowerbound + (double)(seg->x2 + 1)
- * PitchX[layer];
+ if (stub + LefGetRouteKeepout(layer) >= PitchX) {
+ dc = Xlowerbound + (double)(seg->x2 + 1) * PitchX;
x2 = (int)((REPS(dc)) * oscale);
}
}
@@ -1753,9 +2405,8 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
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];
+ if (-stub + LefGetRouteKeepout(layer) >= PitchX) {
+ dc = Xlowerbound + (double)(seg->x2 - 1) * PitchX;
x2 = (int)((REPS(dc)) * oscale);
}
}
@@ -1796,13 +2447,12 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
// other route, then lengthen it to close up the
// distance and resolve the error.
- if ((y < y2) && (seg->y2 < (NumChannelsY[layer] - 1))) {
+ if ((y < y2) && (seg->y2 < (NumChannelsY - 1))) {
tdir = OBSVAL(seg->x2, seg->y2 + 1, layer);
if ((tdir & ROUTED_NET_MASK) ==
(net->netnum | ROUTED_NET)) {
- if (stub + LefGetRouteKeepout(layer) >= PitchY[layer]) {
- dc = Ylowerbound + (double)(seg->y2 + 1)
- * PitchY[layer];
+ if (stub + LefGetRouteKeepout(layer) >= PitchY) {
+ dc = Ylowerbound + (double)(seg->y2 + 1) * PitchY;
y2 = (int)((REPS(dc)) * oscale);
}
}
@@ -1811,9 +2461,8 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
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];
+ if (-stub + LefGetRouteKeepout(layer) >= PitchY) {
+ dc = Ylowerbound + (double)(seg->y2 - 1) * PitchY;
y2 = (int)((REPS(dc)) * oscale);
}
}
@@ -1850,11 +2499,11 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
rt->flags |= RT_STUB;
if (Pathon != 1) {
pathstart(Cmd, layer, x, y, special, oscale, invscale,
- horizontal);
+ horizontal, lnode);
lastx = x;
lasty = y;
}
- pathto(Cmd, x2, y2, horizontal, lastx, lasty, invscale);
+ pathto(Cmd, x2, y2, horizontal, lastx, lasty, invscale, 0);
lastx = x2;
lasty = y2;
}
@@ -1882,7 +2531,7 @@ emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale)
static void emit_routes(char *filename, double oscale, int iscale)
{
FILE *Cmd;
- int i, j, numnets, stubroutes;
+ int i, j, numnets, numvias, stubroutes;
char line[MAX_LINE_LEN + 1], *lptr = NULL;
char netname[MAX_NAME_LEN];
NET net = NULL;
@@ -1890,9 +2539,11 @@ static void emit_routes(char *filename, double oscale, int iscale)
FILE *fdef;
u_char errcond = FALSE;
u_char need_cleanup = FALSE;
+ u_char purge_routed = FALSE;
+ u_char skip_net = FALSE;
fdef = fopen(DEFfilename, "r");
- if (fdef == NULL) {
+ if ((fdef == NULL) && (DEFfilename != NULL)) {
if (strchr(DEFfilename, '.') == NULL) {
char *extfilename = malloc(strlen(DEFfilename) + 5);
sprintf(extfilename, "%s.def", DEFfilename);
@@ -1943,12 +2594,23 @@ static void emit_routes(char *filename, double oscale, int iscale)
// Copy DEF file up to NETS line
numnets = 0;
+ numvias = 0;
while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
lptr = line;
while (isspace(*lptr)) lptr++;
if (!strncmp(lptr, "NETS", 4)) {
- sscanf(lptr + 4, "%d", &numnets);
- break;
+ sscanf(lptr + 4, "%d", &numnets);
+ break;
+ }
+ if (!strncmp(lptr, "VIAS", 4)) {
+ sscanf(lptr + 4, "%d", &numvias);
+ LefWriteGeneratedVias(Cmd, (double)(oscale / (double)iscale), numvias);
+ continue; /* VIAS line already written; do not output. */
+ }
+ if (!strncmp(lptr, "PINS", 4) && (numvias == 0)) {
+ /* Check if there are any generated vias, and write them */
+ /* prior to the PINS section. */
+ LefWriteGeneratedVias(Cmd, (double)(oscale / (double)iscale), 0);
}
fputs(line, Cmd);
}
@@ -1962,13 +2624,6 @@ static void emit_routes(char *filename, double oscale, int iscale)
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) {
@@ -1994,8 +2649,9 @@ static void emit_routes(char *filename, double oscale, int iscale)
// the original routing information
while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
if ((lptr = strchr(line, ';')) != NULL) {
- *lptr = '\n';
- *(lptr + 1) = '\0';
+ // *lptr = '\n';
+ // *(lptr + 1) = '\0';
+ *line = '\0';
break;
}
}
@@ -2016,17 +2672,16 @@ static void emit_routes(char *filename, double oscale, int iscale)
/* 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);
+ net = DefFindNet(netname);
+ if (!net || (net->flags & NET_IGNORED)) {
+ if (!net)
+ Fprintf(stderr, "emit_routes(): Net %s cannot be found.\n",
+ netname);
- /* Dump rest of net and continue---no routing information */
+ /* Dump rest of net and continue */
*(lptr) = ';';
+ *(lptr + 1) = '\n';
+ *(lptr + 2) = '\0';
fputs(line, Cmd);
continue;
}
@@ -2034,7 +2689,6 @@ static void emit_routes(char *filename, double oscale, int iscale)
/* 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");
}
@@ -2059,6 +2713,7 @@ static void emit_routes(char *filename, double oscale, int iscale)
stubroutes = 0;
for (i = 0; i < Numnets; i++) {
net = Nlnets[i];
+ if (net->flags & NET_IGNORED) continue;
if (net->flags & NET_STUB) {
stubroutes++;
for (rt = net->routes; rt; rt = rt->next)
@@ -2071,17 +2726,55 @@ static void emit_routes(char *filename, double oscale, int iscale)
// proper width.
if (stubroutes > 0) {
- fprintf(Cmd, "\nSPECIALNETS %d ", stubroutes);
+ fprintf(Cmd, "\nSPECIALNETS %d ", stubroutes + numSpecial);
for (i = 0; i < Numnets; i++) {
net = Nlnets[i];
+ if (net->flags & NET_IGNORED) continue;
emit_routed_net(Cmd, net, (u_char)1, oscale, iscale);
}
- fprintf(Cmd, ";\nEND SPECIALNETS\n");
+ if (numSpecial == 0)
+ fprintf(Cmd, ";\nEND SPECIALNETS\n");
+ else
+ fprintf(Cmd, ";\n");
}
- // Finish copying the rest of the file
+ // Finish copying the rest of the file. Ignore ROUTED specialnets if
+ // the nets are known nets and not power or ground nets. FIXED or
+ // COVER nets are output verbatim.
+
while (fgets(line, MAX_LINE_LEN, fdef) != NULL) {
- fputs(line, Cmd);
+ lptr = line;
+ while (isspace(*lptr)) lptr++;
+ if (!strncmp(lptr, "SPECIALNETS", 11)) {
+ if (stubroutes > 0) {
+ purge_routed = TRUE;
+ continue; /* SPECIALNETS line already written; do not output. */
+ }
+ }
+ if (!purge_routed)
+ fputs(line, Cmd);
+ else {
+ lptr = line;
+ while (isspace(*lptr)) lptr++;
+ if (*lptr == '-') {
+ lptr++;
+ while (isspace(*lptr)) lptr++;
+ sscanf(lptr, "%s", netname);
+
+ // Find this net
+ net = DefFindNet(netname);
+ if (!net || (net->flags & NET_IGNORED))
+ skip_net = FALSE;
+ else if (net->netnum == VDD_NET || net->netnum == GND_NET)
+ skip_net = FALSE;
+ else
+ skip_net = TRUE;
+ }
+ if (!skip_net) fputs(line, Cmd);
+ else if ((lptr = strchr(line, ';')) != NULL) {
+ skip_net = FALSE;
+ }
+ }
}
fclose(fdef);
fclose(Cmd);
diff --git a/output.h b/output.h
index d1b6df8..2530afc 100644
--- a/output.h
+++ b/output.h
@@ -13,7 +13,9 @@ extern int Pathon;
/* Function prototypes */
static void emit_routes(char *filename, double oscale, int iscale);
+void cleanup_net(NET net);
int write_def(char *filename);
+int write_failed(char *filename);
char *print_node_name(NODE node);
void print_nets(char *filename);
void print_routes(char *filename);
diff --git a/qconfig.c b/qconfig.c
index d71c4ff..0fc0261 100644
--- a/qconfig.c
+++ b/qconfig.c
@@ -30,19 +30,17 @@ int PinNumber = 0;
int Num_layers = MAX_LAYERS; // layers to use to route
double PathWidth[MAX_LAYERS]; // width of the paths
-int GDSLayer[MAX_LAYERS]; // GDS layer number
+int GDSLayer[MAX_TYPES]; // GDS layer number
int GDSCommentLayer = 1; // for dummy wires, etc.
-char CIFLayer[MAX_LAYERS][50]; // CIF layer name
-double PitchX[MAX_LAYERS]; // Horizontal wire pitch of layer
-double PitchY[MAX_LAYERS]; // Vertical wire pitch of layer
-int NumChannelsX[MAX_LAYERS]; // number of wire channels in X on layer
-int NumChannelsY[MAX_LAYERS]; // number of wire channels in Y on layer
+char CIFLayer[MAX_TYPES][50]; // CIF layer name
+double PitchX; // Horizontal wire pitch of layer
+double PitchY; // Vertical wire pitch of layer
+int NumChannelsX; // number of wire channels in X on layer
+int NumChannelsY; // number of wire channels in Y on layer
int Vert[MAX_LAYERS]; // 1 if vertical, 0 if horizontal
int Numpasses = 10; // number of times to iterate in route_segs
char StackedContacts = MAX_LAYERS; // Value is number of contacts that may
// be stacked on top of each other.
-char ViaPattern = VIA_PATTERN_NONE; // Patterning to be used for vias based
- // on grid position (i.e., checkerboarding)
double Xlowerbound=0.0; // Bounding Box of routes, in microns
double Xupperbound=0.0;
@@ -59,80 +57,99 @@ int OffsetCost = 50; // Cost per micron of a node offset
int ConflictCost = 50; // Cost of shorting another route
// during the rip-up and reroute stage
-char *ViaX[MAX_LAYERS];
-char *ViaY[MAX_LAYERS];
+char *ViaXX[MAX_LAYERS];
+char *ViaXY[MAX_LAYERS];
+char *ViaYX[MAX_LAYERS];
+char *ViaYY[MAX_LAYERS];
/*--------------------------------------------------------------*/
/* post_config --- */
/* */
-/* The following code ensures that the layer grids align. */
-/* For now, all PitchX[i] and PitchY[i] should be the same */
-/* for all layers. Hopefully this restriction can be lifted */
-/* sometime, but it will necessarily be a royal pain. */
+/* Resolve PitchX and PitchY, which are the minimum pitches */
+/* that determine the underlying route grid. */
+/* */
+/* If "noprint" is TRUE, then do not print diagnostic info. */
/*--------------------------------------------------------------*/
void
-post_config(void)
+post_config(u_char noprint)
{
int i, h, v;
+ double rpitchx, rpitchy;
// Make sure that Num_layers does not exceed the number of
// routing layers defined by the LEF file (or the config
// file).
- i = LefGetMaxLayer();
+ i = LefGetMaxRouteLayer();
if (i < Num_layers) Num_layers = i;
- h = v = -1;
+ // Make sure all layers have a pitch in both X and Y even if not
+ // specified separately in the configuration or def files.
for (i = 0; i < Num_layers; i++) {
- if (!Vert[i]) {
- h = i;
- PitchY[i] = PitchX[i];
- PitchX[i] = 0.0;
- }
- else
- v = i;
+ rpitchx = LefGetRoutePitchX(i);
+ rpitchy = LefGetRoutePitchY(i);
+ if ((PitchX == 0.0) || ((rpitchx != 0.0) && (rpitchx + EPS < PitchX)))
+ PitchX = rpitchx;
+ if ((PitchY == 0.0) || ((rpitchy != 0.0) && (rpitchy + EPS < PitchY)))
+ PitchY = rpitchy;
}
- // In case all layers are listed as horizontal or all
- // as vertical, we should still handle it gracefully
-
- if (h == -1) h = v;
- else if (v == -1) v = h;
+ // This is mostly arbitrary. Generally, all route layer
+ // pitches except for the smallest X and Y pitches will
+ // be ignored, and the actual route pitches will be multiples
+ // of the smallest value, and determined by width and spacing
+ // rules rather than using any value in the technology LEF.
for (i = 0; i < Num_layers; i++) {
- if (PitchX[i] != 0.0 && PitchX[i] != PitchX[v]) {
- Fprintf(stderr, "Multiple vertical route layers at different"
- " pitches. Using smaller pitch %g, will route on"
- " 1-of-N tracks if necessary.\n",
- PitchX[i]);
- PitchX[v] = PitchX[i];
- }
- if (PitchY[i] != 0.0 && PitchY[i] != PitchY[h]) {
- Fprintf(stderr, "Multiple horizontal route layers at different"
- " pitches. Using smaller pitch %g, will route on"
- " 1-of-N tracks if necessary.\n",
- PitchY[i]);
- PitchY[h] = PitchY[i];
- }
+ if (LefGetRoutePitchX(i) == 0.0) {
+ if (Vert[i])
+ LefSetRoutePitchX(i, PitchX);
+ else if (i > 0)
+ LefSetRoutePitchX(i, LefGetRoutePitchX(i - 1));
+ else
+ LefSetRoutePitchX(i, LefGetRoutePitchX(i + 1));
+ }
+ if (LefGetRoutePitchY(i) == 0.0) {
+ if (!Vert[i])
+ LefSetRoutePitchY(i, PitchY);
+ else if (i > 0)
+ LefSetRoutePitchY(i, LefGetRoutePitchY(i - 1));
+ else
+ LefSetRoutePitchY(i, LefGetRoutePitchY(i + 1));
+ }
}
- // 2nd pass: Make sure all layers have a pitch in both X and Y
- // even if not specified separately in the configuration or def files.
- for (i = 0; i < Num_layers; i++) {
- if (PitchX[i] == 0.0) PitchX[i] = PitchX[v];
- if (PitchY[i] == 0.0) PitchY[i] = PitchY[h];
+ if (noprint == FALSE) {
+ for (i = 0; i < Num_layers; i++) {
+ rpitchx = LefGetRoutePitchX(i);
+ rpitchy = LefGetRoutePitchY(i);
+ if ((PitchX != 0.0) && (PitchX + EPS < rpitchx)) {
+ Fprintf(stdout, "Vertical route layer at non-minimum pitch"
+ " %g. Using smaller pitch %g, will route on"
+ " 1-of-%d tracks for layer %s.\n",
+ rpitchx, PitchX, (int)(ceil(rpitchx / PitchX)),
+ LefGetRouteName(i));
+ }
+ if ((PitchY != 0.0) && (PitchY + EPS < rpitchy)) {
+ Fprintf(stdout, "Horizontal route layer at non-minimum pitch"
+ " %g. Using smaller pitch %g, will route on"
+ " 1-of-%d tracks for layer %s.\n",
+ rpitchy, PitchY, (int)(ceil(rpitchy / PitchY)),
+ LefGetRouteName(i));
+ }
+ }
}
-
} /* post_config() */
/*--------------------------------------------------------------*/
-/* Append to string list */
+/* Append to a string */
/*--------------------------------------------------------------*/
void string_list_append(STRING *lst, const char *s)
{
STRING n, strl;
+
n = (STRING)malloc(sizeof(struct string_));
n->name = strdup(s);
n->next = NULL;
@@ -170,8 +187,10 @@ int read_config(FILE *fconfig, int is_info)
if (Firstcall) {
for (i = 0; i < MAX_LAYERS; i++) {
sprintf(line, "via%d%d", i + 1, i + 2);
- ViaX[i] = strdup(line);
- ViaY[i] = NULL;
+ ViaXX[i] = strdup(line);
+ ViaXY[i] = NULL;
+ ViaYX[i] = NULL;
+ ViaYY[i] = NULL;
}
DontRoute = (STRING)NULL;
@@ -180,9 +199,7 @@ int read_config(FILE *fconfig, int is_info)
Nlgates = (GATE)NULL;
UserObs = (DSEG)NULL;
- for (i = 0; i < MAX_LAYERS; i++)
- PitchX[i] = PitchY[i] = 0.0;
-
+ PitchX = PitchY = 0.0;
Firstcall = 0;
}
@@ -198,11 +215,13 @@ int read_config(FILE *fconfig, int is_info)
while (isspace(*lineptr)) lineptr++;
if (!strncasecmp(lineptr, "lef", 3) || !strncmp(lineptr, "read_lef", 8)) {
+ int mscale;
if ((i = sscanf(lineptr, "%*s %s\n", sarg)) == 1) {
// Argument is a filename of a LEF file from which we
// should get the information about gate pins & obstructions
OK = 1;
- LefRead(sarg);
+ mscale = LefRead(sarg);
+ if (mscale > Scales.mscale) Scales.mscale = mscale;
}
}
@@ -220,13 +239,13 @@ int read_config(FILE *fconfig, int is_info)
}
if ((i = sscanf(lineptr, "layer_%d_name %s", &iarg2, sarg)) == 2) {
- if (iarg2 > 0 && iarg2 < 10) {
+ if (iarg2 > 0 && iarg2 <= MAX_LAYERS) {
OK = 1; strcpy(CIFLayer[iarg2 - 1], sarg);
}
}
if ((i = sscanf(lineptr, "gds_layer_%d %d", &iarg2, &iarg)) == 2) {
- if (iarg2 > 0 && iarg2 < 10) {
+ if (iarg2 > 0 && iarg2 <= MAX_TYPES) {
OK = 1; GDSLayer[iarg2 - 1] = iarg;
}
}
@@ -276,7 +295,13 @@ int read_config(FILE *fconfig, int is_info)
}
if ((i = sscanf(lineptr, "layer %d wire pitch %lf\n", &iarg, &darg)) == 2) {
- OK = 1; PitchX[iarg-1] = darg;
+ OK = 1;
+ if (Vert[iarg - 1]) {
+ if ((PitchX == 0) || (darg < PitchX)) PitchX = darg;
+ }
+ else {
+ if ((PitchY == 0) || (darg < PitchY)) PitchY = darg;
+ }
}
else if (i == 1) {
if ((i = sscanf(lineptr, "layer %*d vertical %d\n", &iarg2)) == 1) {
@@ -364,14 +389,6 @@ int read_config(FILE *fconfig, int is_info)
if (StackedContacts == 0) StackedContacts = 1;
}
- // Look for via patterning specifications
- if (strcasestr(lineptr, "via pattern") != NULL) {
- if (strcasestr(lineptr + 12, "normal") != NULL)
- ViaPattern = VIA_PATTERN_NORMAL;
- else if (strcasestr(lineptr + 12, "invert") != NULL)
- ViaPattern = VIA_PATTERN_INVERT;
- }
-
if ((i = sscanf(lineptr, "obstruction %lf %lf %lf %lf %s\n",
&darg, &darg2, &darg3, &darg4, sarg)) == 5) {
OK = 1;
@@ -457,11 +474,11 @@ int read_config(FILE *fconfig, int is_info)
// Allocate memory for 10 more pins
gateinfo->taps = (DSEG *)realloc(gateinfo->taps,
(CurrentPin + 10) * sizeof(DSEG));
- gateinfo->noderec = (NODE *)realloc(gateinfo->taps,
+ gateinfo->noderec = (NODE *)realloc(gateinfo->noderec,
(CurrentPin + 10) * sizeof(NODE));
- gateinfo->netnum = (int *)realloc(gateinfo->taps,
+ gateinfo->netnum = (int *)realloc(gateinfo->netnum,
(CurrentPin + 10) * sizeof(int));
- gateinfo->node = (char **)realloc(gateinfo->taps,
+ gateinfo->node = (char **)realloc(gateinfo->node,
(CurrentPin + 10) * sizeof(char *));
}
}
@@ -476,7 +493,7 @@ int read_config(FILE *fconfig, int is_info)
line[0] = line[1] = '\0';
}
- post_config();
+ post_config(FALSE);
return count;
} /* read_config() */
diff --git a/qconfig.h b/qconfig.h
index 4693050..05b12cf 100644
--- a/qconfig.h
+++ b/qconfig.h
@@ -13,17 +13,16 @@
extern int Num_layers;
extern double PathWidth[MAX_LAYERS]; // width of the paths
-extern int GDSLayer[MAX_LAYERS]; // GDS layer number
+extern int GDSLayer[MAX_TYPES]; // GDS layer number
extern int GDSCommentLayer; // for dummy wires, etc.
-extern char CIFLayer[MAX_LAYERS][50]; // CIF layer name
-extern double PitchX[MAX_LAYERS]; // horizontal wire pitch of layer
-extern double PitchY[MAX_LAYERS]; // vertical wire pitch of layer
-extern int NumChannelsX[MAX_LAYERS];
-extern int NumChannelsY[MAX_LAYERS];
+extern char CIFLayer[MAX_TYPES][50]; // CIF layer name
+extern double PitchX; // base horizontal wire pitch
+extern double PitchY; // base vertical wire pitch
+extern int NumChannelsX;
+extern int NumChannelsY;
extern int Vert[MAX_LAYERS]; // 1 if verticle, 0 if horizontal
extern int Numpasses; // number of times to iterate in route_segs
extern char StackedContacts; // Number of vias that can be stacked together
-extern char ViaPattern; // Type of via patterning to use
extern double Xlowerbound; // Bounding Box of routes
extern double Xupperbound;
@@ -38,11 +37,17 @@ extern int BlockCost;
extern int OffsetCost;
extern int ConflictCost;
-extern char *ViaX[MAX_LAYERS];
-extern char *ViaY[MAX_LAYERS];
+// If vias are non-square, then they can have up to four orientations,
+// with the top and/or bottom metal layers oriented with the longest
+// dimension along either the X or the Y axis.
+
+extern char *ViaXX[MAX_LAYERS]; // Top and bottom horizontal
+extern char *ViaXY[MAX_LAYERS]; // Bottom horizontal, top vertical
+extern char *ViaYX[MAX_LAYERS]; // Bottom vertial, top horizontal
+extern char *ViaYY[MAX_LAYERS]; // Top and bottom vertical
int read_config(FILE *configfileptr, int is_info);
-void post_config(void);
+void post_config(u_char noprint);
#define QCONFIG_H
#endif
diff --git a/qrouter.c b/qrouter.c
index 7b5ae67..fd18a14 100644
--- a/qrouter.c
+++ b/qrouter.c
@@ -52,6 +52,7 @@ u_char needblock[MAX_LAYERS];
char *vddnet = NULL;
char *gndnet = NULL;
+char *antenna_cell = NULL;
int Numnets = 0;
int Pinlayers = 0;
@@ -80,33 +81,33 @@ int set_num_channels(void)
NODE node;
DPOINT ctap, ltap, ntap;
- if (NumChannelsX[0] != 0) return 0; /* Already been called */
+ if (NumChannelsX != 0) return 0; /* Already been called */
- for (i = 0; i < Num_layers; i++) {
- if (PitchX[i] == 0.0 || PitchY[i] == 0.0) {
- Fprintf(stderr, "Have a 0 pitch for layer %d (of %d). "
- "Exit.\n", i + 1, Num_layers);
- return (-3);
- }
- NumChannelsX[i] = (int)(1.5 + (Xupperbound - Xlowerbound) / PitchX[i]);
- NumChannelsY[i] = (int)(1.5 + (Yupperbound - Ylowerbound) / PitchY[i]);
- if ((Verbose > 1) || (NumChannelsX[i] <= 0))
- Fprintf(stdout, "Number of x channels for layer %d is %d\n",
- i, NumChannelsX[i]);
- if ((Verbose > 1) || (NumChannelsY[i] <= 0))
- Fprintf(stdout, "Number of y channels for layer %d is %d\n",
- i, NumChannelsY[i]);
+ if (PitchX == 0.0) {
+ Fprintf(stderr, "Have a 0 pitch for X direction. Exit.\n");
+ return (-3);
+ }
+ else if (PitchY == 0.0) {
+ Fprintf(stderr, "Have a 0 pitch for Y direction. Exit.\n");
+ return (-3);
+ }
+
+ NumChannelsX = (int)(1.5 + (Xupperbound - Xlowerbound) / PitchX);
+ NumChannelsY = (int)(1.5 + (Yupperbound - Ylowerbound) / PitchY);
+ if ((Verbose > 1) || (NumChannelsX <= 0))
+ Fprintf(stdout, "Number of x channels is %d\n", NumChannelsX);
+ if ((Verbose > 1) || (NumChannelsY <= 0))
+ Fprintf(stdout, "Number of y channels is %d\n", NumChannelsY);
- if (NumChannelsX[i] <= 0) {
- Fprintf(stderr, "Something wrong with layer %d x bounds.\n", i);
- return(-3);
- }
- if (NumChannelsY[i] <= 0) {
- Fprintf(stderr, "Something wrong with layer %d y bounds.\n", i);
- return(-3);
- }
- Flush(stdout);
+ if (NumChannelsX <= 0) {
+ Fprintf(stderr, "Something wrong with x bounds.\n");
+ return(-3);
}
+ if (NumChannelsY <= 0) {
+ Fprintf(stderr, "Something wrong with y bounds.\n");
+ return(-3);
+ }
+ Flush(stdout);
// Go through all nodes and remove any tap or extend entries that are
// out of bounds.
@@ -118,8 +119,8 @@ int set_num_channels(void)
ltap = NULL;
for (ctap = node->taps; ctap != NULL; ) {
ntap = ctap->next;
- glimitx = NumChannelsX[ctap->layer];
- glimity = NumChannelsY[ctap->layer];
+ glimitx = NumChannelsX;
+ glimity = NumChannelsY;
if (ctap->gridx < 0 || ctap->gridx >= glimitx ||
ctap->gridy < 0 || ctap->gridy >= glimity) {
/* Remove ctap */
@@ -136,8 +137,8 @@ int set_num_channels(void)
ltap = NULL;
for (ctap = node->extend; ctap != NULL; ) {
ntap = ctap->next;
- glimitx = NumChannelsX[ctap->layer];
- glimity = NumChannelsY[ctap->layer];
+ glimitx = NumChannelsX;
+ glimity = NumChannelsY;
if (ctap->gridx < 0 || ctap->gridx >= glimitx ||
ctap->gridy < 0 || ctap->gridy >= glimity) {
/* Remove ctap */
@@ -168,7 +169,7 @@ int allocate_obs_array(void)
if (Obs[0] != NULL) return 0; /* Already been called */
for (i = 0; i < Num_layers; i++) {
- Obs[i] = (u_int *)calloc(NumChannelsX[i] * NumChannelsY[i],
+ Obs[i] = (u_int *)calloc(NumChannelsX * NumChannelsY,
sizeof(u_int));
if (!Obs[i]) {
Fprintf(stderr, "Out of memory 4.\n");
@@ -366,34 +367,12 @@ runqrouter(int argc, char *argv[])
#else
fprintf(infoFILEptr, "qrouter %s.%s\n", VERSION, REVISION);
#endif
+ /* Output database units expected by the technology LEF file */
+ /* Note that this comes from MANUFACTURINGGRID, not UNITS DATABASE */
+ fprintf(infoFILEptr, "units scale %d\n", Scales.mscale);
- /* Resolve pitches. This is normally done after reading */
- /* the DEF file, but the info file is usually generated */
- /* from LEF layer information only, in order to get the */
- /* values needed to write the DEF file tracks. */
-
- for (i = 0; i < Num_layers; i++) {
- int o = LefGetRouteOrientation(i);
-
- /* Set PitchX and PitchY from route info as */
- /* check_variable_pitch needs the values */
-
- if (o == 1)
- PitchY[i] = LefGetRoutePitch(i);
- else
- PitchX[i] = LefGetRoutePitch(i);
- }
-
- /* Resolve pitch information similarly to post_config() */
-
- for (i = 1; i < Num_layers; i++) {
- int o = LefGetRouteOrientation(i);
-
- if ((o == 1) && (PitchY[i - 1] == 0))
- PitchY[i - 1] = PitchY[i];
- else if ((o == 0) && (PitchX[i - 1] == 0))
- PitchX[i - 1] = PitchX[i];
- }
+ /* Resolve base horizontal and vertical pitches. */
+ post_config(TRUE);
/* Print information about route layers, and exit */
for (i = 0; i < Num_layers; i++) {
@@ -407,7 +386,7 @@ runqrouter(int argc, char *argv[])
if (hnum > 1 && vnum == 1) vnum++;
if (layername != NULL) {
- pitch = (o == 1) ? PitchY[i] : PitchX[i],
+ pitch = (o == 1) ? PitchY : PitchX,
width = LefGetRouteWidth(i);
if (pitch == 0.0 || width == 0.0) continue;
fprintf(infoFILEptr, "%s %g %g %g %s",
@@ -444,7 +423,7 @@ runqrouter(int argc, char *argv[])
}
Obs[0] = (u_int *)NULL;
- NumChannelsX[0] = 0; // This is so we can check if NumChannelsX/Y were
+ NumChannelsX = 0; // This is so we can check if NumChannelsX/Y were
// set from within DefRead() due to reading in
// existing nets.
@@ -476,7 +455,7 @@ u_char remove_from_failed(NET net)
}
lastnl = nl;
}
- return FALSE;
+ return FALSE;
}
/*--------------------------------------------------------------*/
@@ -496,6 +475,25 @@ void remove_failed()
}
/*--------------------------------------------------------------*/
+/* Remove the first (top) route record from a net */
+/*--------------------------------------------------------------*/
+
+void remove_top_route(NET net)
+{
+ ROUTE rt;
+ SEG seg;
+
+ rt = net->routes;
+ net->routes = net->routes->next;
+ while (rt->segments) {
+ seg = rt->segments;
+ rt->segments = rt->segments->next;
+ free(seg);
+ }
+ free(rt);
+}
+
+/*--------------------------------------------------------------*/
/* reinitialize --- */
/* */
/* Free up memory in preparation for reading another DEF file */
@@ -516,7 +514,7 @@ static void reinitialize()
// Free up all of the matrices
for (i = 0; i < Pinlayers; i++) {
- for (j = 0; j < NumChannelsX[i] * NumChannelsY[i]; j++)
+ for (j = 0; j < NumChannelsX * NumChannelsY; j++)
if (Nodeinfo[i][j])
free(Nodeinfo[i][j]);
free(Nodeinfo[i]);
@@ -547,16 +545,9 @@ static void reinitialize()
net->noripup = net->noripup->next;
free(nl);
}
- while (net->routes) {
- rt = net->routes;
- net->routes = net->routes->next;
- while (rt->segments) {
- seg = rt->segments;
- rt->segments = rt->segments->next;
- free(seg);
- }
- free(rt);
- }
+ while (net->routes)
+ remove_top_route(net);
+
while (net->netnodes) {
node = net->netnodes;
net->netnodes = net->netnodes->next;
@@ -609,6 +600,172 @@ static void reinitialize()
}
/*--------------------------------------------------------------*/
+/* apply_drc_blocks() --- */
+/* */
+/* Use via and route width and spacing information to determine */
+/* if blockages are needed in tracks adjacent to routed */
+/* segments to avoid causing DRC errors in the output. */
+/* */
+/* If layer == -1, then determine values normally for all */
+/* route layers. If layer >= 0, determine values for specified */
+/* layer only. If via_except > 0, then adjust the value for */
+/* a DRC violating distance for vias in adjacent tracks by that */
+/* amount (in microns). If route_except > 0, then adjust the */
+/* value for a DRC violating distance between a via and a route */
+/* in adjacent tracks by that amount. */
+/*--------------------------------------------------------------*/
+
+void apply_drc_blocks(int layer, double via_except, double route_except)
+{
+ int i;
+ double sreq1, sreq2, sreq2t;
+
+ // Fill in needblock bit fields, which are used by commit_proute
+ // when route layers are too large for the grid size, and grid points
+ // around a route need to be marked as blocked whenever something is
+ // routed on those layers.
+
+ // "ROUTEBLOCK" is set if the spacing is violated between a normal
+ // route and an adjacent via. "VIABLOCK" is set if the spacing is
+ // violated between two adjacent vias. It may be helpful to define
+ // a third category which is route-to-route spacing violation.
+
+ // There are up to four different via types per base layer with
+ // different geometries based on the permutation of rotations of
+ // the top and bottom layers, so we only register blocking behavior
+ // if all of the via types will generate spacing violations.
+
+ for (i = 0; i < Num_layers; i++) {
+ if ((layer >= 0) && (i != layer)) continue;
+
+ needblock[i] = FALSE;
+
+ sreq1 = LefGetRouteSpacing(i);
+ if (i < Num_layers - 1) {
+ sreq2 = LefGetXYViaWidth(i, i, 0, 0) + sreq1;
+ sreq2t = LefGetXYViaWidth(i, i, 0, 1) + sreq1;
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = LefGetXYViaWidth(i, i, 0, 2) + sreq1;
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = LefGetXYViaWidth(i, i, 0, 3) + sreq1;
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2 -= via_except;
+ if ((sreq2 - EPS) > PitchX) needblock[i] |= VIABLOCKX;
+ }
+ if (i != 0) {
+ sreq2 = LefGetXYViaWidth(i - 1, i, 0, 0) + sreq1;
+ sreq2t = LefGetXYViaWidth(i - 1, i, 0, 1) + sreq1;
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = LefGetXYViaWidth(i - 1, i, 0, 2) + sreq1;
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = LefGetXYViaWidth(i - 1, i, 0, 3) + sreq1;
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2 -= via_except;
+ if ((sreq2 - EPS) > PitchX) needblock[i] |= VIABLOCKX;
+ }
+
+ if (i < Num_layers - 1) {
+ sreq2 = LefGetXYViaWidth(i, i, 1, 0) + sreq1;
+ sreq2t = LefGetXYViaWidth(i, i, 1, 1) + sreq1;
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = LefGetXYViaWidth(i, i, 1, 2) + sreq1;
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = LefGetXYViaWidth(i, i, 1, 3) + sreq1;
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2 -= via_except;
+ if ((sreq2 - EPS) > PitchY) needblock[i] |= VIABLOCKY;
+ }
+ if (i != 0) {
+ sreq2 = LefGetXYViaWidth(i - 1, i, 1, 0) + sreq1;
+ sreq2t = LefGetXYViaWidth(i - 1, i, 1, 1) + sreq1;
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = LefGetXYViaWidth(i - 1, i, 1, 2) + sreq1;
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = LefGetXYViaWidth(i - 1, i, 1, 3) + sreq1;
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2 -= via_except;
+ if ((sreq2 - EPS) > PitchY) needblock[i] |= VIABLOCKY;
+ }
+
+ sreq1 += 0.5 * LefGetRouteWidth(i);
+
+ if (i < Num_layers - 1) {
+ sreq2 = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 0, 0);
+ sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 0, 1);
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 0, 2);
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 0, 3);
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2 -= route_except;
+ if ((sreq2 - EPS) > PitchX) needblock[i] |= ROUTEBLOCKX;
+ }
+ if (i != 0) {
+ sreq2 = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 0, 0);
+ sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 0, 1);
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 0, 2);
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 0, 3);
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2 -= route_except;
+ if ((sreq2 - EPS) > PitchX) needblock[i] |= ROUTEBLOCKX;
+ }
+
+ if (i < Num_layers - 1) {
+ sreq2 = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 1, 0);
+ sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 1, 1);
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 1, 2);
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i, i, 1, 3);
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2 -= route_except;
+ if ((sreq2 - EPS) > PitchY) needblock[i] |= ROUTEBLOCKY;
+ }
+ if (i != 0) {
+ sreq2 = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 1, 0);
+ sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 1, 1);
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 1, 2);
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2t = sreq1 + 0.5 * LefGetXYViaWidth(i - 1, i, 1, 3);
+ if (sreq2t < sreq2) sreq2 = sreq2t;
+ sreq2 -= route_except;
+ if ((sreq2 - EPS) > PitchY) needblock[i] |= ROUTEBLOCKY;
+ }
+ }
+}
+
+/*--------------------------------------------------------------*/
+/* remove_tap_blocks */
+/* */
+/* Qrouter avoids routing directly over a tap point, blocking */
+/* it, if there is a Nodeinfo[][]->nodeloc entry present. */
+/* Remove this entry to remove the blockage (it can be */
+/* replaced if needed by copying back the Nodeinfo[][]->nodesav */
+/* pointer) */
+/*--------------------------------------------------------------*/
+
+void
+remove_tap_blocks(int netnum)
+{
+ int i, j;
+ NODE node;
+
+ for (i = 0; i < Pinlayers; i++) {
+ for (j = 0; j < NumChannelsX * NumChannelsY; j++) {
+ if (Nodeinfo[i][j]) {
+ node = Nodeinfo[i][j]->nodeloc;
+ if (node != (NODE)NULL)
+ if (node->netnum == netnum)
+ Nodeinfo[i][j]->nodeloc = (NODE)NULL;
+ }
+ }
+ }
+}
+
+/*--------------------------------------------------------------*/
/* post_def_setup --- */
/* */
/* Things to do after a DEF file has been read in, and the size */
@@ -618,8 +775,8 @@ static void reinitialize()
static int post_def_setup()
{
NET net;
+ ROUTE rt;
int i;
- double sreq1, sreq2;
if (DEFfilename == NULL) {
Fprintf(stderr, "No DEF file read, nothing to set up.\n");
@@ -647,14 +804,14 @@ static int post_def_setup()
for (i = 0; i < Num_layers; i++) {
- Obsinfo[i] = (float *)calloc(NumChannelsX[i] * NumChannelsY[i],
+ Obsinfo[i] = (float *)calloc(NumChannelsX * NumChannelsY,
sizeof(float));
if (!Obsinfo[i]) {
fprintf(stderr, "Out of memory 5.\n");
exit(5);
}
- Nodeinfo[i] = (NODEINFO *)calloc(NumChannelsX[i] * NumChannelsY[i],
+ Nodeinfo[i] = (NODEINFO *)calloc(NumChannelsX * NumChannelsY,
sizeof(NODEINFO));
if (!Nodeinfo[i]) {
fprintf( stderr, "Out of memory 6.\n");
@@ -665,12 +822,15 @@ static int post_def_setup()
if (Verbose > 1)
Fprintf(stderr, "Diagnostic: memory block is %d bytes\n",
- (int)sizeof(u_int) * NumChannelsX[0] * NumChannelsY[0]);
+ (int)sizeof(u_int) * NumChannelsX * NumChannelsY);
/* Be sure to create obstructions from gates first, since we don't */
/* want improperly defined or positioned obstruction layers to over- */
/* write our node list. */
+#ifdef TCL_QROUTER
+ find_free_antenna_taps(antenna_cell);
+#endif
expand_tap_geometry();
clip_gate_taps();
create_obstructions_from_gates();
@@ -683,10 +843,13 @@ static int post_def_setup()
count_reachable_taps();
count_pinlayers();
- // If any nets are pre-routed, place those routes.
+ // If any nets are pre-routed, calculate route endpoints, and
+ // place those routes.
for (i = 0; i < Numnets; i++) {
net = Nlnets[i];
+ for (rt = net->routes; rt; rt = rt->next)
+ route_set_connections(net, rt);
writeback_all_routes(net);
}
@@ -696,7 +859,7 @@ static int post_def_setup()
for (i = 0; i < Num_layers; i++) free(Obsinfo[i]);
for (i = 0; i < Num_layers; i++) {
- Obs2[i] = (PROUTE *)calloc(NumChannelsX[i] * NumChannelsY[i],
+ Obs2[i] = (PROUTE *)calloc(NumChannelsX * NumChannelsY,
sizeof(PROUTE));
if (!Obs2[i]) {
fprintf( stderr, "Out of memory 9.\n");
@@ -704,50 +867,13 @@ static int post_def_setup()
}
}
- // Fill in needblock bit fields, which are used by commit_proute
- // when route layers are too large for the grid size, and grid points
- // around a route need to be marked as blocked whenever something is
- // routed on those layers.
-
- // "ROUTEBLOCK" is set if the spacing is violated between a normal
- // route and an adjacent via. "VIABLOCK" is set if the spacing is
- // violated between two adjacent vias. It may be helpful to define
- // a third category which is route-to-route spacing violation.
-
- for (i = 0; i < Num_layers; i++) {
- needblock[i] = FALSE;
- sreq1 = LefGetRouteSpacing(i);
-
- sreq2 = LefGetViaWidth(i, i, 0) + sreq1;
- if ((sreq2 - EPS) > PitchX[i]) needblock[i] |= VIABLOCKX;
- if (i != 0) {
- sreq2 = LefGetViaWidth(i - 1, i, 0) + sreq1;
- if ((sreq2 - EPS) > PitchX[i]) needblock[i] |= VIABLOCKX;
- }
-
- sreq2 = LefGetViaWidth(i, i, 1) + sreq1;
- if ((sreq2 - EPS) > PitchY[i]) needblock[i] |= VIABLOCKY;
- if (i != 0) {
- sreq2 = LefGetViaWidth(i - 1, i, 1) + sreq1;
- if ((sreq2 - EPS) > PitchY[i]) needblock[i] |= VIABLOCKY;
- }
-
- sreq1 += 0.5 * LefGetRouteWidth(i);
+ // Remove tap blocks from power, ground, and antenna nets, as these
+ // can take up large areas of the layout and will cause serious issues
+ // with routability if left blocked.
- sreq2 = sreq1 + 0.5 * LefGetViaWidth(i, i, 0);
- if ((sreq2 - EPS) > PitchX[i]) needblock[i] |= ROUTEBLOCKX;
- if (i != 0) {
- sreq2 = sreq1 + 0.5 * LefGetViaWidth(i - 1, i, 0);
- if ((sreq2 - EPS) > PitchX[i]) needblock[i] |= ROUTEBLOCKX;
- }
-
- sreq2 = sreq1 + 0.5 * LefGetViaWidth(i, i, 1);
- if ((sreq2 - EPS) > PitchY[i]) needblock[i] |= ROUTEBLOCKY;
- if (i != 0) {
- sreq2 = sreq1 + 0.5 * LefGetViaWidth(i - 1, i, 1);
- if ((sreq2 - EPS) > PitchY[i]) needblock[i] |= ROUTEBLOCKY;
- }
- }
+ remove_tap_blocks(VDD_NET);
+ remove_tap_blocks(GND_NET);
+ remove_tap_blocks(ANTENNA_NET);
// Now we have netlist data, and can use it to get a list of nets.
@@ -763,15 +889,18 @@ static int post_def_setup()
/* read_def --- */
/* */
/* Read in the DEF file in DEFfilename */
+/* Return 0 on success, 1 on fatal error in DEF file. */
/*--------------------------------------------------------------*/
-void read_def(char *filename)
+int read_def(char *filename)
{
- double oscale, precis;
+ float oscale;
+ double precis;
+ int result;
if ((filename == NULL) && (DEFfilename == NULL)) {
Fprintf(stderr, "No DEF file specified, nothing to read.\n");
- return;
+ return 1;
}
else if (filename != NULL) {
if (DEFfilename != NULL) {
@@ -782,8 +911,9 @@ void read_def(char *filename)
}
else reinitialize();
- oscale = (double)DefRead(DEFfilename);
- precis = Scales.mscale / oscale; // from LEF manufacturing grid
+ oscale = (float)0.0;
+ result = DefRead(DEFfilename, &oscale);
+ precis = Scales.mscale / (double)oscale; // from LEF manufacturing grid
if (precis < 1.0) precis = 1.0;
precis *= (double)Scales.iscale; // user-defined extra scaling
@@ -796,6 +926,7 @@ void read_def(char *filename)
1.0 / (double)Scales.iscale);
post_def_setup();
+ return result;
}
/*--------------------------------------------------------------*/
@@ -886,7 +1017,7 @@ NET getnettoroute(int order)
// only one node.
if ((net->numnodes == 1) && (net->netnum == VDD_NET ||
- net->netnum == GND_NET))
+ net->netnum == GND_NET || net->netnum == ANTENNA_NET))
return net;
if (Verbose > 3) {
@@ -1289,6 +1420,8 @@ int dothirdstage(u_char graphdebug, int debug_netnum, u_int effort)
if (Verbose > 0)
Fprintf(stdout, "Failed to route net %s; restoring original\n",
net->netname);
+
+ ripup_net(net, TRUE, FALSE, TRUE); // Remove routes from Obs array
remove_routes(net->routes, FALSE); /* should be NULL already */
net->routes = rt;
writeback_all_routes(net); /* restore the original */
@@ -1579,18 +1712,7 @@ static int next_route_setup(struct routeinfo_ *iroute, u_char stage)
// Remove nodes of the net from Nodeinfo.nodeloc so that they will not be
// used for crossover costing of future routes.
-
- for (i = 0; i < Pinlayers; i++) {
- for (j = 0; j < NumChannelsX[i] * NumChannelsY[i]; j++) {
- if (Nodeinfo[i][j]) {
- node = Nodeinfo[i][j]->nodeloc;
- if (node != (NODE)NULL)
- if (node->netnum == iroute->net->netnum)
- Nodeinfo[i][j]->nodeloc = (NODE)NULL;
- }
- }
- }
-
+ remove_tap_blocks(iroute->net->netnum);
free_glist(iroute);
return 0;
}
@@ -1637,13 +1759,13 @@ static int route_setup(struct routeinfo_ *iroute, u_char stage)
// terminal positions for the net being routed.
for (i = 0; i < Num_layers; i++) {
- for (j = 0; j < NumChannelsX[i] * NumChannelsY[i]; j++) {
+ for (j = 0; j < NumChannelsX * NumChannelsY; j++) {
netnum = Obs[i][j] & (~BLOCKED_MASK);
Pr = &Obs2[i][j];
if (netnum != 0) {
Pr->flags = 0; // Clear all flags
- if (netnum == DRC_BLOCKAGE)
- Pr->prdata.net = netnum;
+ if ((netnum & DRC_BLOCKAGE) == DRC_BLOCKAGE)
+ Pr->prdata.net = DRC_BLOCKAGE;
else
Pr->prdata.net = netnum & NETNUM_MASK;
} else {
@@ -1653,7 +1775,8 @@ static int route_setup(struct routeinfo_ *iroute, u_char stage)
}
}
- if (iroute->net->netnum == VDD_NET || iroute->net->netnum == GND_NET) {
+ if (iroute->net->netnum == VDD_NET || iroute->net->netnum == GND_NET ||
+ iroute->net->netnum == ANTENNA_NET) {
// The normal method of selecting source and target is not amenable
// to power bus routes. Instead, we use the global standard cell
// power rails as the target, and each net in sequence becomes the
@@ -1682,8 +1805,8 @@ static int route_setup(struct routeinfo_ *iroute, u_char stage)
if (result) {
iroute->bbox.x2 = iroute->bbox.y2 = 0;
- iroute->bbox.x1 = NumChannelsX[0];
- iroute->bbox.y1 = NumChannelsY[0];
+ iroute->bbox.x1 = NumChannelsX;
+ iroute->bbox.y1 = NumChannelsY;
if (iroute->do_pwrbus == FALSE) {
@@ -1758,18 +1881,7 @@ static int route_setup(struct routeinfo_ *iroute, u_char stage)
if (!result) {
// Remove nodes of the net from Nodeinfo.nodeloc so that they will not be
// used for crossover costing of future routes.
-
- for (i = 0; i < Pinlayers; i++) {
- for (j = 0; j < NumChannelsX[i] * NumChannelsY[i]; j++) {
- if (Nodeinfo[i][j]) {
- iroute->nsrc = Nodeinfo[i][j]->nodeloc;
- if (iroute->nsrc != (NODE)NULL)
- if (iroute->nsrc->netnum == iroute->net->netnum)
- Nodeinfo[i][j]->nodeloc = (NODE)NULL;
- }
- }
- }
-
+ remove_tap_blocks(iroute->net->netnum);
free_glist(iroute);
return 0;
}
@@ -1844,7 +1956,7 @@ static int route_setup(struct routeinfo_ *iroute, u_char stage)
/* AUTHOR and DATE: steve beccue Fri Aug 8 */
/*--------------------------------------------------------------*/
-static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug)
+int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug)
{
POINT gpoint, gunproc, newpt;
int i, o;
@@ -1895,6 +2007,18 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
iroute->glist[0] = gpoint->next;
+ // Stop-gap: Needs to be investigated. Occasional gpoint has
+ // large (random?) value for y1. Suggests a memory leak. Only
+ // seen occurring during doantennaroute(). Check using valgrind.
+
+ if ((gpoint->x1 < 0) || (gpoint->y1 < 0) ||
+ (gpoint->x1 > NumChannelsX) ||
+ (gpoint->y1 > NumChannelsY)) {
+ Fprintf(stderr, "Internal memory error!\n");
+ freePOINT(gpoint);
+ continue;
+ }
+
curpt.x = gpoint->x1;
curpt.y = gpoint->y1;
curpt.lay = gpoint->layer;
@@ -2016,7 +2140,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
predecessor = PR_CONFLICT;
case EAST:
predecessor |= PR_PRED_W;
- if ((curpt.x + 1) < NumChannelsX[curpt.lay]) {
+ if ((curpt.x + 1) < NumChannelsX) {
if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) {
gpoint->next = iroute->glist[i];
iroute->glist[i] = gpoint;
@@ -2052,7 +2176,7 @@ static int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug
predecessor = PR_CONFLICT;
case NORTH:
predecessor |= PR_PRED_S;
- if ((curpt.y + 1) < NumChannelsY[curpt.lay]) {
+ if ((curpt.y + 1) < NumChannelsY) {
if ((gpoint = eval_pt(&curpt, predecessor, stage)) != NULL) {
gpoint->next = iroute->glist[i];
iroute->glist[i] = gpoint;
@@ -2162,7 +2286,7 @@ done:
/* AUTHOR and DATE: steve beccue Fri Aug 8 */
/*--------------------------------------------------------------*/
-static ROUTE createemptyroute(void)
+ROUTE createemptyroute(void)
{
ROUTE rt;
diff --git a/qrouter.h b/qrouter.h
index 3cad5cb..f74e6f0 100644
--- a/qrouter.h
+++ b/qrouter.h
@@ -7,7 +7,7 @@
#ifndef QROUTER_H
-#define OGRID(x, y, layer) ((int)((x) + ((y) * NumChannelsX[(layer)])))
+#define OGRID(x, y) ((int)((x) + ((y) * NumChannelsX)))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define ABSDIFF(x, y) (((x) > (y)) ? ((x) - (y)) : ((y) - (x)))
@@ -45,7 +45,11 @@ typedef int (*__compar_fn_t)(const void*, const void*);
#endif
/* Maximum number of route layers */
-#define MAX_LAYERS 9
+#define MAX_LAYERS 12
+
+/* Maximum number of all defined layers. Since masterslice and */
+/* overlap types are ignored, this just includes all the cuts. */
+#define MAX_TYPES (MAX_LAYERS * 2 - 1)
/* Cell name (and other names) max length */
#define MAX_NAME_LEN 1024
@@ -151,6 +155,7 @@ struct string_ {
#define ST_OFFSET_START 0x04 /* (x1, y1) is offset from grid */
#define ST_OFFSET_END 0x08 /* (x2, y2) is offset from grid */
#define ST_SPECIAL 0x10 /* wide metal (special net) */
+#define ST_MINMETAL 0x20 /* segment for min metal area */
typedef struct seg_ *SEG;
@@ -223,6 +228,7 @@ struct route_ {
#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
+#define RT_CHECK 0x40 // Route from DEF file needs checking
/* Structure used to hold nodes, saved nodes, and stub/offset info */
@@ -246,6 +252,8 @@ struct nodeinfo_ {
#define NI_OFFSET_MASK 0x0c // Tap offset mask (N/S + E/W)
#define NI_NO_VIAX 0x10 // Via in ViaX array is prohibited
#define NI_NO_VIAY 0x20 // Via in ViaY array is prohibited
+#define NI_VIA_X 0x40 // Placed via is oriented horizontally
+#define NI_VIA_Y 0x80 // Placed via is oriented vertically
struct node_ {
NODE next;
@@ -274,6 +282,7 @@ struct gate_ {
char **node; // names of the pins on this gate
int *netnum; // net number connected to each pin
NODE *noderec; // node record for each pin
+ float *area; // gate area for each pin
u_char *direction; // port direction (input, output, etc.)
DSEG *taps; // list of gate node locations and layers
DSEG obs; // list of obstructions in gate
@@ -283,6 +292,16 @@ struct gate_ {
int orient;
};
+// Define record holding information pointing to a gate and the
+// index into a specific node of that gate.
+
+typedef struct gatenode_ *GATENODE;
+
+struct gatenode_ {
+ GATE gate;
+ int idx;
+};
+
// Structure for a network to be routed
typedef struct net_ *NET;
@@ -428,13 +447,13 @@ extern float *Obsinfo[MAX_LAYERS]; // temporary detailed obstruction info
extern NODEINFO *Nodeinfo[MAX_LAYERS]; // stub route distances to pins and
// pointers to node structures.
-#define NODEIPTR(x, y, l) (Nodeinfo[l][OGRID(x, y, l)])
-#define OBSINFO(x, y, l) (Obsinfo[l][OGRID(x, y, l)])
-#define OBSVAL(x, y, l) (Obs[l][OGRID(x, y, l)])
-#define OBS2VAL(x, y, l) (Obs2[l][OGRID(x, y, l)])
+#define NODEIPTR(x, y, l) (Nodeinfo[l][OGRID(x, y)])
+#define OBSINFO(x, y, l) (Obsinfo[l][OGRID(x, y)])
+#define OBSVAL(x, y, l) (Obs[l][OGRID(x, y)])
+#define OBS2VAL(x, y, l) (Obs2[l][OGRID(x, y)])
-#define RMASK(x, y) (RMask[OGRID(x, y, 0)])
-#define CONGEST(x, y) (Congestion[OGRID(x, y, 0)])
+#define RMASK(x, y) (RMask[OGRID(x, y)])
+#define CONGEST(x, y) (Congestion[OGRID(x, y)])
extern DSEG UserObs; // user-defined obstruction layers
@@ -451,6 +470,7 @@ extern u_char ripLimit;
extern char *vddnet;
extern char *gndnet;
+extern char *antenna_cell;
/* Tcl output to console handling */
@@ -468,16 +488,19 @@ extern char *gndnet;
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);
+int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug);
+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 remove_failed();
+void apply_drc_blocks(int, double, double);
+void remove_top_route(NET net);
-void read_def(char *filename);
+int read_def(char *filename);
#ifdef TCL_QROUTER
int write_delays(char *filename);
diff --git a/qrouter.sh.in b/qrouter.sh.in
index 12bab42..12bab42 100755..100644
--- a/qrouter.sh.in
+++ b/qrouter.sh.in
diff --git a/qrouter.tcl.in b/qrouter.tcl.in
index 771fa27..5db9faa 100644
--- a/qrouter.tcl.in
+++ b/qrouter.tcl.in
@@ -159,6 +159,13 @@ proc qrouter::standard_route {{filename ""} {doquit true}} {
}
}
}
+ cleanup all
+ if {$result == 0} {
+ if {![catch {antenna init}]} {
+ puts stdout "*** Running antenna violation checks"
+ antenna fix
+ }
+ }
if {${rootname} != ""} {
puts stdout "*** Writing DEF file $deffilename"
write_def $deffilename
@@ -166,7 +173,6 @@ proc qrouter::standard_route {{filename ""} {doquit true}} {
puts stdout "*** Writing DEF file (default)"
write_def
}
-
if {$result > 0} {
write_failed fail.out
}
@@ -220,6 +226,9 @@ proc qrouter::congestion_route {filename} {
qrouter::write_congested $filename
}
write_def
+ if {$result > 0} {
+ write_failed fail.out
+ }
quit
}
diff --git a/tclqrouter.c b/tclqrouter.c
index 1fe8fd5..d06dcbb 100644
--- a/tclqrouter.c
+++ b/tclqrouter.c
@@ -21,6 +21,7 @@
#include "maze.h"
#include "qconfig.h"
#include "lef.h"
+#include "def.h"
#include "graphics.h"
#include "node.h"
#include "tkSimple.h"
@@ -59,12 +60,21 @@ static int qrouter_stage2(
static int qrouter_stage3(
ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]);
+static int qrouter_cleanup(
+ ClientData clientData, Tcl_Interp *interp,
+ int objc, Tcl_Obj *CONST objv[]);
static int qrouter_writedef(
ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]);
+static int qrouter_writefailed(
+ ClientData clientData, Tcl_Interp *interp,
+ int objc, Tcl_Obj *CONST objv[]);
static int qrouter_writedelays(
ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]);
+static int qrouter_antenna(
+ ClientData clientData, Tcl_Interp *interp,
+ int objc, Tcl_Obj *CONST objv[]);
static int qrouter_readdef(
ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]);
@@ -110,6 +120,9 @@ static int qrouter_congested(
static int qrouter_layers(
ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]);
+static int qrouter_drc(
+ ClientData clientData, Tcl_Interp *interp,
+ int objc, Tcl_Obj *CONST objv[]);
static int qrouter_passes(
ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]);
@@ -136,11 +149,14 @@ static cmdstruct qrouter_commands[] =
{"stage1", qrouter_stage1},
{"stage2", qrouter_stage2},
{"stage3", qrouter_stage3},
+ {"cleanup", qrouter_cleanup},
{"write_def", qrouter_writedef},
{"read_def", qrouter_readdef},
{"read_lef", qrouter_readlef},
{"read_config", qrouter_readconfig},
{"write_delays", qrouter_writedelays},
+ {"antenna", qrouter_antenna},
+ {"write_failed", qrouter_writefailed},
{"layer_info", qrouter_layerinfo},
{"obstruction", qrouter_obs},
{"ignore", qrouter_ignore},
@@ -149,6 +165,7 @@ static cmdstruct qrouter_commands[] =
{"resolution", qrouter_resolution},
{"congested", qrouter_congested},
{"layers", qrouter_layers},
+ {"drc", qrouter_drc},
{"passes", qrouter_passes},
{"vdd", qrouter_vdd},
{"gnd", qrouter_gnd},
@@ -626,18 +643,30 @@ qrouter_start(ClientData clientData, Tcl_Interp *interp,
fclose(scriptf);
result = Tcl_EvalFile(interp, scriptfile);
}
- free(scriptfile);
/* The script file should determine whether or not to */
/* exit by including the "quit" command. But if there */
/* is an error in the script, then always quit. */
+ /* If tkcon console is in use and there is an error in */
+ /* the script, then print the error message to the */
+ /* terminal, not the console, or else it vanishes. */
+
if (result != TCL_OK) {
+ if (consoleinterp == interp)
+ Fprintf(stderr, "Script file \"%s\" failed with result \'%s\'\n",
+ scriptfile, Tcl_GetStringResult(interp));
+ else
+ fprintf(stderr, "Script file \"%s\" failed with result \'%s\'\n",
+ scriptfile, Tcl_GetStringResult(interp));
+ free(scriptfile);
/* Make sure Tcl has generated all output */
while (Tcl_DoOneEvent(TCL_DONT_WAIT) != 0);
/* And exit gracefully */
qrouter_quit(clientData, interp, 1, objv);
}
+ else
+ free(scriptfile);
}
if ((DEFfilename != NULL) && (Nlgates == NULL)) {
@@ -664,6 +693,11 @@ qrouter_quit(ClientData clientData, Tcl_Interp *interp,
return TCL_ERROR;
}
+ /* Free up failed net list */
+ remove_failed();
+
+ /* Should be doing other cleanup tasks here. . . */
+
if (consoleinterp == interp)
Tcl_Exit(TCL_OK);
else
@@ -758,28 +792,12 @@ qrouter_map(ClientData clientData, Tcl_Interp *interp,
}
/*------------------------------------------------------*/
-/* Find the net named "netname" in the list of nets */
-/* and return a pointer to it. */
-/* */
-/* NOTE: Really need a hash table lookup here! */
-/*------------------------------------------------------*/
-
-NET LookupNet(char *netname)
-{
- NET net;
- int i;
-
- for (i = 0; i < Numnets; i++) {
- net = Nlnets[i];
- if (!strcmp(net->netname, netname))
- return net;
- }
- return NULL;
-}
-
-/*------------------------------------------------------*/
/* Find the net with number "number" in the list of */
/* nets and return a pointer to it. */
+/* */
+/* NOTE: This could be hashed like net names, but is */
+/* only used in one place, and router performance does */
+/* not depend on it. */
/*------------------------------------------------------*/
NET LookupNetNr(int number)
@@ -796,22 +814,6 @@ NET LookupNetNr(int number)
}
/*------------------------------------------------------*/
-/* Find the gate instance named gatename and return a */
-/* pointer to it. */
-/*------------------------------------------------------*/
-
-GATE LookupGate(char *gatename)
-{
- GATE gate;
-
- for (gate = Nlgates; gate != NULL; gate = gate->next) {
- if (!strcmp(gate->gatename, gatename))
- return gate;
- }
- return NULL;
-}
-
-/*------------------------------------------------------*/
/* Command "stage1" */
/* */
/* Execute stage1 routing. This works through the */
@@ -899,7 +901,7 @@ qrouter_stage1(ClientData clientData, Tcl_Interp *interp,
return TCL_ERROR;
}
i++;
- net = LookupNet(Tcl_GetString(objv[i]));
+ net = DefFindNet(Tcl_GetString(objv[i]));
if (net == NULL) {
Tcl_SetResult(interp, "No such net", NULL);
return TCL_ERROR;
@@ -1107,7 +1109,7 @@ qrouter_stage2(ClientData clientData, Tcl_Interp *interp,
return TCL_ERROR;
}
i++;
- net = LookupNet(Tcl_GetString(objv[i]));
+ net = DefFindNet(Tcl_GetString(objv[i]));
if (net == NULL) {
Tcl_SetResult(interp, "No such net", NULL);
return TCL_ERROR;
@@ -1276,7 +1278,7 @@ qrouter_stage3(ClientData clientData, Tcl_Interp *interp,
return TCL_ERROR;
}
i++;
- net = LookupNet(Tcl_GetString(objv[i]));
+ net = DefFindNet(Tcl_GetString(objv[i]));
if (net == NULL) {
Tcl_SetResult(interp, "No such net", NULL);
return TCL_ERROR;
@@ -1363,6 +1365,74 @@ qrouter_stage3(ClientData clientData, Tcl_Interp *interp,
}
/*------------------------------------------------------*/
+/* Command "cleanup" */
+/* */
+/* Clean up the nets by removing adjacent vias where */
+/* such adjacent vias would cause a DRC violation. */
+/* Note that this must be done between the last */
+/* routing stage but before finding antenna */
+/* violations, output, and delay writing, as all of */
+/* these can be dependent on topology changes caused */
+/* by the cleanup. */
+/* */
+/* Options: */
+/* */
+/* cleanup all Clean up all nets in the design */
+/* cleanup net <name> [...] */
+/* Clean up the named net(s) */
+/*------------------------------------------------------*/
+
+static int
+qrouter_cleanup(ClientData clientData, Tcl_Interp *interp,
+ int objc, Tcl_Obj *CONST objv[])
+{
+ int result, idx, i;
+ NET net;
+
+ static char *subCmds[] = {
+ "all", "net", NULL
+ };
+ enum SubIdx {
+ AllIdx, NetIdx
+ };
+
+ if (objc < 2) {
+ Tcl_WrongNumArgs(interp, 0, objv, "?option?");
+ return TCL_ERROR;
+ }
+ else {
+ if ((result = Tcl_GetIndexFromObj(interp, objv[1],
+ (CONST84 char **)subCmds, "option", 0, &idx))
+ != TCL_OK)
+ return result;
+
+ // Quick check to see if cleanup_net can be avoided completely.
+ for (i = 0; i < Num_layers; i++)
+ if (needblock[i] & (VIABLOCKX | VIABLOCKY))
+ break;
+ if (i == Num_layers) return TCL_OK; /* No cleanup needed */
+
+ switch (idx) {
+ case AllIdx:
+ for (i = 0; i < Numnets; i++) {
+ net = Nlnets[i];
+ cleanup_net(net);
+ }
+ break;
+
+ case NetIdx:
+ for (i = 2; i < objc; i++) {
+ net = DefFindNet(Tcl_GetString(objv[i]));
+ if (net != NULL)
+ cleanup_net(net);
+ }
+ break;
+ }
+ }
+ return QrouterTagCallback(interp, objc, objv);
+}
+
+/*------------------------------------------------------*/
/* Command "remove" */
/* */
/* Remove a net or nets, or all nets, from the */
@@ -1410,7 +1480,7 @@ qrouter_remove(ClientData clientData, Tcl_Interp *interp,
break;
case NetIdx:
for (i = 2; i < objc; i++) {
- net = LookupNet(Tcl_GetString(objv[i]));
+ net = DefFindNet(Tcl_GetString(objv[i]));
if (net != NULL)
ripup_net(net, (u_char)1, (u_char)1, (u_char)0);
}
@@ -1536,13 +1606,18 @@ qrouter_readlef(ClientData clientData, Tcl_Interp *interp,
for (i = 0; i < Num_layers; i++) {
- /* Set Vert and PitchX from route info */
+ /* Set Vert from route info since this gets called a lot */
+ /* (e.g., from eval_pt() and is more convenient to pull */
+ /* from an array than calling a subroutine every time. */
Vert[i] = (1 - LefGetRouteOrientation(i));
- PitchX[i] = LefGetRoutePitch(i);
}
- post_config();
+ /* Resolve the base horizontal and vertical pitches */
+ post_config(FALSE);
+
+ /* Set DRC blockage behavior based on via and route widths */
+ apply_drc_blocks(-1, 0.0, 0.0);
return QrouterTagCallback(interp, objc, objv);
}
@@ -1555,14 +1630,36 @@ static int
qrouter_readdef(ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
+ char *argv;
+ u_char abort_on_error = FALSE;
+ int result;
+
+ /* Parse out options */
+
+ while (objc > 0) {
+ argv = Tcl_GetString(objv[objc - 1]);
+ if (*argv == '-') {
+ if (!strncmp(argv + 1, "abort", 5))
+ abort_on_error = TRUE;
+ objc--;
+ }
+ else break;
+ }
+
if ((DEFfilename == NULL) && (objc != 2)) {
Tcl_SetResult(interp, "No DEF filename specified!", NULL);
return TCL_ERROR;
}
+
if (objc == 2)
- read_def(Tcl_GetString(objv[1]));
+ result = read_def(Tcl_GetString(objv[1]));
else
- read_def(NULL);
+ result = read_def(NULL);
+
+ if ((result != (u_char)0) && (abort_on_error == TRUE)) {
+ Tcl_SetResult(interp, "Errors in input DEF file; aborting.", NULL);
+ return TCL_ERROR;
+ }
// Redisplay
draw_layout();
@@ -1586,12 +1683,95 @@ qrouter_writedef(ClientData clientData, Tcl_Interp *interp,
Tcl_SetResult(interp, "No DEF filename specified!", NULL);
return TCL_ERROR;
}
+ else DEFoutfile = DEFfilename;
write_def(DEFoutfile);
return QrouterTagCallback(interp, objc, objv);
}
/*------------------------------------------------------*/
+/* Command "antenna" */
+/* Use: */
+/* antenna init <cellname> */
+/* antenna check */
+/* antenna fix */
+/* */
+/* Calculate and handle antenna violations. Option */
+/* "init" declares the cellname that is an antenna */
+/* anchoring cell. This must be declared before */
+/* routing. "antenna check" can be called at any time */
+/* and reports the number of antenna violations at each */
+/* metal layer. "antenna fix" attempts to fix all */
+/* antenna violations by anchoring each antenna to an */
+/* available antenna cell tap. */
+/*------------------------------------------------------*/
+
+static int
+qrouter_antenna(ClientData clientData, Tcl_Interp *interp,
+ int objc, Tcl_Obj *CONST objv[])
+{
+ char *option;
+ u_char do_fix = (u_char)0;
+
+ if (objc >= 2) {
+ option = Tcl_GetString(objv[1]);
+ if (objc == 3) antenna_cell = strdup(Tcl_GetString(objv[2]));
+
+ if (!strcmp(option, "init")) {
+ if (objc != 3) {
+ if (antenna_cell != NULL) {
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(antenna_cell, -1));
+ }
+ else {
+ Tcl_SetResult(interp, "No antenna cell name specified.", NULL);
+ return TCL_ERROR;
+ }
+ }
+ }
+ else if (!strcmp(option, "check")) {
+ resolve_antenna(antenna_cell, (u_char)0);
+ }
+ else if (!strcmp(option, "fix")) {
+ resolve_antenna(antenna_cell, (u_char)1);
+ }
+ else {
+ antenna_cell = Tcl_GetString(objv[1]);
+ }
+ }
+ else {
+ Tcl_SetResult(interp, "Usage: antenna init|check|fix [cellname]", NULL);
+ return TCL_ERROR;
+ }
+
+ if (antenna_cell == NULL) {
+ Tcl_SetResult(interp, "No antenna cell specified!", NULL);
+ return TCL_ERROR;
+ }
+ return QrouterTagCallback(interp, objc, objv);
+}
+
+/*------------------------------------------------------*/
+/* Command "write_failed" */
+/*------------------------------------------------------*/
+
+static int
+qrouter_writefailed(ClientData clientData, Tcl_Interp *interp,
+ int objc, Tcl_Obj *CONST objv[])
+{
+ char *outfile = NULL;
+
+ if (objc == 2)
+ outfile = Tcl_GetString(objv[1]);
+ else if (outfile == NULL) {
+ Tcl_SetResult(interp, "No output filename specified!", NULL);
+ return TCL_ERROR;
+ }
+
+ write_failed(outfile);
+ return QrouterTagCallback(interp, objc, objv);
+}
+
+/*------------------------------------------------------*/
/* Command "write_delays" */
/*------------------------------------------------------*/
@@ -1607,6 +1787,7 @@ qrouter_writedelays(ClientData clientData, Tcl_Interp *interp,
Tcl_SetResult(interp, "No delay filename specified!", NULL);
return TCL_ERROR;
}
+ else delayoutfile = delayfilename;
write_delays(delayoutfile);
return QrouterTagCallback(interp, objc, objv);
@@ -1749,7 +1930,7 @@ qrouter_ignore(ClientData clientData, Tcl_Interp *interp,
}
else {
for (i = 1; i < objc; i++) {
- net = LookupNet(Tcl_GetString(objv[i]));
+ net = DefFindNet(Tcl_GetString(objv[i]));
if (net == NULL) {
Tcl_SetResult(interp, "No such net", NULL);
return TCL_ERROR;
@@ -1776,7 +1957,7 @@ static int
qrouter_priority(ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
- int i;
+ int i, j;
char *netname;
NET net;
STRING cn, ctest;
@@ -1793,15 +1974,40 @@ qrouter_priority(ClientData clientData, Tcl_Interp *interp,
}
Tcl_SetObjResult(interp, lobj);
}
+ else if (Nlnets == NULL) {
+ Tcl_SetResult(interp, "Must read nets from DEF file before setting priority.",
+ NULL);
+ return TCL_ERROR;
+ }
else {
- for (i = objc - 1; i > 0; i--) {
+
+ /* Find the highest-numbered existing critical net so that */
+ /* repeated calls to "priority" will work. */
+
+ j = -1;
+ for (i = 0; i < Numnets; i++) {
+ net = Nlnets[i];
+ if (net->flags & NET_CRITICAL)
+ if (net->netorder > j)
+ j = net->netorder;
+ }
+ j++;
+
+ for (i = 1; i < objc; i++) {
netname = Tcl_GetString(objv[i]);
- net = LookupNet(netname);
+ net = DefFindNet(netname);
if (net == NULL) {
Tcl_SetResult(interp, "No such net", NULL);
}
- else {
+ else if (!(net->flags & NET_CRITICAL)) {
net->flags |= NET_CRITICAL;
+ net->netorder = j++;
+
+ /* NOTE: CriticalNet is left over from the old config */
+ /* file format. Normally it will remain NULL. If the */
+ /* old config file format is used, then remove items */
+ /* from it that match nets in the Tcl priority command. */
+
for (cn = CriticalNet; cn && cn->next; cn = cn->next) {
if (!cn->next) break;
if (!strcmp(cn->next->name, netname)) {
@@ -1994,11 +2200,7 @@ qrouter_layerinfo(ClientData clientData, Tcl_Interp *interp,
/* a single point. Value "none", "0", and "1" */
/* all mean the same thing. */
/* */
-/* via_pattern: If vias are non-square, then they are */
-/* placed in a checkerboard pattern, with every */
-/* other via rotated 90 degrees. If inverted, */
-/* the rotation is swapped relative to the grid */
-/* positions used in the non-inverted case. */
+/* via_pattern: (deprecated) */
/* */
/* use: List of names of vias to use. If any via not */
/* in this list is found when reading a .lef file */
@@ -2054,8 +2256,7 @@ qrouter_via(ClientData clientData, Tcl_Interp *interp,
break;
case PatternIdx:
Tcl_SetObjResult(interp,
- Tcl_NewStringObj(
- patternSubCmds[ViaPattern + 1], -1));
+ Tcl_NewStringObj("deprecated", -1));
break;
case UseIdx:
/* Return list of vias to use */
@@ -2097,7 +2298,6 @@ qrouter_via(ClientData clientData, Tcl_Interp *interp,
(CONST84 char **)patternSubCmds, "option",
0, &idx2)) != TCL_OK)
return result;
- ViaPattern = idx2 - 1;
break;
case UseIdx:
/* Create list of vias to use */
@@ -2114,7 +2314,7 @@ qrouter_via(ClientData clientData, Tcl_Interp *interp,
newVia->next = AllowedVias;
AllowedVias = newVia;
}
- /* Regenerate the ViaX and ViaY lists */
+ /* Regenerate the ViaXX, etc., lists */
LefAssignLayerVias();
break;
}
@@ -2208,6 +2408,82 @@ qrouter_resolution(ClientData clientData, Tcl_Interp *interp,
return QrouterTagCallback(interp, objc, objv);
}
+/*------------------------------------------------------*/
+/* Command "drc" */
+/* */
+/* Set qrouter options related to handling of DRC */
+/* violations. */
+/* */
+/* Options: */
+/* */
+/* drc <layer>|all <dist> <dist> */
+/* */
+/* Allow exceptions to DRC handling. Normally qrouter */
+/* enforces DRC distance between a via and route or */
+/* between two vias on adjacent tracks, forcing a */
+/* keep-out area around a placed route if needed. */
+/* "layer" is the name of a route layer. <dist> (value */
+/* in microns) will limit the enforcement if the DRC */
+/* violation is less than the indicated distance. */
+/* The first value is for via-to-via distance, and the */
+/* second value is for route-to-via distance. A value */
+/* of zero means that the behavior is unchanged from */
+/* what is automatically calculated from defined */
+/* route and via width and spacing values. A positive */
+/* distance value loosens the DRC rule, while a */
+/* negative distance value tightens it. */
+/* */
+/* Ignoring DRC errors is generally discouraged but */
+/* may be necessary in some cases if the pitch is tight */
+/* and assumes routes may be offset to clear vias, */
+/* which is something qrouter does not know how to do. */
+/* Only use this if routability is being impacted by */
+/* DRC enforcement. */
+/*------------------------------------------------------*/
+
+static int
+qrouter_drc(ClientData clientData, Tcl_Interp *interp,
+ int objc, Tcl_Obj *CONST objv[])
+{
+ char *layername;
+ int result, layer;
+ double routedist, viadist;
+
+ if (objc != 4) {
+ Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");
+ return TCL_ERROR;
+ }
+
+ layername = Tcl_GetString(objv[1]);
+ if (!strcasecmp(layername, "all")) {
+ layer = -1;
+ }
+ else {
+ layer = LefFindLayerNum(layername);
+ if (layer < 0) {
+ result = Tcl_GetIntFromObj(interp, objv[1], &layer);
+ if (result != TCL_OK) {
+ Tcl_SetResult(interp, "No such layer name.\n", NULL);
+ return result;
+ }
+ }
+
+ if ((layer < -1) || (layer >= LefGetMaxRouteLayer())) {
+ Tcl_SetResult(interp, "Layer number out of range.\n", NULL);
+ return TCL_ERROR;
+ }
+ }
+
+ result = Tcl_GetDoubleFromObj(interp, objv[2], &viadist);
+ if (result != TCL_OK) return result;
+
+ result = Tcl_GetDoubleFromObj(interp, objv[3], &routedist);
+ if (result != TCL_OK) return result;
+
+ apply_drc_blocks(layer, viadist, routedist);
+
+ return QrouterTagCallback(interp, objc, objv);
+}
/*------------------------------------------------------*/
/* Command "layers" */
@@ -2235,10 +2511,10 @@ qrouter_layers(ClientData clientData, Tcl_Interp *interp,
else if (objc == 2) {
result = Tcl_GetIntFromObj(interp, objv[1], &value);
if (result != TCL_OK) return result;
- if (value <= 0 || value > LefGetMaxLayer()) {
+ if (value <= 0 || value > LefGetMaxRouteLayer()) {
Tcl_SetResult(interp, "Number of layers out of range,"
" setting to max.", NULL);
- Num_layers = LefGetMaxLayer();
+ Num_layers = LefGetMaxRouteLayer();
return TCL_ERROR;
}
Num_layers = value;
@@ -2543,7 +2819,7 @@ qrouter_congested(ClientData clientData, Tcl_Interp *interp,
else
entries = 0;
- Congestion = (float *)calloc(NumChannelsX[0] * NumChannelsY[0],
+ Congestion = (float *)calloc(NumChannelsX * NumChannelsY,
sizeof(float));
// Use net bounding boxes to estimate congestion
@@ -2563,8 +2839,8 @@ qrouter_congested(ClientData clientData, Tcl_Interp *interp,
for (x = net->xmin; x < net->xmax; x++)
for (y = net->ymin; y < net->ymax; y++)
- if (x >= 0 && x < NumChannelsX[0] &&
- y >= 0 && y < NumChannelsY[0])
+ if (x >= 0 && x < NumChannelsX &&
+ y >= 0 && y < NumChannelsY)
CONGEST(x, y) += density;
}
@@ -2589,12 +2865,12 @@ qrouter_congested(ClientData clientData, Tcl_Interp *interp,
cgates[i] = (CLIST)malloc(sizeof(Clist));
dx = gsrch->placedX;
dy = gsrch->placedY;
- bbox.x1 = (int)((dx - Xlowerbound) / PitchX[0]) - 1;
- bbox.y1 = (int)((dy - Ylowerbound) / PitchY[0]) - 1;
+ bbox.x1 = (int)((dx - Xlowerbound) / PitchX) - 1;
+ bbox.y1 = (int)((dy - Ylowerbound) / PitchY) - 1;
dx = gsrch->placedX + gsrch->width;
dy = gsrch->placedY + gsrch->height;
- bbox.x2 = (int)((dx - Xlowerbound) / PitchX[0]) - 1;
- bbox.y2 = (int)((dy - Ylowerbound) / PitchY[0]) - 1;
+ bbox.x2 = (int)((dx - Xlowerbound) / PitchX) - 1;
+ bbox.y2 = (int)((dy - Ylowerbound) / PitchY) - 1;
cavg = 0.0;
for (x = bbox.x1; x <= bbox.x2; x++) {
@@ -2680,7 +2956,7 @@ qrouter_print(ClientData clientData, Tcl_Interp *interp,
switch (idx) {
case NetIdx:
- net = LookupNet(Tcl_GetString(objv[2]));
+ net = DefFindNet(Tcl_GetString(objv[2]));
if (net == NULL) {
Tcl_SetResult(interp, "Net not found", NULL);
return TCL_ERROR;
@@ -2700,7 +2976,7 @@ qrouter_print(ClientData clientData, Tcl_Interp *interp,
break;
case GateIdx:
- gate = LookupGate(Tcl_GetString(objv[2]));
+ gate = DefFindGate(Tcl_GetString(objv[2]));
if (gate == NULL) {
Tcl_SetResult(interp, "Gate not found", NULL);
return TCL_ERROR;