1 /*
2  * ExtSubtree.c --
3  *
4  * Circuit extraction.
5  * Extracts interactions between subtrees of a parent and the
6  * parent itself.  Does not handle extraction of interactions
7  * arising between elements of the same array; those are handled
8  * by the procedures in ExtArray.c
9  *
10  * The procedures in this file are not re-entrant.
11  *
12  *     *********************************************************************
13  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
14  *     * Permission to use, copy, modify, and distribute this              *
15  *     * software and its documentation for any purpose and without        *
16  *     * fee is hereby granted, provided that the above copyright          *
17  *     * notice appear in all copies.  The University of California        *
18  *     * makes no representations about the suitability of this            *
19  *     * software for any purpose.  It is provided "as is" without         *
20  *     * express or implied warranty.  Export of this software outside     *
21  *     * of the United States of America may require an export license.    *
22  *     *********************************************************************
23  */
24 
25 #ifndef lint
26 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/extract/ExtSubtree.c,v 1.3 2010/06/24 12:37:17 tim Exp $";
27 #endif  /* not lint */
28 
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/time.h>
32 
33 #include "tcltk/tclmagic.h"
34 #include "utils/magic.h"
35 #include "tcltk/tclmagic.h"
36 #include "utils/geometry.h"
37 #include "utils/geofast.h"
38 #include "tiles/tile.h"
39 #include "utils/hash.h"
40 #include "database/database.h"
41 #include "utils/malloc.h"
42 #include "textio/textio.h"
43 #include "debug/debug.h"
44 #include "extract/extract.h"
45 #include "extract/extractInt.h"
46 #include "graphics/graphics.h"
47 #include "utils/signals.h"
48 #include "windows/windows.h"
49 #include "dbwind/dbwind.h"
50 #include "utils/styles.h"
51 
52 #ifdef	exactinteractions
53 /*
54  * If "exactinteractions" is defined, we use an experimental algorithm
55  * for finding exact interaction areas.  Currently it doesn't work too
56  * well, so we leave it turned off.
57  */
58 int ExtInterBloat = 10;
59 #endif	/* exactinteractions */
60 
61 /* Imports from elsewhere in this module */
62 extern int extHierYankFunc();
63 extern LabRegion *extSubtreeHardNode();
64 extern Node *extHierNewNode();
65 extern ExtTree *extHierNewOne();
66 
67 /* Global data incremented by extSubtree() */
68 int extSubtreeTotalArea;	/* Total area of cell */
69 int extSubtreeInteractionArea;	/* Total area of all interactions, counting the
70 				 * entire area of the interaction each time.
71 				 */
72 int extSubtreeClippedArea;	/* Total area of all interactions, counting only
73 				 * the area that lies inside each chunk, so no
74 				 * area is counted more than once.
75 				 */
76 
77 /* Local data */
78 
79     /* TRUE if processing the first subtree in an interaction area */
80 bool extFirstPass;
81 
82     /* Points to list of subtrees in an interaction area */
83 ExtTree *extSubList = (ExtTree *) NULL;
84 
85 /* Forward declarations of filter functions */
86 char *extSubtreeTileToNode();
87 int extSubtreeFunc();
88 int extSubstrateFunc();
89 int extConnFindFunc();
90 int extSubtreeHardUseFunc();
91 int extHardProc();
92 int extSubtreeCopyPlane();
93 int extSubtreeShrinkPlane();
94 void extSubtreeInteraction();
95 void extSubtreeAdjustInit();
96 void extSubtreeOutputCoupling();
97 void extSubtreeHardSearch();
98 
99 /*
100  * ----------------------------------------------------------------------------
101  *
102  * extClearUseFlags --
103  *
104  *  Callback function to clear the CU_SUB_EXTRACTED flag from each child
105  *  use of a CellDef.
106  *
107  * ----------------------------------------------------------------------------
108  */
109 
110 int
extClearUseFlags(use,clientData)111 extClearUseFlags(use, clientData)
112     CellUse *use;
113     ClientData clientData;
114 {
115     use->cu_flags &= ~CU_SUB_EXTRACTED;
116     return 0;
117 }
118 
119 
120 /*
121  * ----------------------------------------------------------------------------
122  *
123  * extSubtree --
124  *
125  * Do the hierarchical part of extracting the cell 'parentUse->cu_def'.
126  * This consists of finding all connections either between geometry in the
127  * parent and geometry in a subcell, or between geometry in two overlapping
128  * or adjacent subcells.
129  *
130  * This procedure only finds interaction areas, where subcells are close
131  * to each other or to mask information, and then calls extSubtreeInteraction()
132  * to do the real work.  See the comments there for more details.
133  *
134  * Results:
135  *	None.
136  *
137  * Side effects:
138  *	Outputs connections and adjustments to the file 'f'.
139  *	There are two kinds of records:
140  *
141  *		merge node1 node2 deltaC deltaP1 deltaA1 deltaP2 deltaA2 ...
142  *		cap node1 node2 deltaC
143  *
144  *	The first merges node1 and node2, adjusts the substrate capacitance
145  *	by adding deltaC (usually negative), and the node perimeter and area
146  *	for each resistive layer n by deltaPn deltaAn.
147  *
148  *	The second adjusts the coupling capacitance between node1 and node2
149  *	by deltaC, which may be positive or negative.
150  *
151  * ----------------------------------------------------------------------------
152  */
153 
154 #define	RECTAREA(r)	(((r)->r_xtop-(r)->r_xbot) * ((r)->r_ytop-(r)->r_ybot))
155 
156 void
extSubtree(parentUse,reg,f)157 extSubtree(parentUse, reg, f)
158     CellUse *parentUse;
159     NodeRegion *reg;		/* Node regions of the parent cell */
160     FILE *f;
161 {
162     int extSubtreeInterFunc();
163     CellDef *def = parentUse->cu_def;
164     int halo = ExtCurStyle->exts_sideCoupleHalo	 + 1;
165     HierExtractArg ha;
166     Rect r, rlab, rbloat, *b;
167     Label *lab;
168     bool result;
169     int cuts, totcuts;
170     float pdone, plast;
171     SearchContext scx;
172 
173     /* Use the display timer to force a 5-second progress check */
174     GrDisplayStatus = DISPLAY_IN_PROGRESS;
175     SigSetTimer(5);		    /* Print at 5-second intervals */
176 
177     if ((ExtOptions & (EXT_DOCOUPLING|EXT_DOADJUST))
178 		   != (EXT_DOCOUPLING|EXT_DOADJUST))
179 	halo = 1;
180 
181     /*
182      * The cumulative buffer is initially empty.  It will be built up
183      * for each interaction area, and then cleared before processing
184      * the next one.
185      *
186      * The connection hash table is initialized here but doesn't get
187      * cleared until the end.  It is responsible for changes to the
188      * node structure over the entire cell 'def'.
189      */
190     extSubtreeTotalArea += RECTAREA(&def->cd_bbox);
191     ha.ha_outf = f;
192     ha.ha_parentUse = parentUse;
193     ha.ha_parentReg = reg;
194     ha.ha_nodename = extSubtreeTileToNode;
195     ha.ha_cumFlat.et_use = extYuseCum;
196     HashInit(&ha.ha_connHash, 32, 0);
197 
198 #ifndef	exactinteractions
199     /*
200      * Cookie-cutter up def into pieces ExtCurStyle->exts_stepSize by
201      * ExtCurStyle->exts_stepSize.
202      * Find all interaction areas (within halo units distance, where
203      * halo has been set above to reflect the maximum distance for
204      * sidewall coupling capacitance).
205      */
206     b = &def->cd_bbox;
207 
208     /* Monitor progress, for large designs, and allow display refresh at intervals */
209 
210     totcuts = (b->r_ytop - b->r_ybot + ExtCurStyle->exts_stepSize - 1)
211 		    / ExtCurStyle->exts_stepSize;
212     totcuts *= ((b->r_xtop - b->r_xbot + ExtCurStyle->exts_stepSize - 1)
213 		    / ExtCurStyle->exts_stepSize);
214     cuts = 0;
215     pdone = 0.0;
216     plast = 0.0;
217 
218     for (r.r_ybot = b->r_ybot; r.r_ybot < b->r_ytop; r.r_ybot = r.r_ytop)
219     {
220 	r.r_ytop = r.r_ybot + ExtCurStyle->exts_stepSize;
221 	for (r.r_xbot = b->r_xbot; r.r_xbot < b->r_xtop; r.r_xbot = r.r_xtop)
222 	{
223 	    r.r_xtop = r.r_xbot + ExtCurStyle->exts_stepSize;
224 	    if (SigInterruptPending)
225 		goto done;
226 	    rbloat = r;
227 	    rbloat.r_xbot -= halo, rbloat.r_ybot -= halo;
228 	    rbloat.r_xtop += halo, rbloat.r_ytop += halo;
229 	    result = DRCFindInteractions(def, &rbloat, halo, &ha.ha_interArea);
230 
231 	    // Check area for labels.  Expand interaction area to include
232 	    // the labels.  This catches labels that are not attached to
233 	    // any geometry in the cell and therefore do not get flagged by
234 	    // DRCFindInteractions().
235 
236 	    for (lab = def->cd_labels; lab; lab = lab->lab_next)
237 		if (GEO_OVERLAP(&lab->lab_rect, &r) || GEO_TOUCH(&lab->lab_rect, &r)) {
238 		    // Clip the label area to the area of rbloat
239 		    rlab = lab->lab_rect;
240 		    GEOCLIP(&rlab, &rbloat);
241 		    if (!result) {
242 			// If result == FALSE then ha.ha_interArea is invalid.
243 			ha.ha_interArea = rlab;
244 			result = TRUE;
245 		    }
246 		    else
247 		        result |= GeoIncludeAll(&rlab, &ha.ha_interArea);
248 		}
249 
250 	    if (result)
251 	    {
252 		ha.ha_clipArea = ha.ha_interArea;
253 		GEOCLIP(&ha.ha_clipArea, &r);
254 		extSubtreeInteractionArea += RECTAREA(&ha.ha_interArea);
255 		extSubtreeClippedArea += RECTAREA(&ha.ha_clipArea);
256 		extSubtreeInteraction(&ha);
257 	    }
258 	    else
259 	    {
260 		/* Make sure substrate connections have been handled	*/
261 		/* even if there were no other interactions found.	*/
262 
263 		ha.ha_clipArea = r;
264 		scx.scx_trans = GeoIdentityTransform;
265 		scx.scx_area = r;
266 		scx.scx_use = ha.ha_parentUse;
267 		DBCellSrArea(&scx, extSubstrateFunc, (ClientData)&ha);
268 	    }
269 
270 	    cuts++;
271 	    pdone = 100.0 * ((float)cuts / (float)totcuts);
272 	    if ((((pdone - plast) > 5.0) || (cuts == totcuts)) && (cuts > 1)) {
273 		/* Only print something if the 5-second timer has expired */
274 		if (GrDisplayStatus == DISPLAY_BREAK_PENDING)
275 		{
276 		    TxPrintf("Completed %d%%\n", (int)(pdone + 0.5));
277 		    plast = pdone;
278 		    TxFlushOut();
279 
280 		    GrDisplayStatus = DISPLAY_IN_PROGRESS;
281 		    SigSetTimer(5);
282 		}
283 
284 #ifdef MAGIC_WRAPPER
285 		/* We need to let Tk paint the console display */
286 		while (Tcl_DoOneEvent(TCL_DONT_WAIT) != 0);
287 #endif
288 	    }
289 	}
290     }
291 #else	/* exactinteractions */
292     {
293 	static Plane *interPlane = NULL, *bloatPlane = NULL;
294 
295 	/*
296 	 * Experimental code to find exact interaction areas.
297 	 * Currently, this both takes longer to find interactions
298 	 * and longer to process them than the cookie-cutter
299 	 * approach above, but maybe it can be turned into a
300 	 * scheme that is faster.
301 	 */
302 	if (interPlane == (Plane *) NULL)
303 	    interPlane = DBNewPlane((ClientData) TT_SPACE);
304 	if (bloatPlane == (Plane *) NULL)
305 	    bloatPlane = DBNewPlane((ClientData) TT_SPACE);
306 	ExtFindInteractions(def, halo, ExtInterBloat, interPlane);
307 	if (ExtInterBloat)
308 	{
309 	    /* Shrink back down */
310 	    (void) DBSrPaintArea((Tile *) NULL, interPlane,
311 			&TiPlaneRect, &DBAllButSpaceBits,
312 			extSubtreeCopyPlane, (ClientData) bloatPlane);
313 	    (void) DBSrPaintArea((Tile *) NULL, bloatPlane,
314 			&TiPlaneRect, &DBSpaceBits,
315 			extSubtreeShrinkPlane, (ClientData) interPlane);
316 	    DBClearPaintPlane(bloatPlane);
317 	}
318 	(void) DBSrPaintArea((Tile *) NULL, interPlane,
319 		    &TiPlaneRect, &DBAllButSpaceBits,
320 		    extSubtreeInterFunc, (ClientData) &ha);
321 	DBClearPaintPlane(interPlane);
322     }
323 #endif	/* exactinteractions */
324 
325 done:
326     /* Output connections and node adjustments */
327     extOutputConns(&ha.ha_connHash, f);
328     HashKill(&ha.ha_connHash);
329     GrDisplayStatus = DISPLAY_IDLE;
330     SigRemoveTimer();
331 
332     /* Clear the CU_SUB_EXTRACTED flag from all children instances */
333     DBCellEnum(def, extClearUseFlags, (ClientData)NULL);
334 }
335 
336 #ifdef	exactinteractions
337 int
extSubtreeCopyPlane(tile,plane)338 extSubtreeCopyPlane(tile, plane)
339     Tile *tile;
340     Plane *plane;
341 {
342     Rect r;
343 
344     TITORECT(tile, &r);
345     (void) DBPaintPlane(plane, &r, DBStdWriteTbl(TT_ERROR_P),
346 		(PaintUndoInfo *) NULL);
347     return (0);
348 }
349 
350 int
extSubtreeShrinkPlane(tile,plane)351 extSubtreeShrinkPlane(tile, plane)
352     Tile *tile;
353     Plane *plane;
354 {
355     Rect r;
356 
357     TITORECT(tile, &r);
358     r.r_xbot -= ExtInterBloat; r.r_ybot -= ExtInterBloat;
359     r.r_xtop += ExtInterBloat; r.r_ytop += ExtInterBloat;
360     GEOCLIP(&r, &TiPlaneRect);
361     (void) DBPaintPlane(plane, &r, DBStdWriteTbl(TT_SPACE),
362 		(PaintUndoInfo *) NULL);
363     return (0);
364 }
365 
366 int
extSubtreeInterFunc(tile,ha)367 extSubtreeInterFunc(tile, ha)
368     Tile *tile;
369     HierExtractArg *ha;
370 {
371     TITORECT(tile, &ha->ha_interArea);
372     ha->ha_clipArea = ha->ha_interArea;
373     extSubtreeInteractionArea += RECTAREA(&ha->ha_interArea);
374     extSubtreeClippedArea += RECTAREA(&ha->ha_clipArea);
375     extSubtreeInteraction(ha);
376     return (0);
377 }
378 #endif	/* exactinteractions */
379 
380 /*
381  * ----------------------------------------------------------------------------
382  *
383  * extSubtreeInteraction --
384  *
385  * Having found an interaction area, we process it.
386  * The def being extracted is ha->ha_parentUse->cu_def.
387  *
388  * Clipping:
389  *	The cookie-cutter piece we were looking at for the interaction is
390  *	ha->ha_clipArea, and the interaction area actually found is
391  *	ha->ha_interArea.  It is possible that ha->ha_interArea extends
392  *	outside of ha->ha_clipArea; if this is the case, all area and
393  *	perimeter outside of ha->ha_clipArea are ignored when making
394  *	adjustments.  When computing sidewall coupling capacitance,
395  *	we search for an initial tile only inside ha->ha_clipArea.
396  *
397  * Algorithm:
398  *	Extracting an interaction area consists of two passes.
399  *
400  *	The first pass will build the connection table ha->ha_connHash,
401  *	but leave the adjustment for each connection as zero.  At the
402  *	end of the first pass, extSubList is a list of ExtTrees containing
403  *	each flattened subtree in the area of the interaction (including
404  *	the parent geometry), and ha->ha_cumFlat contains everything
405  *	flattened.
406  *
407  *	The second pass will make the adjustments in ha->ha_connHash, and
408  *	will build the table et_coupleHash in ha->ha_cumFlat.  All of
409  *	the table ha->ha_connHash will be output, but only those entries
410  *	in et_coupleHash with non-zero capacitance adjustment (either
411  *	positive or negative) will get output.
412  *
413  * Results:
414  *	None.
415  *
416  * Side effects:
417  *	Adds more information to ha->ha_connHash and
418  *	ha->ha_cumFlat.et_coupleHash.
419  *
420  * ----------------------------------------------------------------------------
421  */
422 
423 void
extSubtreeInteraction(ha)424 extSubtreeInteraction(ha)
425     HierExtractArg *ha;	/* Context for hierarchical extraction */
426 {
427     CellDef *oneDef, *cumDef = ha->ha_cumFlat.et_use->cu_def;
428     ExtTree *oneFlat, *nextFlat;
429     NodeRegion *reg;
430     SearchContext scx;
431 
432     scx.scx_trans = GeoIdentityTransform;
433     scx.scx_area = ha->ha_interArea;
434     scx.scx_use = ha->ha_parentUse;
435 
436     /* Copy parent paint into ha->ha_cumFlat */
437     DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, ha->ha_cumFlat.et_use);
438 
439     /*
440      * First element on the subtree list will be parent mask info.
441      * Extract nodes and capacitors.  Node names come from parent.
442      */
443     oneFlat = extHierNewOne();
444     oneDef = oneFlat->et_use->cu_def;
445     DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, oneFlat->et_use);
446 
447     oneFlat->et_nodes = extFindNodes(oneDef, &ha->ha_clipArea, FALSE);
448     if ((ExtOptions & (EXT_DOCOUPLING|EXT_DOADJUST))
449 		   == (EXT_DOCOUPLING|EXT_DOADJUST))
450     {
451 	HashInit(&oneFlat->et_coupleHash, 32, HashSize(sizeof (CoupleKey)));
452 	extFindCoupling(oneDef, &oneFlat->et_coupleHash, &ha->ha_clipArea);
453     }
454     oneFlat->et_lookNames = ha->ha_parentUse->cu_def;
455     oneFlat->et_realuse = (CellUse *) NULL;
456     extSubList = oneFlat;
457 
458     /*
459      * Cumulative yank buffer names also come from parent.
460      * Since we only mark nodes for use in naming on the first
461      * pass, there's no need to extract nodes in ha_cumFlat
462      * until we process the first subcell in extSubtreeFunc.
463      */
464     ha->ha_cumFlat.et_nodes = (NodeRegion *) NULL;
465     ha->ha_cumFlat.et_lookNames = ha->ha_parentUse->cu_def;
466     extFirstPass = TRUE;
467 
468     /*
469      * Process each subcell in the interaction area exactly once.
470      * After processing each subcell, we reset ha->ha_cumFlat.et_nodes
471      * to NULL.
472      */
473     (void) DBCellSrArea(&scx, extSubtreeFunc, (ClientData) ha);
474 
475     if (ExtOptions & EXT_DOADJUST)
476     {
477 	/*
478 	 * Re-extract ha->ha_cumFlat, this time getting node capacitance,
479 	 * perimeter, and area, and coupling capacitances between nodes.
480 	 * Assign labels from cumDef's label list.
481 	 * Don't reset ha_lookNames, since we still need to be able to
482 	 * refer to nodes in the parent.
483 	 */
484 	ha->ha_cumFlat.et_nodes = extFindNodes(cumDef, &ha->ha_clipArea, FALSE);
485 	ExtLabelRegions(cumDef, ExtCurStyle->exts_nodeConn,
486 			&(ha->ha_cumFlat.et_nodes), &ha->ha_clipArea);
487 	if (ExtOptions & EXT_DOCOUPLING)
488 	{
489 	    HashInit(&ha->ha_cumFlat.et_coupleHash, 32,
490 			HashSize(sizeof(CoupleKey)));
491 	    extFindCoupling(cumDef, &ha->ha_cumFlat.et_coupleHash,
492 			&ha->ha_clipArea);
493 	}
494 
495 	/* Process all adjustments */
496 	ha->ha_subUse = (CellUse *) NULL;
497 	extSubtreeAdjustInit(ha);
498 	for (oneFlat = extSubList; oneFlat; oneFlat = oneFlat->et_next)
499 	    extHierAdjustments(ha, &ha->ha_cumFlat, oneFlat, &ha->ha_cumFlat);
500 
501 #if 0
502 	/*
503 	 * Output adjustments to substrate capacitance that are not
504 	 * output anywhere else.  Nodes that connect down into the
505 	 * hierarchy are part of ha_connHash and have adjustments
506 	 * that are printed in the "merge" statement.  Nodes not in
507 	 * the current cell are not considered.  Anything left over
508 	 * has its adjusted value output.
509 	 */
510 
511 	/* Disabled (9/28/2021)---This does not work as advertised. */
512 
513 	for (reg = ha->ha_parentReg; reg; reg = reg->nreg_next)
514 	{
515 	    Rect r;
516 	    NodeRegion *treg;
517 	    CapValue finC;
518 	    char *text;
519 
520 	    r.r_ll = reg->nreg_ll;
521 	    r.r_xtop = r.r_xbot + 1;
522 	    r.r_ytop = r.r_ybot + 1;
523 
524 	    /* Use the tile position of the parent region to find the
525 	     * equivalent region in cumDef.  Then compare the substrate
526 	     * cap and output the difference.
527 	     */
528 
529 	    if (DBSrPaintArea((Tile *)NULL, cumDef->cd_planes[reg->nreg_pnum],
530 			&r, &DBAllButSpaceBits, extConnFindFunc,
531 			(ClientData) &treg))
532 	    {
533 		text = extNodeName(reg);
534 		// Output the adjustment made to the substrate cap
535 		// (should be negative).  Ignore adjustments of zero
536 		finC = (treg->nreg_cap - reg->nreg_cap) /
537 						ExtCurStyle->exts_capScale;
538 		if (finC < -1.0E-6)
539 		    fprintf(ha->ha_outf, "subcap \"%s\" %lg\n", text, finC);
540 	    }
541 	}
542 #endif
543 
544 	/*
545 	 * Output adjustments to coupling capacitance.
546 	 * The names output for coupling capacitors are those on the
547 	 * label list for each node in the cumulative buffer.
548 	 */
549 	if (ExtOptions & EXT_DOCOUPLING)
550 	{
551 	    extSubtreeOutputCoupling(ha);
552 	    extCapHashKill(&ha->ha_cumFlat.et_coupleHash);
553 	}
554     }
555 
556     /* Free the subtrees (this must happen after all adjustments are made) */
557     for (oneFlat = extSubList; oneFlat; oneFlat = nextFlat)
558 	nextFlat = oneFlat->et_next, extHierFreeOne(oneFlat);
559     extSubList = (ExtTree *) NULL;
560 
561     /*
562      * Done with the cumulative yank buffer for this interaction.
563      * Free the list of nodes, the list of hierarchical labels
564      * built when we yanked this def, and then erase all the paint
565      * in the buffer.
566      */
567     if (ha->ha_cumFlat.et_nodes)
568 	ExtFreeLabRegions((LabRegion *) ha->ha_cumFlat.et_nodes);
569     ha->ha_cumFlat.et_nodes = (NodeRegion *) NULL;
570     extHierFreeLabels(cumDef);
571     DBCellClearDef(cumDef);
572 }
573 
574 /*
575  * ----------------------------------------------------------------------------
576  *
577  * extSubtreeAdjustInit --
578  *
579  * Initialize the node capacitance, perimeter, and area values in
580  * all the Nodes in the HashTable ha->ha_connHash.  The initial
581  * values come from the NodeRegions in ha->ha_cumFlat.et_nodes,
582  * which correspond to extracting the entire flattened interaction
583  * area.  We add these values to any already existing from a previous
584  * interaction area in case there were any nodes that span the boundary
585  * between two interaction areas.  We will then call extHierAdjustments
586  * to subtract away the extracted values in each of the individually
587  * flattened subtrees.
588  *
589  * Results:
590  *	None.
591  *
592  * Side effects:
593  *	See above.
594  *
595  * Design notes:
596  *	We only need to update perimeter, area, or substrate capacitance
597  *	when nodes from different subtrees abut or overlap, i.e., connect.
598  *	These nodes have already been recorded in the table ha->ha_connHash
599  *	by extHierConnections(), so all we have to do is find the appropriate
600  *	entries in this table.
601  *
602  *	Each NodeRegion in ha->ha_cumFlat contains a list of labels with
603  *	it.  The first label in each list is guaranteed to correspond to
604  *	an entry in the table ha->ha_connHash if this node is a participant
605  *	in a connection, so we pass this label to HashFind to obtain the
606  *	appropriate Node.
607  *
608  * ----------------------------------------------------------------------------
609  */
610 
611 void
extSubtreeAdjustInit(ha)612 extSubtreeAdjustInit(ha)
613     HierExtractArg *ha;
614 {
615     NodeRegion *np;
616     NodeName *nn;
617     int n;
618     HashEntry *he;
619     char *name;
620 
621     /*
622      * Initialize the capacitance, perimeter, and area values
623      * in the Nodes in the hash table ha->ha_connHash.
624      */
625     for (np = ha->ha_cumFlat.et_nodes; np; np = np->nreg_next)
626     {
627 	if ((name = extNodeName((LabRegion *) np))
628 		&& (he = HashLookOnly(&ha->ha_connHash, name))
629 		&& (nn = (NodeName *) HashGetValue(he)))
630 	{
631 	    nn->nn_node->node_cap += np->nreg_cap;
632 	    for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
633 	    {
634 		nn->nn_node->node_pa[n].pa_perim += np->nreg_pa[n].pa_perim;
635 		nn->nn_node->node_pa[n].pa_area += np->nreg_pa[n].pa_area;
636 	    }
637 	}
638     }
639 }
640 
641 /*
642  * ----------------------------------------------------------------------------
643  *
644  * extSubtreeOutputCoupling --
645  *
646  * Output the coupling capacitance table built up by extFindCoupling().
647  * Each entry in the hash table is a capacitance between the pair of
648  * nodes identified by he->h_key, an CoupleKey struct.  Writes to the
649  * FILE ha->ha_outf.
650  *
651  * Because it is possible that the coupled nodes aren't already named,
652  * we have to call extSubtreeTileToNode() to find their actual names.
653  *
654  * Results:
655  *	None.
656  *
657  * Side effects:
658  *	See the comments above.
659  *
660  * ----------------------------------------------------------------------------
661  */
662 
663 void
extSubtreeOutputCoupling(ha)664 extSubtreeOutputCoupling(ha)
665     HierExtractArg *ha;
666 {
667     CapValue cap;
668     CoupleKey *ck;
669     HashEntry *he;
670     Tile *tp;
671     HashSearch hs;
672     char *name;
673 
674     HashStartSearch(&hs);
675     while (he = HashNext(&ha->ha_cumFlat.et_coupleHash, &hs))
676     {
677 	cap = extGetCapValue(he) / ExtCurStyle->exts_capScale;
678 	if (cap == 0)
679 	    continue;
680 
681 	ck = (CoupleKey *) he->h_key.h_words;
682 
683 	tp = extNodeToTile(ck->ck_1, &ha->ha_cumFlat);
684 	name = extSubtreeTileToNode(tp, ck->ck_1->nreg_pnum, &ha->ha_cumFlat, ha, TRUE);
685 	fprintf(ha->ha_outf, "cap \"%s\" ", name);
686 
687 	tp = extNodeToTile(ck->ck_2, &ha->ha_cumFlat);
688 	name = extSubtreeTileToNode(tp, ck->ck_2->nreg_pnum, &ha->ha_cumFlat, ha, TRUE);
689 	fprintf(ha->ha_outf, "\"%s\" %lg\n", name, cap);
690     }
691 }
692 
693 /*
694  * ----------------------------------------------------------------------------
695  *
696  * extSubtreeFunc --
697  *
698  * Called once for each cell use that is a child of the parent def
699  * being extracted.  Yanks the subtree into a new ExtTree.  Extract
700  * connections between this subtree and ha->ha_cumFlat, then paint
701  * the subtree into the cumulative buffer ha->ha_cumFlat and prepend
702  * the subtree to extSubList.
703  *
704  * Results:
705  *	Always returns 2, to avoid further elements in arrays.
706  *
707  * Side effects:
708  *	Leaves ha->ha_cumFlat unextracted (all LabRegions free,
709  *	and ha->ha_cumFlat.et_nodes set to NULL).
710  *	See extHierConnections().
711  *
712  * ----------------------------------------------------------------------------
713  */
714 
715 int
extSubtreeFunc(scx,ha)716 extSubtreeFunc(scx, ha)
717     SearchContext *scx;
718     HierExtractArg *ha;
719 {
720     CellUse *cumUse = ha->ha_cumFlat.et_use;
721     CellUse *use = scx->scx_use;
722     CellDef *oneDef;
723     SearchContext newscx;
724     ExtTree *oneFlat;
725     HierYank hy;
726     int x, y;
727 
728     /* Allocate a new ExtTree to hold the flattened, extracted subtree */
729     oneFlat = extHierNewOne();
730     oneFlat->et_realuse = use;
731 
732     /* Record information for finding node names the hard way later */
733     ha->ha_subUse = use;
734 
735     /*
736      * Yank all array elements of this subcell that lie in the interaction
737      * area.  Transform to parent coordinates.  Prefix is true, meaning that
738      * we should prefix each hierarchical name with the subcell use it
739      * belongs to.
740      */
741     ha->ha_subArea = use->cu_bbox;
742     GEOCLIP(&ha->ha_subArea, &ha->ha_interArea);
743     hy.hy_area = &ha->ha_subArea;
744     hy.hy_target = oneFlat->et_use;
745     hy.hy_prefix = TRUE;
746 
747     (void) DBArraySr(use, &ha->ha_subArea, extHierYankFunc, (ClientData) &hy);
748 
749     /*
750      * Extract node capacitance, perimeter, area, and coupling capacitance
751      * for this subtree.  Labels come from the hierarchical labels yanked
752      * above, but may have additional labels added when we find names the
753      * hard way.
754      */
755     oneDef = oneFlat->et_use->cu_def;
756     oneFlat->et_nodes = extFindNodes(oneDef, &ha->ha_clipArea, FALSE);
757     ExtLabelRegions(oneDef, ExtCurStyle->exts_nodeConn,
758 		&(oneFlat->et_nodes), &ha->ha_clipArea);
759     if ((ExtOptions & (EXT_DOCOUPLING|EXT_DOADJUST))
760 		   == (EXT_DOCOUPLING|EXT_DOADJUST))
761 	extFindCoupling(oneDef, &oneFlat->et_coupleHash, &ha->ha_clipArea);
762 
763     /*
764      * If this is not the first subcell we're processing, mark ha_cumFlat's
765      * tiles with LabRegions.  We don't mark it the first time through,
766      * since then ha_cumFlat contains only the parent mask geometry and
767      * node names will be found by looking in ha_lookNames.
768      */
769     if (extFirstPass)
770     {
771 	extFirstPass = FALSE;
772 
773 	// On the first pass, run through et_lookName's label list.
774 	// Copy any sticky labels to cumUse->cu_def, so that the labels
775 	// can be found even when there is no geometry underneath in
776 	// the parent cell.
777 
778 	CellDef *cumDef = ha->ha_cumFlat.et_lookNames;
779 
780 	if (cumDef != NULL)
781 	{
782 	    Label *lab, *newlab;
783 	    unsigned int n;
784 
785 	    for (lab = cumDef->cd_labels; lab ; lab = lab->lab_next)
786 	    {
787 		if (!(lab->lab_flags & LABEL_STICKY)) continue;
788 
789 		n = sizeof (Label) + strlen(lab->lab_text)
790 			- sizeof lab->lab_text + 1;
791 
792 		newlab = (Label *)mallocMagic(n);
793 		newlab->lab_type = lab->lab_type;
794 		newlab->lab_rect = lab->lab_rect;
795 		newlab->lab_flags = lab->lab_flags;
796 		newlab->lab_port = lab->lab_port;
797 		strcpy(newlab->lab_text, lab->lab_text);
798 
799 		newlab->lab_next = cumUse->cu_def->cd_labels;
800 		cumUse->cu_def->cd_labels = newlab;
801 	    }
802 	}
803     }
804     else
805     {
806 	/*
807 	 * We don't care about the lreg_ll or lreg_pNum for these
808 	 * nodes (we're only interested in the label list associated
809 	 * with each node), so we don't pass extHierLabEach() to
810 	 * ExtFindRegions().
811 	 */
812 	ha->ha_cumFlat.et_nodes =
813 	    (NodeRegion *) ExtFindRegions(cumUse->cu_def, &TiPlaneRect,
814 				&ExtCurStyle->exts_activeTypes,
815 				ExtCurStyle->exts_nodeConn,
816 				extUnInit, extHierLabFirst, (int (*)()) NULL);
817 	ExtLabelRegions(cumUse->cu_def, ExtCurStyle->exts_nodeConn,
818 			&(ha->ha_cumFlat.et_nodes), &TiPlaneRect);
819     }
820 
821     /* Process connections; this updates ha->ha_connHash */
822     extHierConnections(ha, &ha->ha_cumFlat, oneFlat);
823 
824     /* Process substrate connection.  All substrates should be	*/
825     /* connected together in the cell def, so in the case of an	*/
826     /* array, just make sure that the first array entry is	*/
827     /* connected.						*/
828 
829     if (use->cu_xhi == use->cu_xlo && use->cu_yhi == use->cu_ylo)
830 	extHierSubstrate(ha, use, -1, -1);
831     else if (use->cu_xhi == use->cu_xlo && use->cu_yhi > use->cu_ylo)
832     {
833 	for (y = use->cu_ylo; y <= use->cu_yhi; y++)
834 	    extHierSubstrate(ha, use, -1, y);
835     }
836     else if (use->cu_xhi > use->cu_xlo && use->cu_yhi == use->cu_ylo)
837     {
838 	for (x = use->cu_xlo; x <= use->cu_xhi; x++)
839 	extHierSubstrate(ha, use, x, -1);
840     }
841     else
842     {
843 	for (x = use->cu_xlo; x <= use->cu_xhi; x++)
844 	    for (y = use->cu_ylo; y <= use->cu_yhi; y++)
845 		extHierSubstrate(ha, use, x, y);
846     }
847     /* Mark substrate as having been extracted for this use. */
848     use->cu_flags |= CU_SUB_EXTRACTED;
849 
850     /* Free the cumulative node list we extracted above */
851     if (ha->ha_cumFlat.et_nodes)
852     {
853 	ExtResetTiles(cumUse->cu_def, extUnInit);
854 	ExtFreeLabRegions((LabRegion *) ha->ha_cumFlat.et_nodes);
855 	ha->ha_cumFlat.et_nodes = (NodeRegion *) NULL;
856     }
857 
858     /*
859      * Paint the subtree buffer on top of the cumulative buffer.
860      * Copy the labels that were yanked along with the subtree into
861      * the cumulative buffer as well.
862      */
863     newscx.scx_use = oneFlat->et_use;
864     newscx.scx_area = ha->ha_subArea;
865     newscx.scx_trans = GeoIdentityTransform;
866     DBCellCopyPaint(&newscx, &DBAllButSpaceBits, 0, cumUse);
867     extHierCopyLabels(oneFlat->et_use->cu_def, cumUse->cu_def);
868 
869     /* Prepend this tree to the list of trees we've processed so far */
870     oneFlat->et_next = extSubList;
871     extSubList = oneFlat;
872 
873     return (2);
874 }
875 
876 
877 /*
878  * ----------------------------------------------------------------------------
879  *
880  * extSubstrateFunc
881  *
882  * This contains just the part of extSubtreeFunc() dealing with the
883  * substrate, so that substrate extraction can occur in cells not
884  * otherwise having extraction interactions, without incurring the
885  * overhead of all the other items handled by extHierSubtreeFunc().
886  *
887  * Results:
888  *	Always returns 2, to avoid further elements in arrays.
889  *
890  * ----------------------------------------------------------------------------
891  */
892 
893 int
extSubstrateFunc(scx,ha)894 extSubstrateFunc(scx, ha)
895     SearchContext *scx;
896     HierExtractArg *ha;
897 {
898     CellUse *use = scx->scx_use;
899     int x, y;
900 
901     /* Record information for finding node names the hard way */
902     ha->ha_subUse = use;
903     ha->ha_subArea = use->cu_bbox;
904     GEOCLIP(&ha->ha_subArea, &ha->ha_interArea);
905 
906     /* Process substrate connection.  All substrates should be	*/
907     /* connected together in the cell def, so in the case of an	*/
908     /* array, just make sure that the first array entry is	*/
909     /* connected.						*/
910 
911     if (use->cu_xhi == use->cu_xlo && use->cu_yhi == use->cu_ylo)
912 	extHierSubstrate(ha, use, -1, -1);
913     else if (use->cu_xhi == use->cu_xlo && use->cu_yhi > use->cu_ylo)
914     {
915 	for (y = use->cu_ylo; y <= use->cu_yhi; y++)
916 	    extHierSubstrate(ha, use, -1, y);
917     }
918     else if (use->cu_xhi > use->cu_xlo && use->cu_yhi == use->cu_ylo)
919     {
920 	for (x = use->cu_xlo; x <= use->cu_xhi; x++)
921 	extHierSubstrate(ha, use, x, -1);
922     }
923     else
924     {
925 	for (x = use->cu_xlo; x <= use->cu_xhi; x++)
926 	    for (y = use->cu_ylo; y <= use->cu_yhi; y++)
927 		extHierSubstrate(ha, use, x, y);
928     }
929     use->cu_flags |= CU_SUB_EXTRACTED;
930     return (2);
931 }
932 
933 
934 /*
935  * ----------------------------------------------------------------------------
936  *
937  * extSubtreeTileToNode --
938  *
939  * Map from a Tile in a given yank buffer 'et' to the name of the node
940  * containing that tile.
941  *
942  * The node associated with a tile can be determined in one of the
943  * following ways:
944  *
945  *	(1) Look for a label on the list of the Region pointed to by the
946  *	    tile planes of the yank buffer.  If no label was found, then
947  *	    try (2).
948  *
949  *	(2) If et->et_lookNames is non-NULL, see if the tile overlaps a
950  *	    connected tile on the same plane of the def et->et_lookNames.
951  *
952  *	(3) Call extSubtreeHardNode() to do a painful extraction of a label.
953  *	    See the comments in extSubtreeHardNode() for a description of
954  *	    the algorithm used.  Only do this if doHard is TRUE.
955  *
956  * Results:
957  *	Returns a pointer to the name of the node containing
958  *	the tile.  If no node name was found, and doHard was
959  *	TRUE, return the string "(none)"; if doHard was FALSE,
960  *	return NULL.
961  *
962  * Side effects:
963  *	The string returned is allocated from a static buffer, so
964  *	subsequent calls to extSubtreeTileToNode() will overwrite
965  *	the results returned in previous calls.
966  *
967  *	Records an error with the feedback package if no node name
968  *	could be found and doHard was TRUE.
969  *
970  * ----------------------------------------------------------------------------
971  */
972 
973 char *
extSubtreeTileToNode(tp,pNum,et,ha,doHard)974 extSubtreeTileToNode(tp, pNum, et, ha, doHard)
975     Tile *tp;	/* Tile whose node name is to be found */
976     int pNum;	/* Plane of the tile */
977     ExtTree *et;	/* Yank buffer to search */
978     HierExtractArg *ha;	/* Extraction context */
979     bool doHard;	/* If TRUE, we look up this node's name the hard way
980 			 * if we can't find it any other way; otherwise, we
981 			 * return NULL if we can't find the node's name.
982 			 */
983 {
984     static char warningStr[] =
985 	"Warning: node labels should be inside overlap area";
986     static char errorStr[] =
987 	"Cannot find the name of this node (probable extractor error)";
988     CellDef *parentDef = ha->ha_parentUse->cu_def;
989     LabRegion *reg;
990     Label *lab;
991     Rect r;
992     TileType ttype;
993 
994     /* If there is a label list, use it */
995     if (extHasRegion(tp, extUnInit))
996     {
997 	reg = (LabRegion *) extGetRegion(tp);
998 	if (reg->lreg_labels)
999 	    return (extNodeName(reg));
1000     }
1001 
1002     /*
1003      * If there is any node at all in the cell et->et_lookNames,
1004      * use it.  The node doesn't have to have a label list.
1005      */
1006     TITORECT(tp, &r);
1007     if (et->et_lookNames)
1008     {
1009 	/*
1010 	 * Make sure we've got a valid tile -- interactions with interrupts
1011 	 * can cause problems.
1012 	 */
1013 	if (IsSplit(tp))
1014 	{
1015 	    if (SplitSide(tp))
1016 		ttype = SplitRightType(tp);
1017 	    else
1018 		ttype = SplitLeftType(tp);
1019 	}
1020 	else
1021 	    ttype = TiGetTypeExact(tp);
1022 
1023 	if (pNum >= PL_PAINTBASE)
1024 	{
1025 	    if (IsSplit(tp))
1026 	    {
1027 		if (DBSrPaintNMArea((Tile *) NULL,
1028 			et->et_lookNames->cd_planes[pNum],
1029 			TiGetTypeExact(tp), &r, &DBAllButSpaceBits,
1030 			extConnFindFunc, (ClientData) &reg))
1031 		{
1032 		    if (SigInterruptPending)
1033 			return ("(none)");
1034 		    return (extNodeName(reg));
1035 		}
1036 	    }
1037 	    else
1038 	    {
1039 		if (DBSrPaintArea((Tile *) NULL,
1040 			et->et_lookNames->cd_planes[pNum], &r,
1041 			&DBAllButSpaceBits, extConnFindFunc, (ClientData) &reg))
1042 		{
1043 		    if (SigInterruptPending)
1044 			return ("(none)");
1045 		    return (extNodeName(reg));
1046 		}
1047 	    }
1048 	}
1049     }
1050 
1051     /* We have to do it the hard way */
1052     if (!doHard) return ((char *) NULL);
1053     if (extHasRegion(tp, extUnInit)
1054 	    && (reg = extSubtreeHardNode(tp, pNum, et, ha)))
1055     {
1056 	if (ExtDoWarn & EXTWARN_LABELS)
1057 	{
1058 	    DBWFeedbackAdd(&r, warningStr, parentDef, 1, STYLE_PALEHIGHLIGHTS);
1059 	    extNumWarnings++;
1060 	}
1061 	return (extNodeName(reg));
1062     }
1063 
1064     extNumFatal++;
1065     if (!DebugIsSet(extDebugID, extDebNoFeedback))
1066 	DBWFeedbackAdd(&r, errorStr, parentDef, 1, STYLE_MEDIUMHIGHLIGHTS);
1067     return ("(none)");
1068 }
1069 
1070 /*
1071  * ----------------------------------------------------------------------------
1072  * extConnFindFunc --
1073  *
1074  * Called when searching the area of a tile in the def et->et_lookNames
1075  * by extSubtreeTileToNode() above.
1076  *
1077  * Results:
1078  *	If we find a tile that has been marked with a node,
1079  *	return 1; otherwise, return 0.
1080  *
1081  * Side effects:
1082  *	Sets *preg to the node found if we returned 1; otherwise,
1083  *	leaves *preg alone.
1084  * ----------------------------------------------------------------------------
1085  */
1086 
1087 int
extConnFindFunc(tp,preg)1088 extConnFindFunc(tp, preg)
1089     Tile *tp;
1090     LabRegion **preg;
1091 {
1092     if (extHasRegion(tp, extUnInit))
1093     {
1094 	*preg = (LabRegion *) extGetRegion(tp);
1095 	return (1);
1096     }
1097 
1098     return (0);
1099 }
1100 
1101 /*
1102  * ----------------------------------------------------------------------------
1103  *
1104  * extSubtreeHardNode --
1105  *
1106  * Find a node name for the electrical node containing the tile 'tp'
1107  * the hard way.  We assume tp->ti_client points to a LabRegion that
1108  * had no labels associated with it; if we succeed, we leave this
1109  * LabRegion pointing to a newly allocated LabelList and Label.
1110  *
1111  * Results:
1112  *	Returns a pointer to LabRegion for the node to which the tile
1113  *	'tp' belongs.  Returns NULL if no region could be found.
1114  *
1115  * Side effects:
1116  *	See above.
1117  *
1118  * Algorithm:
1119  *	For each subcell of the parent that could have contributed
1120  *	to the yank buffer in question, search the original tree
1121  *	for geometry in the area of the tile 'tp'.  For each cell
1122  *	we find, we trace out just those nodes lying in the area
1123  *	of the overlap, and then do a label assignment for those
1124  *	nodes.  As soon as we find a label, we're done.  Otherwise,
1125  *	we reset this def back the way we found it and continue on
1126  *	to the next cell in our search.
1127  *
1128  * ----------------------------------------------------------------------------
1129  */
1130 
1131 LabRegion *
extSubtreeHardNode(tp,pNum,et,ha)1132 extSubtreeHardNode(tp, pNum, et, ha)
1133     Tile *tp;
1134     int pNum;
1135     ExtTree *et;
1136     HierExtractArg *ha;
1137 {
1138     LabRegion *lreg = (LabRegion *) extGetRegion(tp);
1139     CellDef *def = et->et_use->cu_def;
1140     TileType ttype;
1141     char labelBuf[4096];
1142     LabelList *ll;
1143     HardWay arg;
1144 
1145     ASSERT(lreg->lreg_labels == NULL, "extSubtreeHardNode");
1146 
1147     if (IsSplit(tp))
1148     {
1149 	if (SplitSide(tp))
1150 	    ttype = SplitRightType(tp);
1151 	else
1152 	    ttype = SplitLeftType(tp);
1153     }
1154     else
1155 	ttype = TiGetTypeExact(tp);
1156 
1157     arg.hw_ha = ha;
1158     arg.hw_label = (Label *) NULL;
1159     arg.hw_mask = DBPlaneTypes[pNum];
1160     TTMaskAndMask(&arg.hw_mask, &DBConnectTbl[ttype]);
1161     arg.hw_tpath.tp_last = &labelBuf[sizeof labelBuf - 3];
1162     arg.hw_tpath.tp_first = arg.hw_tpath.tp_next = labelBuf;
1163     arg.hw_prefix = TRUE;
1164     TITORECT(tp, &arg.hw_area);
1165 
1166     /*
1167      * Try to find a label in the area.
1168      * If we can't find a label, we make one up based on the
1169      * automatically generated node name in a child cell that
1170      * contains paint in this node.
1171      */
1172     labelBuf[0] = '\0';
1173     arg.hw_autogen = FALSE;
1174     extSubtreeHardSearch(et, &arg);
1175     if (arg.hw_label == NULL)
1176     {
1177 	labelBuf[0] = '\0';
1178 	arg.hw_autogen = TRUE;
1179 	extSubtreeHardSearch(et, &arg);
1180     }
1181 
1182     /*
1183      * If we succeeded (we always should), we now have a label.
1184      * Make the single LabelList for the region 'lreg' point to
1185      * this label, and prepend it to the list for 'def'.
1186      */
1187     if (arg.hw_label)
1188     {
1189 	ll = (LabelList *) mallocMagic((unsigned) (sizeof (LabelList)));
1190 	lreg->lreg_labels = ll;
1191 	ll->ll_next = (LabelList *) NULL;
1192 	ll->ll_label = arg.hw_label;
1193 	arg.hw_label->lab_next = def->cd_labels;
1194 	def->cd_labels = arg.hw_label;
1195 	return (lreg);
1196     }
1197 
1198     return ((LabRegion *) NULL);
1199 }
1200 
1201 /*
1202  * ----------------------------------------------------------------------------
1203  * extSubtreeHardSearch --
1204  *
1205  * Do the actual work of deciding which subtrees to search
1206  * for extSubtreeHardNode above.  We apply the procedure
1207  * extHardProc() at each subcell.
1208  * ----------------------------------------------------------------------------
1209  */
1210 
1211 void
extSubtreeHardSearch(et,arg)1212 extSubtreeHardSearch(et, arg)
1213     ExtTree *et;
1214     HardWay *arg;
1215 {
1216     HierExtractArg *ha = arg->hw_ha;
1217     ExtTree *oneFlat;
1218 
1219     arg->hw_proc = extHardProc;
1220     if (et == &ha->ha_cumFlat)
1221     {
1222 	/*
1223 	 * Recursively search all children of parent up to, but not
1224 	 * including, ha->ha_subUse.  Don't search parent paint.
1225 	 */
1226 	for (oneFlat = extSubList; oneFlat; oneFlat = oneFlat->et_next)
1227 	{
1228 	    if (oneFlat->et_realuse)
1229 	    {
1230 		if (DBArraySr(oneFlat->et_realuse, &arg->hw_area,
1231 				    extSubtreeHardUseFunc, (ClientData) arg))
1232 		{
1233 		    break;
1234 		}
1235 	    }
1236 	}
1237     }
1238     else
1239     {
1240 	/* Recursively search only the elements of ha->ha_subUse */
1241 	(void) DBArraySr(ha->ha_subUse, &arg->hw_area,
1242 		extSubtreeHardUseFunc, (ClientData) arg);
1243     }
1244 }
1245 
1246 /*
1247  * ----------------------------------------------------------------------------
1248  * extSubtreeHardUseFunc --
1249  *
1250  * When searching a subtree, this is called once for each element
1251  * in the array that is the root of the subtree.
1252  *
1253  * Results:
1254  *	Returns 1 if we have successfully found a label, 0 if not
1255  *	(return value of arg->hw_proc).
1256  *
1257  * Side effects:
1258  *	Calls (*arg->hw_proc)().
1259  * ----------------------------------------------------------------------------
1260  */
1261 
1262 int
extSubtreeHardUseFunc(use,trans,x,y,arg)1263 extSubtreeHardUseFunc(use, trans, x, y, arg)
1264     CellUse *use;	/* Use that is the root of the subtree being searched */
1265     Transform *trans;	/* Transform from coordinates of use->cu_def to those
1266 			 * in use->cu_parent, for the array element (x, y).
1267 			 */
1268     int x, y;		/* Indices of this array element */
1269     HardWay *arg;	/* Context passed down to filter functions */
1270 {
1271     SearchContext scx;
1272     Transform tinv;
1273 
1274     scx.scx_use = use;
1275     scx.scx_trans = *trans;
1276     scx.scx_x = x;
1277     scx.scx_y = y;
1278     GEOINVERTTRANS(trans, &tinv);
1279     GEOTRANSRECT(&tinv, &arg->hw_area, &scx.scx_area);
1280     return ((*arg->hw_proc)(&scx, arg));
1281 }
1282