1 /*
2  * ExtArray.c --
3  *
4  * Circuit extraction.
5  * Extract interactions between elements of an array.
6  * The routines in this file are not re-entrant.
7  *
8  *     *********************************************************************
9  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
10  *     * Permission to use, copy, modify, and distribute this              *
11  *     * software and its documentation for any purpose and without        *
12  *     * fee is hereby granted, provided that the above copyright          *
13  *     * notice appear in all copies.  The University of California        *
14  *     * makes no representations about the suitability of this            *
15  *     * software for any purpose.  It is provided "as is" without         *
16  *     * express or implied warranty.  Export of this software outside     *
17  *     * of the United States of America may require an export license.    *
18  *     *********************************************************************
19  */
20 
21 #ifndef lint
22 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/extract/ExtArray.c,v 1.2 2009/05/30 03:14:00 tim Exp $";
23 #endif  /* not lint */
24 
25 #include <stdio.h>
26 #include <string.h>
27 
28 #include "utils/magic.h"
29 #include "utils/geometry.h"
30 #include "utils/geofast.h"
31 #include "tiles/tile.h"
32 #include "utils/hash.h"
33 #include "database/database.h"
34 #include "utils/malloc.h"
35 #include "textio/textio.h"
36 #include "debug/debug.h"
37 #include "extract/extract.h"
38 #include "extract/extractInt.h"
39 #include "utils/signals.h"
40 #include "utils/styles.h"
41 #include "windows/windows.h"
42 #include "dbwind/dbwind.h"
43 
44 /* Canonical interaction areas */
45 #define	AREA_A	0
46 #define	AREA_B	1
47 #define	AREA_C	2
48 
49 /* Imports from elsewhere in this module */
50 extern int extHardProc();
51 
52 /* Local data passed to extArrayTileToNode() and its children */
53 Point extArrayPrimXY;		/* X, Y indices of primary array element */
54 Point extArrayInterXY;		/* X, Y indices of intersecting array element */
55 Transform extArrayPTrans;	/* Transform from primary element to root */
56 Transform extArrayITrans;	/* Transform from intersecting element ... */
57 int extArrayWhich;		/* Which interaction area is being processed */
58 ExtTree *extArrayPrimary;	/* Primary array element */
59 
60 /* Forward declarations */
61 int extArrayFunc();
62 int extArrayPrimaryFunc(), extArrayInterFunc();
63 char *extArrayRange();
64 char *extArrayTileToNode();
65 LabRegion *extArrayHardNode();
66 char *extArrayNodeName();
67 
68 void extArrayProcess();
69 void extArrayAdjust();
70 void extArrayHardSearch();
71 
72 #if 0
73 
74 /*
75  * ----------------------------------------------------------------------------
76  * extOutputGeneratedLabels ---
77  *
78  * Write to the .ext file output "node" lines for labels generated in
79  * the parent cell where paint in the subcell is not otherwise
80  * represented by a node in the parent.  These nodes have no material
81  * in the parent, and therefore have no capacitance or resistance
82  * associated with them.
83  *
84  * ----------------------------------------------------------------------------
85  */
86 
87 void
88 extOutputGeneratedLabels(parentUse, f)
89     CellUse *parentUse;
90     FILE *f;
91 {
92     CellDef *parentDef;
93     Label *lab;
94     int n;
95 
96     parentDef = parentUse->cu_def;
97 
98     while ((lab = parentDef->cd_labels) != NULL)
99     {
100 	if ((lab->lab_flags & LABEL_GENERATE) == 0) return;
101 
102 	fprintf(f, "node \"%s\" 0 0 %d %d %s",
103 		lab->lab_text, lab->lab_rect.r_xbot,
104 		lab->lab_rect.r_ybot,
105 		DBTypeShortName(lab->lab_type));
106 	for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
107 	    fprintf(f, " 0 0");
108 	putc('\n', f);
109 	freeMagic(lab);
110 	parentDef->cd_labels = lab->lab_next;
111     }
112 }
113 
114 #endif
115 
116 /*
117  * ----------------------------------------------------------------------------
118  *
119  * extArray --
120  *
121  * Extract all connections resulting from interactions within each
122  * array of subcells in the cell parentUse->cu_def.
123  *
124  * This procedure only finds arrays, and then calls extArrayFunc() to
125  * do the real work.  See the comments there for more details.
126  *
127  * Results:
128  *	None.
129  *
130  * Side effects:
131  *	Outputs connections and adjustments to the file 'f'.
132  *	There are two kinds of records; see extSubtree for a description.
133  *	However, when we output nodenames, they may contain implicit
134  *	subscripting information, e.g,
135  *
136  *		cap a[1:3]/In a[2:4]/Phi1 deltaC
137  *
138  *	which is like 3 separate "cap" records:
139  *
140  *		cap a[1]/In a[2]/Phi1 deltaC
141  *		cap a[2]/In a[3]/Phi1 deltaC
142  *		cap a[3]/In a[4]/Phi1 deltaC
143  *
144  * ----------------------------------------------------------------------------
145  */
146 
147 void
extArray(parentUse,f)148 extArray(parentUse, f)
149     CellUse *parentUse;
150     FILE *f;
151 {
152     SearchContext scx;
153     HierExtractArg ha;
154 
155     /*
156      * The connection hash table is initialized here but doesn't get
157      * cleared until the end.  It is responsible for changes to the
158      * node structure over the entire cell 'parentUse->cu_def'.
159      */
160     ha.ha_outf = f;
161     ha.ha_parentUse = parentUse;
162     ha.ha_nodename = extArrayTileToNode;
163     ha.ha_cumFlat.et_use = extYuseCum;
164     HashInit(&ha.ha_connHash, 32, 0);
165 
166     /* The real work of processing each array is done by extArrayFunc() */
167     scx.scx_use = parentUse;
168     scx.scx_trans = GeoIdentityTransform;
169     scx.scx_area = TiPlaneRect;
170     (void) DBCellSrArea(&scx, extArrayFunc, (ClientData) &ha);
171 
172 #if 0
173     /* Output generated labels and remove them from the parent */
174     extOutputGeneratedLabels(parentUse, f);
175 #endif
176 
177     /* Output connections and node adjustments */
178     extOutputConns(&ha.ha_connHash, f);
179     HashKill(&ha.ha_connHash);
180 }
181 
182 /*
183  * ----------------------------------------------------------------------------
184  *
185  * extArrayFunc --
186  *
187  * Given a CellUse as argument, extract and output all the connections that
188  * result from interactions between neighboring elements of the array.
189  *
190  * Results:
191  *	Returns 2 always so we stop after the first CellUse in the array.
192  *
193  * Side effects:
194  *	Writes to the file 'ha->ha_outf'
195  *
196  * Design:
197  *	To extract all the connections made between members of an array, we
198  *	only have to look for interactions in three canonical areas, shaded as
199  *	A, B, and C in the diagram below.  Each interaction area consists only
200  *	of the portion of overlap between the canonical cell (1 for A, B, and
201  *	2 for C) and its neighbors.  Hence the exact size of the interaction
202  *	areas depends on how much overlap there is.  In the extreme cases,
203  *	there may be no areas to check at all (instances widely separated),
204  *	or there may even be areas with more than four instances overlapping
205  *	(spacing less than half the size of the instance).
206  *
207  * 	-------------------------------------------------
208  *	|               |               |               |
209  *	|       2       |               |               |
210  *	|               |               |               |
211  *	|             CCC               |               |
212  * 	--------------CCC--------------------------------
213  *	|               |               |               |
214  *	|               |               |               |
215  *	|               |               |               |
216  *	|               |               |               |
217  * 	AAAAAAAAAAAAAAaba-------------------------------|
218  *	AAAAAAAAAAAAAAbab               |               |
219  *	|             BBB               |               |
220  *	|       1     BBB               |               |
221  *	|             BBB               |               |
222  * 	--------------BBB--------------------------------
223  *
224  * In area A, we check for interactions with 1 and the elements directly
225  * above, or above and to the right.  In area B, we check for interactions
226  * only with elements at the same level but to the right.  In area C, we
227  * check for interactions only with elements below and to the right.
228  *
229  * ----------------------------------------------------------------------------
230  */
231 
232 int
extArrayFunc(scx,ha)233 extArrayFunc(scx, ha)
234     SearchContext *scx;	/* Describes first element of array */
235     HierExtractArg *ha;	/* Extraction context */
236 {
237     int xsep, ysep;	/* X, Y separation in parent coordinates */
238     int xsize, ysize;	/* X, Y sizes in parent coordinates */
239     int halo = ExtCurStyle->exts_sideCoupleHalo	 + 1;
240     CellUse *use = scx->scx_use;
241     CellDef *def = use->cu_def;
242     Rect tmp, tmp2, primary;
243 
244     /* Skip uses that aren't arrays */
245     if ((use->cu_xlo == use->cu_xhi) && (use->cu_ylo == use->cu_yhi))
246 	return (2);
247 
248     if ((ExtOptions & (EXT_DOCOUPLING|EXT_DOADJUST))
249 		   != (EXT_DOCOUPLING|EXT_DOADJUST))
250 	halo = 1;
251 
252     /*
253      * Compute the sizes and separations of elements, in coordinates
254      * of the parent.  If the array is 1-dimensional, we set the
255      * corresponding spacing to an impossibly large distance.
256      */
257     tmp.r_xbot = tmp.r_ybot = 0;
258     if (use->cu_xlo == use->cu_xhi)
259 	tmp.r_xtop = def->cd_bbox.r_xtop - def->cd_bbox.r_xbot + 2;
260     else tmp.r_xtop = use->cu_xsep;
261     if (use->cu_ylo == use->cu_yhi)
262 	tmp.r_ytop = def->cd_bbox.r_ytop - def->cd_bbox.r_ybot + 2;
263     else tmp.r_ytop = use->cu_ysep;
264     GeoTransRect(&use->cu_transform, &tmp, &tmp2);
265     xsep = tmp2.r_xtop - tmp2.r_xbot;
266     ysep = tmp2.r_ytop - tmp2.r_ybot;
267     GeoTransRect(&use->cu_transform, &def->cd_bbox, &tmp2);
268     xsize = tmp2.r_xtop - tmp2.r_xbot;
269     ysize = tmp2.r_ytop - tmp2.r_ybot;
270 
271     /*
272      * For areas A and B, we will be looking at the interactions
273      * between the element in the lower-left corner of the array
274      * (in parent coordinates) and its neighbors to the top, right,
275      * and top-right.
276      */
277     primary.r_xbot = use->cu_bbox.r_xbot;
278     primary.r_xtop = use->cu_bbox.r_xbot + 1;
279     primary.r_ybot = use->cu_bbox.r_ybot;
280     primary.r_ytop = use->cu_bbox.r_ybot + 1;
281     ha->ha_subUse = use;
282 
283     /* Area A */
284     if (ysep <= ysize)
285     {
286 	ha->ha_clipArea.r_xbot = use->cu_bbox.r_xbot;
287 	ha->ha_clipArea.r_xtop = use->cu_bbox.r_xbot + xsize + halo;
288 	ha->ha_clipArea.r_ybot = use->cu_bbox.r_ybot + ysep - halo;
289 	ha->ha_clipArea.r_ytop = use->cu_bbox.r_ybot + ysize + halo;
290 	ha->ha_interArea = ha->ha_clipArea;
291 	extArrayWhich = AREA_A;
292 	extArrayProcess(ha, &primary);
293 	if (SigInterruptPending)
294 	    return (1);
295     }
296 
297     /* Area B */
298     if (xsep <= xsize)
299     {
300 	ha->ha_clipArea.r_xbot = use->cu_bbox.r_xbot + xsep - halo;
301 	ha->ha_clipArea.r_xtop = use->cu_bbox.r_xbot + xsize + halo;
302 	ha->ha_clipArea.r_ybot = use->cu_bbox.r_ybot;
303 	ha->ha_clipArea.r_ytop = use->cu_bbox.r_ybot + ysize + halo;
304 	ha->ha_interArea = ha->ha_clipArea;
305 	extArrayWhich = AREA_B;
306 	extArrayProcess(ha, &primary);
307 	if (SigInterruptPending)
308 	    return (1);
309     }
310 
311     /* Area C */
312     if (ysep <= ysize && xsep <= xsize)
313     {
314 	/*
315 	 * For area C, we will be looking at the interactions between
316 	 * the element in the upper-left corner of the array (in parent
317 	 * coordinates) and its neighbors to the bottom-right only.
318 	 */
319 	primary.r_ybot = use->cu_bbox.r_ytop - 1;
320 	primary.r_ytop = use->cu_bbox.r_ytop;
321 	ha->ha_clipArea.r_xbot = use->cu_bbox.r_xbot + xsep - halo;
322 	ha->ha_clipArea.r_xtop = use->cu_bbox.r_xbot + xsize + halo;
323 	ha->ha_clipArea.r_ybot = use->cu_bbox.r_ytop - ysize - halo;
324 	ha->ha_clipArea.r_ytop = use->cu_bbox.r_ytop - ysep + halo;
325 	ha->ha_interArea = ha->ha_clipArea;
326 	extArrayWhich = AREA_C;
327 	extArrayProcess(ha, &primary);
328     }
329 
330     return (2);
331 }
332 
333 /*
334  * ----------------------------------------------------------------------------
335  *
336  * extArrayProcess --
337  *
338  * Process a single canonical interaction area for the arrayed CellUse
339  * 'ha->ha_subUse'.  The area 'primary', in parent coordinates, should
340  * be contained in only one element of the array.  For each other element
341  * in the array that appears in the area 'ha->ha_interArea', we determine
342  * all connections and R/C adjustments and output them in the form of an
343  * implicitly iterated "merge" or "adjust" line for the rest of the array.
344  *
345  * Expects extArrayWhich to be one of AREA_A, AREA_B, or AREA_C; this
346  * is the interaction area being searched.
347  *
348  * Results:
349  *	None.
350  *
351  * Side effects:
352  *	See extArrayPrimaryFunc and extArrayInterFunc for details.
353  *	Trashes ha->ha_cumFlat.et_use.
354  *
355  * ----------------------------------------------------------------------------
356  */
357 
358 void
extArrayProcess(ha,primary)359 extArrayProcess(ha, primary)
360     HierExtractArg *ha;
361     Rect *primary;	/* Area guaranteed to contain only the primary
362 			 * element of the array, against which we will
363 			 * extract all other elements that overlap the
364 			 * area 'ha->ha_interArea'.
365 			 */
366 {
367     CellUse *use = ha->ha_subUse;
368 
369 
370     /*
371      * Yank the primary array element into a new yank buffer
372      * that we leave extArrayPrimary pointing to.
373      */
374     extArrayPrimary = (ExtTree *) NULL;
375     if (DBArraySr(use, primary, extArrayPrimaryFunc, (ClientData) ha) == 0)
376     {
377 	DBWFeedbackAdd(primary,
378 		"System error: expected array element but none found",
379 		ha->ha_parentUse->cu_def, 1, STYLE_MEDIUMHIGHLIGHTS);
380 	extNumFatal++;
381 	return;
382     }
383     if (SigInterruptPending) goto done;
384 
385     /*
386      * Find and process all other elements that intersect ha->ha_interArea,
387      * extracting connections against extArrayPrimary.
388      */
389     (void) DBArraySr(use, &ha->ha_interArea, extArrayInterFunc, (ClientData)ha);
390 
391 done:
392     if (extArrayPrimary) extHierFreeOne(extArrayPrimary);
393     extArrayPrimary = (ExtTree *) NULL;
394 }
395 
396 /*
397  * ----------------------------------------------------------------------------
398  *
399  * extArrayPrimaryFunc --
400  *
401  * Called by DBArraySr, which should only find a single array element.
402  * We record which element was found by setting extArrayPrimXY.p_x
403  * and extArrayPrimXY.p_y, and also the transform in extArrayPTrans
404  * for use by extArrayHardNode().
405  *
406  * We yank the paint and labels of this array element into a new ExtTree,
407  * which we leave extArrayPrimary pointing to.  The area, perimeter,
408  * capacitance, and coupling capacitance for this element are extracted.
409  *
410  * Results:
411  *	Returns 1 to cause DBArraySr to abort and return 1 itself.
412  *	This is so the caller of DBArraySr can tell whether or not
413  *	any elements were found (a sanity check).
414  *
415  * Side effects:
416  *	See above.
417  *
418  * ----------------------------------------------------------------------------
419  */
420 
421 int
extArrayPrimaryFunc(use,trans,x,y,ha)422 extArrayPrimaryFunc(use, trans, x, y, ha)
423     CellUse *use;	/* Use of which this is an array element */
424     Transform *trans;	/* Transform from coordinates of use->cu_def to those
425 			 * in use->cu_parent, for the array element (x, y).
426 			 */
427     int x, y;		/* X, Y indices of this array element */
428     HierExtractArg *ha;
429 {
430     CellDef *primDef;
431     HierYank hy;
432 
433     /*
434      * Remember the indices of this array element.
435      * When we are looking for all other array elements intersecting
436      * this area, we will ignore this element.  We also remember the
437      * transform in case we need to use it in extArrayHardNode().
438      */
439     extArrayPrimXY.p_x = x, extArrayPrimXY.p_y = y;
440     extArrayPTrans = *trans;
441 
442     /* Restrict searching to interaction area for this element of array */
443     GeoTransRect(trans, &use->cu_def->cd_bbox, &ha->ha_subArea);
444     GeoClip(&ha->ha_subArea, &ha->ha_interArea);
445 
446     /* Yank this element into the primary buffer */
447     extArrayPrimary = extHierNewOne();
448     hy.hy_area = &ha->ha_subArea;
449     hy.hy_target = extArrayPrimary->et_use;
450     hy.hy_prefix = FALSE;
451     (void) extHierYankFunc(use, trans, x, y, &hy);
452 
453     /*
454      * Extract extArrayPrimary, getting node capacitance, perimeter,
455      * and area, and coupling capacitances between nodes.  Assign
456      * labels from primDef's label list.
457      */
458     primDef = extArrayPrimary->et_use->cu_def;
459     extArrayPrimary->et_nodes = extFindNodes(primDef, &ha->ha_clipArea, FALSE);
460     ExtLabelRegions(primDef, ExtCurStyle->exts_nodeConn,
461 		&extArrayPrimary->et_nodes, &ha->ha_clipArea);
462     if ((ExtOptions & (EXT_DOADJUST|EXT_DOCOUPLING))
463 		   == (EXT_DOADJUST|EXT_DOCOUPLING))
464 	extFindCoupling(primDef, &extArrayPrimary->et_coupleHash,
465 			&ha->ha_clipArea);
466 
467     return (1);
468 }
469 
470 /*
471  * ----------------------------------------------------------------------------
472  *
473  * extArrayInterFunc --
474  *
475  * Called by DBArraySr, which should find all array elements inside
476  * 'ha->ha_interArea' (in parent coordinates).  If the array element
477  * (x, y) is the same as the primary element found by extArrayPrimaryFunc,
478  * i.e, the element (extArrayPrimXY.p_x, extArrayPrimXY.p_y), we
479  * skip it.  Otherwise, we yank the overlap of this array element with
480  * 'ha->ha_interArea' into its own subtree and extract the interactions
481  * between it and extArrayPrimary.
482  *
483  * Results:
484  *	Returns 0 to cause DBArraySr to continue.
485  *
486  * Side effects:
487  *	Sets extArrayInterXY.p_x, extArrayInterXY.p_y to the element
488  *	(x, y) so that lower-level functions have access to this information.
489  *
490  * ----------------------------------------------------------------------------
491  */
492 
493 int
extArrayInterFunc(use,trans,x,y,ha)494 extArrayInterFunc(use, trans, x, y, ha)
495     CellUse *use;	/* Use of which this is an array element */
496     Transform *trans;	/* Transform from use->cu_def to use->cu_parent
497 			 * coordinates, for the array element (x, y).
498 			 */
499     int x, y;		/* X, Y of this array element in use->cu_def coords */
500     HierExtractArg *ha;
501 {
502     CellUse *cumUse = ha->ha_cumFlat.et_use;
503     CellDef *cumDef = cumUse->cu_def;
504     SearchContext scx;
505     CellDef *oneDef;
506     ExtTree *oneFlat;
507     HierYank hy;
508 
509     /* Skip this element if it is the primary one */
510     if (x == extArrayPrimXY.p_x && y == extArrayPrimXY.p_y)
511 	return (0);
512 
513     switch (extArrayWhich)
514     {
515 	/*
516 	 * Area A is above, or above and to the right.
517 	 * Given where we search, there are no elements below and
518 	 * to the right of area A.
519 	 */
520 	case AREA_A:
521 	    if (x == extArrayPrimXY.p_x || y == extArrayPrimXY.p_y)
522 	    {
523 		/*
524 		 * Exactly one of X or Y is the same as for
525 		 * the primary element.
526 		 */
527 		if (trans->t_a)
528 		{
529 		    /*
530 		     * X, Y are still X, Y in parent.
531 		     * If X is different, this element is only to the
532 		     * right and so belongs to area B.
533 		     */
534 		    if (x != extArrayPrimXY.p_x) return (0);
535 		}
536 		else
537 		{
538 		    /*
539 		     * X, Y are interchanged in parent.
540 		     * If Y is different, this element is only to the
541 		     * right and so belongs to area B.
542 		     */
543 		    if (y != extArrayPrimXY.p_y) return (0);
544 		}
545 	    }
546 	    break;
547 	/*
548 	 * Area B is only interactions to the right (not
549 	 * above, or diagonally above or below), in parent
550 	 * coordinates.
551 	 */
552 	case AREA_B:
553 	    if (trans->t_a)
554 	    {
555 		/* x, y are still x, y in parent */
556 		if (y != extArrayPrimXY.p_y) return (0);
557 	    }
558 	    else
559 	    {
560 		/* x, y are interchanged in parent */
561 		if (x != extArrayPrimXY.p_x) return (0);
562 	    }
563 	    break;
564 	/*
565 	 * Area C checks only diagonal interactions.
566 	 * Given where we search, there are no interactions
567 	 * above and to the right of area C; the only diagonal
568 	 * interactions are below and to the right.
569 	 */
570 	case AREA_C:
571 	    if (x == extArrayPrimXY.p_x || y == extArrayPrimXY.p_y)
572 		return (0);
573 	    break;
574     }
575 
576     /* Indicate which element this is to connection output routines */
577     extArrayInterXY.p_x = x, extArrayInterXY.p_y = y;
578     extArrayITrans = *trans;
579 
580     /* Restrict searching to interaction area for this element of array */
581     GeoTransRect(trans, &use->cu_def->cd_bbox, &ha->ha_subArea);
582     GeoClip(&ha->ha_subArea, &ha->ha_interArea);
583 
584     /* Yank this array element into a new ExtTree */
585     oneFlat = extHierNewOne();
586     hy.hy_area = &ha->ha_subArea;
587     hy.hy_target = oneFlat->et_use;
588     hy.hy_prefix = FALSE;
589     (void) extHierYankFunc(use, trans, x, y, &hy);
590 
591     /*
592      * Extract node capacitance, perimeter, area, and coupling capacitance
593      * for this subtree.  Labels come from the hierarchical labels yanked
594      * above, but may have additional labels added when we find names the
595      * hard way.
596      */
597     oneDef = oneFlat->et_use->cu_def;
598     oneFlat->et_nodes = extFindNodes(oneDef, &ha->ha_clipArea, FALSE);
599     ExtLabelRegions(oneDef, ExtCurStyle->exts_nodeConn, &oneFlat->et_nodes,
600 		&ha->ha_clipArea);
601     if ((ExtOptions & (EXT_DOADJUST|EXT_DOCOUPLING))
602 		   == (EXT_DOADJUST|EXT_DOCOUPLING))
603 	extFindCoupling(oneDef, &oneFlat->et_coupleHash, &ha->ha_clipArea);
604 
605     /* Process connections */
606     extHierConnections(ha, extArrayPrimary, oneFlat);
607 
608     /* Process substrate connection */
609     if (use->cu_xlo == use->cu_xhi)
610 	extHierSubstrate(ha, use, -1, y);
611     else if (use->cu_ylo == use->cu_yhi)
612 	extHierSubstrate(ha, use, x, -1);
613     else
614 	extHierSubstrate(ha, use, x, y);
615 
616     ha->ha_cumFlat.et_nodes = (NodeRegion *) NULL;
617     if (ExtOptions & EXT_DOADJUST)
618     {
619 	/* Build cumulative buffer from both extArrayPrimary and oneFlat */
620 	scx.scx_trans = GeoIdentityTransform;
621 	scx.scx_area = TiPlaneRect;
622 	scx.scx_use = oneFlat->et_use;
623 	DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, cumUse);
624 	scx.scx_use = extArrayPrimary->et_use;
625 	DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, cumUse);
626 
627 	/*
628 	 * Extract everything in the cumulative buffer.
629 	 * Don't bother labelling the nodes, though, since we will never look
630 	 * at the node labels (we only search extArrayPrimary or oneFlat for
631 	 * the name of a node).  Finally, compute and output adjustments for
632 	 * nodes and coupling capacitance.
633 	 */
634 	HashInit(&ha->ha_cumFlat.et_coupleHash, 32,
635 			HashSize(sizeof (CoupleKey)));
636 	ha->ha_cumFlat.et_nodes = extFindNodes(cumDef, &ha->ha_clipArea, FALSE);
637 	if (ExtOptions & EXT_DOCOUPLING)
638 	    extFindCoupling(cumDef, &ha->ha_cumFlat.et_coupleHash,
639 			&ha->ha_clipArea);
640 	extArrayAdjust(ha, oneFlat, extArrayPrimary);
641 	if (ExtOptions & EXT_DOCOUPLING)
642 	    extCapHashKill(&ha->ha_cumFlat.et_coupleHash);
643     }
644 
645     /* Clean up */
646     if (oneFlat) extHierFreeOne(oneFlat);
647     if (ha->ha_cumFlat.et_nodes)
648 	ExtFreeLabRegions((LabRegion *) ha->ha_cumFlat.et_nodes);
649     ha->ha_cumFlat.et_nodes = (NodeRegion *) NULL;
650     DBCellClearDef(cumDef);
651     return (0);
652 }
653 
654 void
extArrayAdjust(ha,et1,et2)655 extArrayAdjust(ha, et1, et2)
656     HierExtractArg *ha;
657     ExtTree *et1, *et2;
658 {
659     CapValue cap;	/* value of capacitance WAS: int */
660     NodeRegion *np;
661     CoupleKey *ck;
662     HashEntry *he;
663     NodeName *nn;
664     HashSearch hs;
665     char *name;
666 
667     /*
668      * Initialize the capacitance, perimeter, and area values
669      * in the Nodes in the hash table ha->ha_connHash, taking
670      * their values from the NodeRegions in ha->ha_cumFlat.
671      */
672     for (np = ha->ha_cumFlat.et_nodes; np; np = np->nreg_next)
673     {
674 	if ((name = extArrayNodeName(np, ha, et1, et2))
675 		&& (he = HashLookOnly(&ha->ha_connHash, name))
676 		&& (nn = (NodeName *) HashGetValue(he)))
677 	{
678 	    nn->nn_node->node_cap = np->nreg_cap;
679 	    bcopy((char *) np->nreg_pa, (char *) nn->nn_node->node_pa,
680 		    ExtCurStyle->exts_numResistClasses * sizeof (PerimArea));
681 	}
682     }
683 
684     /*
685      * Coupling capacitance from et1 and et2 gets subtracted from that
686      * stored in ha->ha_cumFlat.  Also, subtract the node capacitance,
687      * perimeter, and area of each subtree from ha->ha_cumFlat's nodes.
688      */
689     extHierAdjustments(ha, &ha->ha_cumFlat, et1, et1);
690     extHierAdjustments(ha, &ha->ha_cumFlat, et2, et2);
691 
692     HashStartSearch(&hs);
693     while (he = HashNext(&ha->ha_cumFlat.et_coupleHash, &hs))
694     {
695 	cap = extGetCapValue(he)  / ExtCurStyle->exts_capScale;
696 	if (cap == 0)
697 	    continue;
698 
699 	ck = (CoupleKey *) he->h_key.h_words;
700 	name = extArrayNodeName(ck->ck_1, ha, et1, et2);
701 	fprintf(ha->ha_outf, "cap \"%s\" ", name);
702 	name = extArrayNodeName(ck->ck_2, ha, et1, et2);
703 	fprintf(ha->ha_outf, "\"%s\" %lg\n", name, cap);
704     }
705 }
706 
707 char *
extArrayNodeName(np,ha,et1,et2)708 extArrayNodeName(np, ha, et1, et2)
709     NodeRegion *np;
710     HierExtractArg *ha;
711     ExtTree *et1, *et2;
712 {
713     Tile *tp;
714 
715     tp = extNodeToTile(np, et1);
716     if (tp && TiGetType(tp) != TT_SPACE && extHasRegion(tp, extUnInit))
717 	return (extArrayTileToNode(tp, np->nreg_pnum, et1, ha, TRUE));
718 
719     tp = extNodeToTile(np, et2);
720     if (tp && TiGetType(tp) != TT_SPACE && extHasRegion(tp, extUnInit))
721 	return (extArrayTileToNode(tp, np->nreg_pnum, et2, ha, TRUE));
722 
723     return ("(none)");
724 }
725 
726 /*
727  * ----------------------------------------------------------------------------
728  *
729  * extArrayTileToNode --
730  *
731  * Map from a Tile in a given ExtTree to the name of the node
732  * containing that tile.
733  *
734  * The node associated with a tile can be determined in one of the
735  * following ways:
736  *
737  *	(1) Look for a label on the list of the Region pointed to by the
738  *	    tile planes of 'et->et_use->cu_def'.  If no label was found,
739  *	    then try (2).
740  *
741  *	(2) Call extArrayHardNode() to do a painful extraction of a label.
742  *	    See the comments in extArrayHardNode() for a description of
743  *	    the algorithm used.  Only do this if doHard is TRUE.
744  *
745  * The actual name we use will be prefixed by the array use identifier
746  * (from ha->ha_subUse), followed by the range of subscripts for that array
747  * for which this is valid.  The ExtTree 'et' tells us whether we are looking
748  * at the primary element of an array (when it is extArrayPrimary), or at
749  * one of the elements against which the primary is being extracted.
750  *
751  * Results:
752  *	Returns a pointer to the name of the node containing
753  *	the tile.  If no node name was found, and doHard was
754  *	TRUE, return the string "(none)"; if doHard was FALSE,
755  *	return NULL.
756  *
757  * Side effects:
758  *	The string returned is allocated from a static buffer, so
759  *	subsequent calls to extArrayTileToNode() will overwrite
760  *	the results returned in previous calls.
761  *
762  *	Records an error with the feedback package if no node name
763  *	could be found, and doHard was TRUE.
764  *
765  * ----------------------------------------------------------------------------
766  */
767 
768 char *
extArrayTileToNode(tp,pNum,et,ha,doHard)769 extArrayTileToNode(tp, pNum, et, ha, doHard)
770     Tile *tp;
771     int pNum;
772     ExtTree *et;
773     HierExtractArg *ha;
774     bool doHard;	/* If TRUE, we look up this node's name the hard way
775 			 * if we can't find it any other way; otherwise, we
776 			 * return NULL if we can't find the node's name.
777 			 */
778 {
779     static char name[2048];
780     static char errorStr[] =
781 	"Cannot find the name of this node (probable extractor error)";
782     CellDef *def = et->et_use->cu_def;
783     CellUse *use = ha->ha_subUse;
784     char *srcp, *dstp, *endp;
785     bool hasX = (use->cu_xlo != use->cu_xhi);
786     bool hasY = (use->cu_ylo != use->cu_yhi);
787     int xdiff = extArrayInterXY.p_x - extArrayPrimXY.p_x;
788     int ydiff = extArrayInterXY.p_y - extArrayPrimXY.p_y;
789     LabRegion *reg;
790     Rect r;
791 
792     if (extHasRegion(tp, extUnInit))
793     {
794 	reg = (LabRegion *) extGetRegion(tp);
795 	if (reg->lreg_labels)
796 	    goto found;
797     }
798 
799     if (!DebugIsSet(extDebugID, extDebNoHard))
800 	if (reg = (LabRegion *) extArrayHardNode(tp, pNum, def, ha))
801 	    goto found;
802 
803     /* Blew it */
804     if (!doHard) return ((char *) NULL);
805     extNumFatal++;
806     TiToRect(tp, &r);
807     if (!DebugIsSet(extDebugID, extDebNoFeedback))
808 	DBWFeedbackAdd(&r, errorStr, ha->ha_parentUse->cu_def, 1,
809 				STYLE_MEDIUMHIGHLIGHTS);
810     return ("(none)");
811 
812 found:
813     /* Copy in the use id, leaving room for [%d:%d,%d:%d] at the end */
814     srcp = use->cu_id;
815     dstp = name;
816     endp = &name[sizeof name - 40];
817     while (dstp < endp && (*dstp++ = *srcp++))
818 	/* Nothing */;
819     if (dstp >= endp) goto done;
820     dstp--;
821 
822 #define	Far(v, lo, hi)	((v) == (lo) ? (hi) : (lo))
823 #define	FarX(u)		Far(extArrayPrimXY.p_x, (u)->cu_xlo, (u)->cu_xhi)
824 #define	FarY(u)		Far(extArrayPrimXY.p_y, (u)->cu_ylo, (u)->cu_yhi)
825 
826     /*
827      * Append the array subscripts.
828      * Remember that 2-d arrays are subscripted [y,x] and not [x,y].
829      */
830     if (def == extArrayPrimary->et_use->cu_def)
831     {
832 	if (hasY)
833 	    dstp = extArrayRange(dstp, extArrayPrimXY.p_y,
834 				FarY(use) - ydiff, FALSE, hasX);
835 	if (hasX)
836 	    dstp = extArrayRange(dstp, extArrayPrimXY.p_x,
837 				FarX(use) - xdiff, hasY, FALSE);
838     }
839     else
840     {
841 	if (hasY)
842 	    dstp = extArrayRange(dstp, extArrayInterXY.p_y,
843 				FarY(use), FALSE, hasX);
844 	if (hasX)
845 	    dstp = extArrayRange(dstp, extArrayInterXY.p_x,
846 				FarX(use), hasY, FALSE);
847     }
848 
849 #undef	Far
850 #undef	FarX
851 #undef	FarY
852 
853 done:
854     *dstp++ = '/';
855     endp = &name[sizeof name - 1];
856     srcp = extNodeName(reg);
857     while (dstp < endp && (*dstp++ = *srcp++))
858 	/* Nothing */;
859 
860     *dstp = '\0';
861     return (name);
862 }
863 
864 /*
865  * ----------------------------------------------------------------------------
866  *
867  * extArrayRange --
868  *
869  * Called by extArrayTileToNode above, we print a range of the form [lo:hi]
870  * into the string pointed to by 'dstp'.  Guarantees that lo <= hi.
871  *
872  * Results:
873  *	Returns a pointer to the NULL byte at the end of the string
874  *	we print into (dstp).
875  *
876  * Side effects:
877  *	Writes characters into 'dstp', which should be large enough
878  *	to hold any possible string of the form [int:int].
879  *
880  * ----------------------------------------------------------------------------
881  */
882 
883 char *
extArrayRange(dstp,lo,hi,prevRange,followRange)884 extArrayRange(dstp, lo, hi, prevRange, followRange)
885     char *dstp;
886     int lo, hi;
887     bool prevRange;	/* TRUE if preceded by a range */
888     bool followRange;	/* TRUE if followed by a range */
889 {
890     if (!prevRange) *dstp++ = '[';
891     if (hi < lo)
892 	(void) sprintf(dstp, "%d:%d", hi, lo);
893     else
894 	(void) sprintf(dstp, "%d:%d", lo, hi);
895     while (*dstp++) /* Nothing */;
896     dstp[-1] = followRange ? ',' : ']';
897     *dstp = '\0';
898     return (dstp);
899 }
900 
901 /*
902  * ----------------------------------------------------------------------------
903  *
904  * extArrayHardNode --
905  *
906  * Find a node name for the electrical node containing the tile 'tp'
907  * the hard way.  We assume tp->ti_client points to a LabRegion that
908  * had no labels associated with it; if we succeed, we leave this
909  * LabRegion pointing to a newly allocated LabelList and Label.
910  *
911  * Results:
912  *	Returns a pointer to LabRegion for the node to which the tile
913  *	'tp' belongs.  Returns NULL if no region could be found.
914  *
915  * Side effects:
916  *	None.
917  *
918  * Algorithm:
919  *	Search in the appropriate array element to the yank buffer
920  *	in question: if 'def' is the primary buffer, search the
921  *	element (extArrayPrimXY.p_x, extArrayPrimXY.p_y); otherwise,
922  *	search (extArrayInterXY.p_x, extArrayInterXY.p_y).
923  *
924  *	For each cell we find in the course of a hierarchical search
925  *	of this array element in the area of the tile 'tp', trace out
926  *	the nodes lying in the area of the overlap, and then do a label
927  *	assignment for those nodes.  As soon as we find a label, we're
928  *	done.  Otherwise, we reset this def back the way we found it
929  *	and continue on to the next cell in our search.
930  *
931  * ----------------------------------------------------------------------------
932  */
933 
934 LabRegion *
extArrayHardNode(tp,pNum,def,ha)935 extArrayHardNode(tp, pNum, def, ha)
936     Tile *tp;
937     int pNum;
938     CellDef *def;
939     HierExtractArg *ha;
940 {
941     TileType type = TiGetType(tp);
942     char labelBuf[4096];
943     SearchContext scx;
944     HardWay arg;
945 
946     arg.hw_ha = ha;
947     arg.hw_label = (Label *) NULL;
948     arg.hw_mask = DBPlaneTypes[pNum];
949     TTMaskAndMask(&arg.hw_mask, &DBConnectTbl[type]);
950     arg.hw_tpath.tp_last = &labelBuf[sizeof labelBuf - 3];
951     arg.hw_tpath.tp_first = arg.hw_tpath.tp_next = labelBuf;
952     arg.hw_prefix = FALSE;
953     arg.hw_autogen = FALSE;
954     TiToRect(tp, &arg.hw_area);
955     scx.scx_use = ha->ha_subUse;
956 
957     /* Find a label in the interaction area */
958     labelBuf[0] = '\0';
959     extArrayHardSearch(def, &arg, &scx, extHardProc);
960     if (arg.hw_label == NULL)
961     {
962 	labelBuf[0] = '\0';
963 	arg.hw_autogen = TRUE;
964 	extArrayHardSearch(def, &arg, &scx, extHardProc);
965     }
966 
967     if (arg.hw_label)
968     {
969 	LabRegion *lreg;
970 	LabelList *ll;
971 
972 	lreg = (LabRegion *) extGetRegion(tp);
973 	ll = (LabelList *) mallocMagic((unsigned) (sizeof (LabelList)));
974 	lreg->lreg_labels = ll;
975 	ll->ll_next = (LabelList *) NULL;
976 	ll->ll_label = arg.hw_label;
977 	arg.hw_label->lab_next = def->cd_labels;
978 	def->cd_labels = arg.hw_label;
979 	return (lreg);
980     }
981 
982     return ((LabRegion *) NULL);
983 }
984 
985 /*
986  * ----------------------------------------------------------------------------
987  *
988  * extArrayHardSearch --
989  *
990  * Do the actual work of calling (*proc)() either to find a label the hard
991  * way, or to create a new label.  Called from extArrayHardNode above.
992  *
993  * Results:
994  *	None.
995  *
996  * Side effects:
997  *	Those of (*proc)().
998  *
999  * ----------------------------------------------------------------------------
1000  */
1001 
1002 void
extArrayHardSearch(def,arg,scx,proc)1003 extArrayHardSearch(def, arg, scx, proc)
1004     CellDef *def;
1005     HardWay *arg;
1006     SearchContext *scx;
1007     int (*proc)();
1008 {
1009     Transform tinv;
1010 
1011     if (def == extArrayPrimary->et_use->cu_def)
1012     {
1013 	scx->scx_trans = extArrayPTrans;
1014 	scx->scx_x = extArrayPrimXY.p_x;
1015 	scx->scx_y = extArrayPrimXY.p_y;
1016     }
1017     else
1018     {
1019 	scx->scx_trans = extArrayITrans;
1020 	scx->scx_x = extArrayInterXY.p_x;
1021 	scx->scx_y = extArrayInterXY.p_y;
1022     }
1023     GeoInvertTrans(&scx->scx_trans, &tinv);
1024     GeoTransRect(&tinv, &arg->hw_area, &scx->scx_area);
1025     (void) (*proc)(scx, arg);
1026 }
1027