1 /*
2 * grouteMulti.c
3 *
4 * Route a multi-terminal net.
5 * Currently includes just a single algorithm, for routing a net
6 * where arbitrary branching is allowed. This algorithm produces
7 * something like a steiner-tree, with intermediate points introduced
8 * at channel boundaries.
9 *
10 * *********************************************************************
11 * * Copyright (C) 1985, 1990 Regents of the University of California. *
12 * * Permission to use, copy, modify, and distribute this *
13 * * software and its documentation for any purpose and without *
14 * * fee is hereby granted, provided that the above copyright *
15 * * notice appear in all copies. The University of California *
16 * * makes no representations about the suitability of this *
17 * * software for any purpose. It is provided "as is" without *
18 * * express or implied warranty. Export of this software outside *
19 * * of the United States of America may require an export license. *
20 * *********************************************************************
21 */
22
23 #ifndef lint
24 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/grouter/grouteMult.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
25 #endif /* lint */
26
27 #include <stdio.h>
28 #include "utils/magic.h"
29 #include "utils/geometry.h"
30 #include "utils/hash.h"
31 #include "utils/heap.h"
32 #include "tiles/tile.h"
33 #include "database/database.h"
34 #include "router/router.h"
35 #include "gcr/gcr.h"
36 #include "grouter/grouter.h"
37 #include "utils/netlist.h"
38 #include "utils/signals.h"
39 #include "textio/textio.h"
40 #include "utils/malloc.h"
41 #include "utils/styles.h"
42 #include "windows/windows.h"
43 #include "dbwind/dbwind.h"
44
45 /* Forward declarations */
46
47 void glMultiAddStart();
48
49
50 /*
51 * ----------------------------------------------------------------------------
52 *
53 * glMultiSteiner --
54 *
55 * Perform global routing for all segments of a net.
56 * The caller supplies two procedures: one to produce a list of
57 * GlPoints from any of a set of possible starting points to the
58 * single destination, and the other to accept a list of GlPoints
59 * and remember it permanently, e.g, in the form of crossing assignments.
60 *
61 * The two procedures are of the following form:
62 *
63 * GlPoint *
64 * (*routeProc)(startList, loc, bestCost, cdRoute)
65 * GlPoint *startList; --- list of GlPoints that are possible
66 * --- starting points for the route; the
67 * --- points in the list are linked via gl_path
68 * --- fields as though they were a path.
69 * NLTermLoc *loc; --- loc->nloc_pin is the destination
70 * int bestCost; --- return NULL if we can't beat this cost
71 * ClientData cdRoute; --- same as cdRoute passed to us
72 * {
73 * }
74 *
75 * int
76 * (*markProc)(rootUse, path, pNetId, cdMark)
77 * CellUse *rootUse; --- leave feedback here if necessary and if
78 * --- rootUse is non-NULL
79 * GlPoint *path; --- path to be marked
80 * NetId *pNetId; --- netid_net is the argument 'net' to
81 * --- glMultiSteiner; netid_seg will be
82 * --- incremented for each new segment id
83 * --- assigned.
84 * ClientData cdMark; --- same as 'cdMark' passed to us
85 * {
86 * }
87 *
88 *
89 * Assumptions:
90 * The net has at least two terminals, each of which has at least
91 * one valid location.
92 *
93 * Algorithm:
94 * Multiterminal nets are routed using an algorithm that finds
95 * pseudo-Steiner tree routes. The idea is to process the
96 * terminals of the net in the order they appear in the netlist.
97 * Processing consists of finding the shortest path from the
98 * terminal being considered to all of the terminals processed
99 * before it, or to any of the crossing points used by the routes
100 * used to connect these previously-processed terminals.
101 *
102 * Results:
103 * Returns the number of terminals processed.
104 *
105 * Side effects:
106 * Whatever (*routeProc)() and (*markProc)() do.
107 *
108 * ----------------------------------------------------------------------------
109 */
110
111 int
glMultiSteiner(rootUse,net,routeProc,markProc,cdRoute,cdMark)112 glMultiSteiner(rootUse, net, routeProc, markProc, cdRoute, cdMark)
113 CellUse *rootUse; /* If non-NULL, feedback for errors left here */
114 NLNet *net; /* Net to process */
115 GlPoint *(*routeProc)(); /* Procedure to route a segment */
116 int (*markProc)(); /* Procedure to remember the route */
117 ClientData cdRoute; /* Passed to (*routeProc)() */
118 ClientData cdMark; /* Passed to (*markProc)() */
119 {
120 GlPoint *startList, *bestDest, *dest;
121 char mesg[128], *lastTermName;
122 int bestCost, nterms;
123 NLTermLoc *loc;
124 NLTerm *term;
125 Rect errorArea;
126 NetId netid;
127
128 /* Skip to the first term that has a location */
129 ASSERT(net != (NLNet *) NULL, "glMultiSteiner");
130 for (term = net->nnet_terms; term; term = term->nterm_next)
131 if (term->nterm_locs)
132 break;
133 ASSERT(term != (NLTerm *) NULL, "glMultiSteiner");
134
135 /*
136 * For the first terminal in the net, mark the point where the terminal
137 * enters its adjacent channel. If there are several electrically
138 * equivalent terminals, then mark them all.
139 */
140 nterms = 0;
141 startList = (GlPoint *) NULL;
142 lastTermName = term->nterm_name;
143 for (loc = term->nterm_locs; loc; loc = loc->nloc_next)
144 glListAdd(&startList, loc->nloc_pin, glMultiStemCost(loc));
145
146 /* Process all other terminals in net */
147 netid.netid_net = net;
148 netid.netid_seg = 1;
149 for (term = term->nterm_next; term; term = term->nterm_next)
150 {
151 /*
152 * Skip if no valid locations exist for this terminal;
153 * the error has already been reported (either in the
154 * stem generator or the netlist reader).
155 */
156 if (term->nterm_locs == (NLTermLoc *) NULL)
157 continue;
158
159 /*
160 * Consider routing to each of the possible locations for
161 * this terminal, and use the best path. (The comparison of
162 * route cost includes the final channel in each path).
163 * After each call to rgRoutePath, 'dest' will be a GlPoint
164 * for one of the zero-cost points to 'loc' (or NULL if no
165 * path could be found).
166 */
167 bestCost = INFINITY;
168 bestDest = (GlPoint *) NULL;
169 for (loc = term->nterm_locs; loc; loc = loc->nloc_next)
170 {
171 nterms++;
172
173 /* Try to find a path from a zero-cost point to loc */
174 dest = (*routeProc)(startList, loc, bestCost, cdRoute);
175
176 /* Remember it if it was better than the previous best */
177 if (dest && dest->gl_cost < bestCost)
178 {
179 if (bestDest) glPathFreePerm(bestDest);
180 bestDest = glPathCopyPerm(dest);
181 bestCost = dest->gl_cost;
182 }
183
184 /* Free all temporary storage used for GlPoints */
185 glPathFreeTemp();
186 }
187
188 /*
189 * If we were successful in finding a path, add the crossing points
190 * to the zero-cost list, mark all the crossings it used as allocated,
191 * and update the segment-id.
192 */
193 if (bestDest)
194 {
195 glMultiAddStart(bestDest, &startList);
196 (*markProc)(rootUse, bestDest, &netid, cdMark);
197 glPathFreePerm(bestDest);
198
199 /*
200 * Finally, move all of the locations for the terminal just
201 * processed to the zero-cost list, since any of them can
202 * be used as a new starting point.
203 */
204 for (loc = term->nterm_locs; loc; loc = loc->nloc_next)
205 glListAdd(&startList, loc->nloc_pin, glMultiStemCost(loc));
206 lastTermName = term->nterm_name;
207 }
208 else
209 {
210 GEO_EXPAND(&term->nterm_locs->nloc_rect, 1, &errorArea);
211 sprintf(mesg, "Can't find a path from \"%s\" to \"%s\"",
212 term->nterm_name, lastTermName);
213 if (rootUse)
214 DBWFeedbackAdd(&errorArea, mesg, rootUse->cu_def,
215 1, STYLE_PALEHIGHLIGHTS);
216 else TxError("%s\n", mesg);
217 }
218 }
219
220 /* Free the list of starting points */
221 glPathFreePerm(startList);
222 return nterms;
223 }
224
225 /*
226 * ----------------------------------------------------------------------------
227 *
228 * glMultiStemCost --
229 *
230 * Compute the initial cost of a terminal. This is the cost from the
231 * terminal loc->nloc_rect to its initial crossing point loc->nloc_stem.
232 *
233 * Results:
234 * Returns the Manhattan distance just described.
235 *
236 * Side effects:
237 * None.
238 *
239 * ----------------------------------------------------------------------------
240 */
241
242 int
glMultiStemCost(loc)243 glMultiStemCost(loc)
244 NLTermLoc *loc;
245 {
246 int n1, n2, cost;
247
248 n1 = ABSDIFF(loc->nloc_stem.p_x, loc->nloc_rect.r_xbot);
249 n2 = ABSDIFF(loc->nloc_stem.p_x, loc->nloc_rect.r_xtop);
250 cost = MIN(n1, n2);
251 n1 = ABSDIFF(loc->nloc_stem.p_y, loc->nloc_rect.r_ybot);
252 n2 = ABSDIFF(loc->nloc_stem.p_y, loc->nloc_rect.r_ytop);
253 cost += MIN(n1, n2);
254
255 return cost;
256 }
257
258 /*
259 * ----------------------------------------------------------------------------
260 *
261 * glMultiAddStart --
262 *
263 * Add all the pins along the GlPoint 'path' to the list of
264 * starting points '*pStartList'. For each crossing we add
265 * up to two pins: one on each side of the crossing.
266 * If a pin has already been marked as belonging to
267 * a net, we don't add it, since it was already added
268 * in an earlier iteration.
269 *
270 * Results:
271 * None.
272 *
273 * Side effects:
274 * Prepends the GlPoints on the list 'path' to the list of
275 * starting points *pStart.
276 *
277 * ----------------------------------------------------------------------------
278 */
279
280 void
glMultiAddStart(path,pStartList)281 glMultiAddStart(path, pStartList)
282 GlPoint *path; /* Path linked via gl_path pointers */
283 GlPoint **pStartList; /* List of starting points */
284 {
285 GlPoint *srcEntry, *dstEntry;
286 GCRPin *srcPin, *dstPin;
287
288 /*
289 * Walk from path back along gl_path pointers down the list.
290 * At each step, process the segment between srcEntry and
291 * dstEntry in the channel srcEntry->gl_pin->gcr_ch.
292 */
293 for (srcEntry = path->gl_path, dstEntry = path;
294 srcEntry;
295 dstEntry = srcEntry, srcEntry = srcEntry->gl_path)
296 {
297 /* Use srcPin's channel for both srcPin and dstPin */
298 srcPin = srcEntry->gl_pin;
299 dstPin = dstEntry->gl_pin;
300 if (dstPin->gcr_ch != srcPin->gcr_ch) dstPin = dstPin->gcr_linked;
301 ASSERT(dstPin && dstPin->gcr_ch == srcPin->gcr_ch, "glMultiAddStart");
302
303 /* Add to list of starting points */
304 if (srcPin->gcr_pId == NULL || srcPin->gcr_pSeg == GCR_STEMSEGID)
305 glListAdd(pStartList, srcPin, 0);
306 glListAdd(pStartList, dstPin, 0);
307 }
308 }
309