1 /*
2  * mzSubrs.c --
3  *
4  * Misc. surport routines for the Maze router.
5  *
6  *     *********************************************************************
7  *     * Copyright (C) 1988, 1990 Michael H. Arnold and the Regents of the *
8  *     * University of California.                                         *
9  *     * Permission to use, copy, modify, and distribute this              *
10  *     * software and its documentation for any purpose and without        *
11  *     * fee is hereby granted, provided that the above copyright          *
12  *     * notice appear in all copies.  The University of California        *
13  *     * makes no representations about the suitability of this            *
14  *     * software for any purpose.  It is provided "as is" without         *
15  *     * express or implied warranty.  Export of this software outside     *
16  *     * of the United States of America may require an export license.    *
17  *     *********************************************************************
18  */
19 
20 #ifndef lint
21 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/mzrouter/mzSubrs.c,v 1.2 2008/06/01 18:37:44 tim Exp $";
22 #endif  /* not lint */
23 
24 #include <stdio.h>
25 
26 #include "utils/magic.h"
27 #include "utils/geometry.h"
28 #include "tiles/tile.h"
29 #include "utils/hash.h"
30 #include "database/database.h"
31 #include "drc/drc.h"
32 #include "select/select.h"
33 #include "utils/signals.h"
34 #include "textio/textio.h"
35 #include "windows/windows.h"
36 #include "dbwind/dbwind.h"
37 #include "utils/styles.h"
38 #include "debug/debug.h"
39 #include "utils/undo.h"
40 #include "textio/txcommands.h"
41 #include "utils/malloc.h"
42 #include "utils/main.h"
43 #include "utils/geofast.h"
44 #include "utils/list.h"
45 #include "utils/touchingtypes.h"
46 #include "utils/heap.h"
47 #include "mzrouter/mzrouter.h"
48 #include "mzrouter/mzInternal.h"
49 
50 
51 
52 /*
53  * ----------------------------------------------------------------------------
54  *
55  * mzComputeDerivedParms --
56  *
57  * Processes current parms deriving some parameters from others.
58  *
59  * Results:
60  *	None
61  *
62  * Side effects:
63  *      Modifies current parms.
64  *
65  * ----------------------------------------------------------------------------
66  */
67 
68 void
mzComputeDerivedParms()69 mzComputeDerivedParms()
70 {
71     RouteContact *rC;
72     RouteLayer *rL;
73     RouteType *rT;
74 
75     /* Compute active routelayer list */
76     mzActiveRLs = NULL;
77     for(rL=mzRouteLayers; rL!=NULL; rL=rL->rl_next)
78     {
79 	if(rL->rl_routeType.rt_active)
80 	{
81 	    rL->rl_nextActive = mzActiveRLs;
82 	    mzActiveRLs = rL;
83 	}
84     }
85 
86     /* Compute active routetype list */
87     mzActiveRTs = NULL;
88     for(rT=mzRouteTypes; rT!=NULL; rT=rT->rt_next)
89     {
90 	if(rT->rt_active)
91 	{
92 	    rT->rt_nextActive = mzActiveRTs;
93 	    mzActiveRTs = rT;
94 	}
95     }
96 
97     /* Compute bloats and effWidth for route layers.
98      * Since we are routing bottom left edge of wires:
99      *     bloat to bottom = spacing + width - 1;
100      *     bloat to top = spacing
101      */
102     for(rL=mzRouteLayers; rL!=NULL; rL=rL->rl_next)
103     {
104 	RouteType *rT = &(rL->rl_routeType);
105 	int i;
106 
107 	rT->rt_effWidth = rT->rt_width;
108 
109         for(i=0;i<=TT_MAXTYPES;i++)
110 	{
111 	    if(rT->rt_spacing[i]>=0)
112 	    {
113 		rT->rt_bloatBot[i] = rT->rt_width + rT->rt_spacing[i] - 1;
114 		rT->rt_bloatTop[i] = rT->rt_spacing[i];
115 	    }
116 	    else
117 	    {
118 		rT->rt_bloatBot[i] = -1;
119 		rT->rt_bloatTop[i] = -1;
120 	    }
121 	}
122     }
123 
124     /* contact widths and bloats are max of components */
125     for(rC=mzRouteContacts; rC!=NULL; rC=rC->rc_next)
126     {
127 	RouteType *rT = &(rC->rc_routeType);
128 	RouteType *rT1 = &(rC->rc_rLayer1->rl_routeType);
129 	RouteType *rT2 = &(rC->rc_rLayer2->rl_routeType);
130 	int i;
131 
132 	rT->rt_effWidth = MAX(MAX(rT1->rt_width,rT2->rt_width),rT->rt_width);
133 
134         for(i=0;i<=TT_MAXTYPES;i++)
135 	{
136 	    int bot, bot1, bot2;
137 	    int top, top1, top2;
138 
139 	    if(rT->rt_spacing[i]>=0)
140 	    {
141 		bot = rT->rt_width + rT->rt_spacing[i] - 1;
142 		top = rT->rt_spacing[i];
143 	    }
144 	    else
145 	    {
146 		bot = -1;
147 		top = -1;
148 	    }
149 
150 	    if(rT1->rt_spacing[i]>=0)
151 	    {
152 		bot1 = rT1->rt_width + rT1->rt_spacing[i] - 1;
153 		top1 = rT1->rt_spacing[i];
154 	    }
155 	    else
156 	    {
157 		bot1 = -1;
158 		top1 = -1;
159 	    }
160 
161 	    if(rT2->rt_spacing[i]>=0)
162 	    {
163 		bot2 = rT2->rt_width + rT2->rt_spacing[i] - 1;
164 		top2 = rT2->rt_spacing[i];
165 	    }
166 	    else
167 	    {
168 		bot2 = -1;
169 		top2 = -1;
170 	    }
171 
172 	    rT->rt_bloatBot[i] = MAX(MAX(bot1,bot2),bot);
173 	    rT->rt_bloatTop[i] = MAX(MAX(top1,top2),top);
174 	}
175     }
176 
177     /*
178      * compute context radius = how much to bloat blockage area
179      * to be built to obtain search area for mask data.
180      */
181     {
182         int i;
183 
184 	mzContextRadius = 0;
185 	for(rT=mzActiveRTs; rT!=NULL; rT=rT->rt_nextActive)
186         for(i=0;i<=TT_MAXTYPES;i++)
187 	mzContextRadius = MAX(mzContextRadius,rT->rt_bloatBot[i]);
188     }
189 
190     /* If max walk length is -1, set to twice the context radius */
191     if(mzMaxWalkLength==-1)
192     {
193 	mzMaxWalkLength = mzContextRadius * 2;
194     }
195 
196     /* If bounds increment is -1, set to 30 times min active pitch */
197     if(mzBoundsIncrement==-1)
198     {
199 	int minPitch = INFINITY;
200 
201 	for(rL=mzActiveRLs; rL!=NULL; rL=rL->rl_nextActive)
202 	{
203 	    RouteType *rT = &(rL->rl_routeType);
204 	    int pitch = rT->rt_width + rT->rt_spacing[rT->rt_tileType];
205 
206 	    minPitch = MIN(minPitch, pitch);
207 	}
208 
209 	if(minPitch==INFINITY)
210 	/* Don't coredump just because no active rL's */
211 	{
212 	    mzBoundsIncrement = 100;
213 	}
214 	else
215 	{
216 	    mzBoundsIncrement = 30*minPitch;
217 	}
218     }
219 
220     /* Set up (global) bounding rect for route */
221     if(mzBoundsHint)
222     /* Blockage gen will be confined to user supplied hint (+ 2 units)
223      * generate slightly larger bounds for other purposes (estimate generation
224      * and marking of tiles connected to dest nodes, for example) to avoid
225      * edge effects.
226      */
227     {
228 	mzBoundingRect = *mzBoundsHint;
229 
230 	mzBoundingRect.r_xbot -= 2*mzContextRadius;
231 	mzBoundingRect.r_ybot -= 2*mzContextRadius;
232 	mzBoundingRect.r_xtop += 2*mzContextRadius;
233 	mzBoundingRect.r_ytop += 2*mzContextRadius;
234     }
235     else
236     /* No user supplied bounds, shrink maximum paintable rect by a
237      * conservative amount (to avoid overflow during blockage
238      * plane generation etc.)
239      */
240     {
241 	int maxWidth, maxSpacing, safeHalo;
242 	RouteType *rT;
243 
244 	mzBoundingRect = TiPlaneRect;
245 
246 	maxWidth = 0;
247 	maxSpacing = 0;
248 	for (rT = mzRouteTypes; rT!=NULL; rT=rT->rt_next)
249 	{
250 	    int i;
251 
252 	    maxWidth = MAX(maxWidth,rT->rt_width);
253 	    for(i=0;i<TT_MAXTYPES+1;i++)
254 		maxSpacing = MAX(maxSpacing,rT->rt_spacing[i]);
255 	}
256 	safeHalo = 3 * (maxSpacing + maxWidth + 2);
257 
258 	mzBoundingRect.r_xbot += safeHalo;
259 	mzBoundingRect.r_xtop -= safeHalo;
260 	mzBoundingRect.r_ybot += safeHalo;
261 	mzBoundingRect.r_ytop -= safeHalo;
262 
263 	ASSERT(mzBoundingRect.r_xbot < mzBoundingRect.r_xtop,
264 	       "mzComputeDerivedParms");
265 	ASSERT(mzBoundingRect.r_ybot < mzBoundingRect.r_ytop,
266 	       "mzComputeDerivedParms");
267     }
268 }
269 
270 int mzMakeEndpoints;  /* Set to MZ_EXPAND_START, MZ_EXPAND_DEST, or
271 		       * MZ_EXPAND_NONE.
272 		       */
273 /*
274  * ----------------------------------------------------------------------------
275  *
276  * mzMarkConnectedTiles --
277  *
278  * Marks tiles connected to given area on given layer in mask data.
279  * Used to mark tiles that are part of start or dest nodes.
280  *
281  * If mzExpandEndpoints is set, also adds dest areas for connected tiles.
282  *
283  * Results:
284  *	none.
285  *
286  * Side effects:
287  *	See above.
288  *
289  * ----------------------------------------------------------------------------
290  */
291 
292 void
mzMarkConnectedTiles(rect,type,expandType)293 mzMarkConnectedTiles(rect, type, expandType)
294     Rect *rect;
295     TileType type;
296     int expandType;
297 {
298     List *expandList = NULL;	/* areas remaining to be expanded from */
299 
300     /* set global controlling the creation of dest areas for each connected
301      * tile found.
302      */
303     mzMakeEndpoints = expandType;
304 
305     /* Create colored rect corresponding to passed args and initial
306      *  expandList with it.
307      */
308     {
309 	ColoredRect *e;
310 	e = (ColoredRect *) mallocMagic((unsigned)(sizeof(ColoredRect)));
311 	e->cr_type = type;
312 	e->cr_rect = *rect;
313 	LIST_ADD(e, expandList);
314     }
315 
316     /* repeatedly expand from top area on expandList */
317     while(expandList)
318     {
319 	ColoredRect *e = (ColoredRect *) LIST_FIRST(expandList);
320 	SearchContext scx;
321 	TileTypeBitMask typeMask;
322 	int mzConnectedTileFunc();
323 
324 	/* Restrict marking to route bounds */
325 	if(GEO_OVERLAP(&mzBoundingRect, &(e->cr_rect)))
326 	{
327 	    /* Set search area to colored rect */
328 	    scx.scx_trans = GeoIdentityTransform;
329 	    scx.scx_use = mzRouteUse;
330 	    scx.scx_area = e->cr_rect;
331 
332 	    /* Grow search area by one unit in each direction so that in
333 	     * addition to overlapping
334 	     * tiles we also get those that just touch it.
335 	     */
336 	    scx.scx_area.r_xbot -= 1;
337 	    scx.scx_area.r_ybot -= 1;
338 	    scx.scx_area.r_xtop += 1;
339 	    scx.scx_area.r_ytop += 1;
340 
341 	    /* Build type mask with just the type of e set */
342 	    TTMaskSetOnlyType(&typeMask, e->cr_type);
343 
344 	    /* search for connecting tiles, mark them, and add them to
345 	     * expandList (They are inserted
346 	     * AFTER the first (= current) element.)
347 	     */
348 	    (void)
349 	    DBTreeSrTiles(
350 			  &scx,
351 			  &(DBConnectTbl[e->cr_type]), /* enumerate all
352 							* tiles of connecting
353 							* types */
354 			  mzCellExpansionMask,
355 			  mzConnectedTileFunc,
356 			  (ClientData) expandList);
357 	}
358 
359 	/* Done processing top element of expandList, toss it */
360 	e = (ColoredRect *) ListPop(&expandList);
361 	freeMagic((char *) e);
362     }
363 
364 
365     /* mark unexpanded subcells intersecting dest area */
366     {
367 	if(mzCellExpansionMask != 0)
368 	{
369 	    int mzConnectedSubcellFunc();
370 	    SearchContext scx;
371 
372 	    scx.scx_trans = GeoIdentityTransform;
373 	    scx.scx_use = mzRouteUse;
374 	    scx.scx_area = *rect;
375 
376 	    /* clip area to bounding box to avoid overflow during transforms */
377 	    GEOCLIP(&(scx.scx_area),&(mzRouteUse->cu_def->cd_bbox));
378 
379 	    /* clip to route bounds for performance */
380 	    GEOCLIP(&(scx.scx_area),&mzBoundingRect);
381 
382 	    DBTreeSrCells(
383 			  &scx,
384 			  mzCellExpansionMask,
385 			  mzConnectedSubcellFunc,
386 			  (ClientData) NULL);
387 	}
388     }
389 
390     return;
391 }
392 
393 
394 /*
395  * ---------------------------------------------------------------------
396  *
397  * mzConnectedTileFunc --
398  *
399  * Called by MZAddDest to mark mask data tile connected to a dest terminal.
400 
401  *
402  * Results:
403  *	Always returns 0 to continue search.
404  *
405  * Side effects:
406  *	Mark clientdata fileds of connected tiles.
407  *	Add freshly marked tiles to expandList (for recursive expansion).
408  *      If mzExpandEndpoints is set, also adds dest areas for connected
409  *	tiles.
410  *
411  * ---------------------------------------------------------------------
412  */
413 
414 int
mzConnectedTileFunc(tile,cxp)415 mzConnectedTileFunc(tile, cxp)
416     Tile *tile;
417     TreeContext *cxp;
418 {
419     /* If tile not marked, mark it, add it to marked list, and add
420      * corresponding area to expand list.  Mark start tiles MZ_EXPAND_START
421      * and destination tiles MZ_EXPAND_DEST so that we don't have to run
422      * the tile cleanup routing (in MZClean()) unnecessarily between
423      * MZAddStart() and MZAddDest().
424      */
425 
426     if ((int)tile->ti_client != mzMakeEndpoints)
427     {
428 	SearchContext *scx = cxp->tc_scx;
429 	List *expandList = (List *) (cxp->tc_filter->tf_arg);
430 	Rect rRaw, r;
431 
432 	/* Get bounding box of tile */
433 	TITORECT(tile, &rRaw);
434 	GEOTRANSRECT(&scx->scx_trans, &rRaw, &r);
435 
436 	/* mark tile with destination type */
437 	tile->ti_client = (ClientData) mzMakeEndpoints;
438 
439 	/* Add tiles connected to Start to mzStartTerms */
440 	/* (Added by Tim, August 2006)			*/
441 
442 	if (mzMakeEndpoints == MZ_EXPAND_START)
443 	{
444 	    ColoredRect *newTerm;
445 	    extern List *mzStartTerms;
446 
447             newTerm = (ColoredRect *) mallocMagic((unsigned)(sizeof(ColoredRect)));
448             newTerm->cr_rect = r;
449             newTerm->cr_type = TiGetType(tile);
450             LIST_ADD(newTerm, mzStartTerms);
451 	}
452 
453 	/* Add dest area (if appropriate).  Don't paint contact types,	*/
454 	/* or the planes will get fractured up, possibly into areas too	*/
455 	/* small to place a valid route.				*/
456 
457 	else if (mzMakeEndpoints == MZ_EXPAND_DEST)
458 	{
459 	    RouteLayer *rL;
460 	    TileType ttype = TiGetType(tile);
461 
462 	    for(rL=mzRouteLayers; rL!=NULL; rL=rL->rl_next)
463 	    {
464 		if (rL->rl_routeType.rt_active &&
465 		   TTMaskHasType(&(DBConnectTbl[ttype]),
466 				   rL->rl_routeType.rt_tileType))
467 		{
468 		    DBPaint(mzDestAreasUse->cu_def,
469 			    &r,
470 			    rL->rl_routeType.rt_tileType);
471 		}
472 	    }
473 	}
474 
475 	/* add entry to expandList */
476 	{
477 	    ColoredRect *e;
478 
479 	    /* build colored rect corresponding to tile */
480 	    e = (ColoredRect *) mallocMagic((unsigned)(sizeof(ColoredRect)));
481 	    e->cr_type = TiGetType(tile);
482 	    e->cr_rect = r;
483 
484 	    /* add new entry to second position of expandList (just
485 	     * past current entry)
486 	     */
487 	    LIST_ADD(e, LIST_TAIL(expandList));
488 	}
489     }
490 
491     /* return 0 to continue search */
492     return 0;
493 }
494 
495 
496 /*
497  * ----------------------------------------------------------------------------
498  *
499  * mzConnectedSubcellFunc --
500  *
501  * Called by MZAddDest to mark subcells overlapping a dest terminal.
502  * (The blockage generation code treats marked subcells as same-node geometry,
503  * allowing walks and dest areas near them.)
504  *
505  * Results:
506  *	Always returns 0 (to continue search)
507  *
508  * Side effects:
509  *	Mark client field in subcell use, and add use to list of marked
510  *      subcells.
511  *
512  * ----------------------------------------------------------------------------
513  */
514 
515 int
mzConnectedSubcellFunc(scx,cdarg)516 mzConnectedSubcellFunc(scx, cdarg)
517     SearchContext *scx;
518     ClientData cdarg;
519 {
520     CellUse *cu = scx->scx_use;
521 
522     /* If not already marked, mark celluse and add to marked list */
523     if (cu->cu_client == (ClientData)MZ_EXPAND_NONE)
524     {
525 	cu->cu_client = (ClientData)MZ_EXPAND_DEST;
526 	LIST_ADD(cu, mzMarkedCellsList);
527     }
528 
529     /* continue search */
530     return (0);
531 }
532 
533 /*
534  * ----------------------------------------------------------------------------
535  *
536  * mzGetContact --
537  *
538  * Get the RouteContact record that matches the contact type between
539  * planes path->rp_rLayer and prev->rp_rLayer,
540  *
541  * Results:
542  *	A pointer to the appropriate RouteContact structure, or NULL if
543  *	none exists (which shouldn't happen).
544  *
545  * Side effects:
546  *	None.
547  *
548  * ----------------------------------------------------------------------------
549  */
550 
551 RouteContact *
MZGetContact(path,prev)552 MZGetContact(path, prev)
553     RoutePath *path, *prev;
554 {
555     RouteContact *rC;
556     List *cL;
557 
558     /* Find RouteContact connecting the route layers of path and prev.  */
559 
560     for (cL = path->rp_rLayer->rl_contactL;  cL != NULL &&
561 	    ((RouteContact*)LIST_FIRST(cL))->rc_rLayer1 != prev->rp_rLayer &&
562 	    ((RouteContact*)LIST_FIRST(cL))->rc_rLayer2 != prev->rp_rLayer;
563 	    cL = LIST_TAIL(cL));
564 
565     ASSERT(cL != NULL, "mzPaintContact");
566     rC = ((RouteContact*)LIST_FIRST(cL));
567 
568     return rC;
569 }
570 
571 /*
572  * ----------------------------------------------------------------------------
573  *
574  * mzPaintContact --
575  *
576  * Paint a single contact between planes path->rp_rLayer and prev->rp_rLayer,
577  *
578  * Results:
579  *	None.
580  *
581  * Side effects:
582  *	Updates both mask and blockage planes.
583  *
584  * ----------------------------------------------------------------------------
585  */
586 
587 int
mzPaintContact(path,prev)588 mzPaintContact(path, prev)
589     RoutePath *path, *prev;
590 {
591     RouteContact *rC;
592     int pNum, pNumC, cWidth;
593     Rect r;
594     TileType cType;
595 
596     rC = MZGetContact(path, prev);
597 
598     /* compute the contact tileType */
599     cType = rC->rc_routeType.rt_tileType;
600     cWidth = rC->rc_routeType.rt_width;
601 
602     /* compute bounds of contact tile */
603     r.r_ll = path->rp_entry;
604 
605     if (path->rp_orient == 'X')
606     {
607 	r.r_xtop = r.r_xbot + cWidth;
608 	r.r_ytop = r.r_ybot + rC->rc_routeType.rt_length;
609     }
610     else if (path->rp_orient == 'O')
611     {
612 	r.r_xtop = r.r_xbot + rC->rc_routeType.rt_length;
613 	r.r_ytop = r.r_ybot + cWidth;
614     }
615     else	/* Type "C", residues only */
616     {
617 	r.r_xtop = r.r_xbot + cWidth;
618 	r.r_ytop = r.r_ybot + cWidth;
619     }
620 
621     /* Paint the contact on all connected mask planes */
622     /* (should just let DBPaint() do this. . . ) */
623 
624     if (DBIsContact(cType))
625     {
626 	if (path->rp_orient != 'C')
627 	{
628 	    for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
629 		if (PlaneMaskHasPlane(DBConnPlanes[cType], pNum))
630 		    DBPaintPlane(mzResultDef->cd_planes[pNum],
631 				&r, DBStdPaintTbl(cType, pNum),
632 				(PaintUndoInfo *) NULL);
633 	}
634 	else
635 	{
636 	    /* Paint residues, not the contact type, to avoid DRC errors */
637 	    RouteLayer *rL;
638 
639 	    rL = rC->rc_rLayer1;
640 	    DBPaintPlane(mzResultDef->cd_planes[rL->rl_planeNum], &r,
641 			DBStdPaintTbl(rL->rl_routeType.rt_tileType,
642 			rL->rl_planeNum), (PaintUndoInfo *)NULL);
643 	    rL = rC->rc_rLayer2;
644 	    DBPaintPlane(mzResultDef->cd_planes[rL->rl_planeNum], &r,
645 			DBStdPaintTbl(rL->rl_routeType.rt_tileType,
646 			rL->rl_planeNum), (PaintUndoInfo *)NULL);
647 	}
648     }
649     return cWidth;
650 }
651 
652 
653 /*
654  * ----------------------------------------------------------------------------
655  *
656  * mzCopyPath --
657  *
658  * Copy a RoutePath from the temporary arena into permanent storage
659  * allocated via mallocMagic.
660  *
661  * Results:
662  *	Returns a pointer to a copy of the RoutePath passed to us
663  *	as an argument.
664  *
665  * Side effects:
666  *	Allocates memory.
667  *
668  * ----------------------------------------------------------------------------
669  */
670 
671 RoutePath *
mzCopyPath(path)672 mzCopyPath(path)
673     RoutePath *path;
674 {
675     RoutePath *newHead, *newPrev, *new;
676 
677     newPrev = newHead = (RoutePath *) NULL;
678     for (newPrev = NULL; path; newPrev = new, path = path->rp_back)
679     {
680 	new = (RoutePath *) mallocMagic((unsigned)(sizeof (RoutePath)));
681 	*new = *path;
682 	if (newPrev) newPrev->rp_back = new;
683 	if (newHead == NULL) newHead = new;
684     }
685 
686     return (newHead);
687 }
688 
689 /*--------------- Static variables only referenced by RPath allocation
690                   and deallocation routines below ----------------------- */
691 
692 /* First, last, and current RoutePages on list for allocating RoutePaths */
693 RoutePage *mzFirstPage = NULL;
694 RoutePage *mzLastPage = NULL;
695 RoutePage *mzCurPage = NULL;
696 
697 
698 /*
699  * ----------------------------------------------------------------------------
700  *
701  * mzAllocRPath --
702  *
703  * Allocate a new RoutePath from our temporary RoutePath arena.
704  *
705  * Results:
706  *	Returns a pointer to a newly allocated RoutePath.
707  *	This RoutePath is NOT allocated directly via
708  *	mallocMagic/freeMagic,
709  *	but rather via our own temporary mechanism.  It goes away
710  *	once mzFreeAllTemp() gets called, so callers that wish to
711  *	retain the "best" RoutePath must call mzCopyPath() to
712  *	preserve it.
713  *
714  * Side effects:
715  *	May allocate memory.
716  *
717  * ----------------------------------------------------------------------------
718  */
719 
720 RoutePath *
mzAllocRPath()721 mzAllocRPath()
722 {
723     /* Skip to next page if this one is full */
724     if (mzCurPage && mzCurPage->rpp_free >= PATHSPERSEG)
725 	mzCurPage = mzCurPage->rpp_next;
726 
727     /* If out of pages, allocate a new one */
728     if (mzCurPage == NULL)
729     {
730 	mzCurPage = (RoutePage *) mallocMagic((unsigned)(sizeof (RoutePage)));
731 	mzCurPage->rpp_next = (RoutePage *) NULL;
732 	mzCurPage->rpp_free = 0;
733 	if (mzLastPage == NULL)
734 	    mzFirstPage = mzLastPage = mzCurPage;
735 	else
736 	    mzLastPage->rpp_next = mzCurPage, mzLastPage = mzCurPage;
737     }
738 
739     return (&mzCurPage->rpp_array[mzCurPage->rpp_free++]);
740 }
741 
742 /*
743  * ----------------------------------------------------------------------------
744  *
745  * mzFreeAllRPaths --
746  *
747  * Reset the temporary arena used for allocating RoutePaths.
748  *
749  * Results:
750  *	None.
751  *
752  * Side effects:
753  *	Any RoutePaths in the arena become available again for
754  *	allocation.  Callers wishing to preserve paths must
755  *	do so by calling mzCopyPath().
756  *
757  * ----------------------------------------------------------------------------
758  */
759 
760 void
mzFreeAllRPaths()761 mzFreeAllRPaths()
762 {
763     RoutePage *rpage;
764 
765     for (rpage = mzFirstPage; rpage; rpage = rpage->rpp_next)
766     {
767 	/* Mark page of RoutePaths as being free */
768 	rpage->rpp_free = 0;
769 
770 	/* Can stop after processing the last page used in this cycle */
771 	if (rpage == mzCurPage)
772 	    break;
773     }
774 
775     /* Start allocating again from the first page on the list */
776     mzCurPage = mzFirstPage;
777 }
778 
779 /*
780  * ----------------------------------------------------------------------------
781  *
782  * mzPresent --
783  *
784  * Predicate, checkes if type corresponding to rL is set in touchingTypes
785  * mask.
786  *
787  * Results:
788  *	TRUE if RL in touchingTypes, else FALSE
789  *
790  * Side effects:
791  *	None.
792  *
793  * ----------------------------------------------------------------------------
794  */
795 
796 bool
mzPresent(rL,touchingTypes)797 mzPresent(rL,touchingTypes)
798     RouteLayer *rL;
799     TileTypeBitMask *touchingTypes;
800 {
801     List *l;
802 
803     /* return true if rL present */
804     if(TTMaskHasType(touchingTypes, rL->rl_routeType.rt_tileType))
805 	return TRUE;
806 
807     /* return true if rL present as part of contact */
808     for(l=rL->rl_contactL; l!=NULL; l=LIST_TAIL(l))
809     {
810 	RouteContact *rC = (RouteContact *)LIST_FIRST(l);
811 	if(TTMaskHasType(touchingTypes, rC->rc_routeType.rt_tileType) &&
812 		(rC->rc_rLayer1==rL || rC->rc_rLayer2==rL))
813 	    return TRUE;
814     }
815 
816     return FALSE;
817 }
818