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