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