1 /*
2 * ExtBasic.c --
3 *
4 * Circuit extraction.
5 * Flat extraction of a single CellDef.
6 *
7 * *********************************************************************
8 * * Copyright (C) 1985, 1990 Regents of the University of California. *
9 * * Permission to use, copy, modify, and distribute this *
10 * * software and its documentation for any purpose and without *
11 * * fee is hereby granted, provided that the above copyright *
12 * * notice appear in all copies. The University of California *
13 * * makes no representations about the suitability of this *
14 * * software for any purpose. It is provided "as is" without *
15 * * express or implied warranty. Export of this software outside *
16 * * of the United States of America may require an export license. *
17 * *********************************************************************
18 */
19
20 #ifndef lint
21 static char sccsid[] = "@(#)ExtBasic.c 4.13 MAGIC (Berkeley) 12/5/85";
22 #endif /* not lint */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <math.h>
28
29 #include "tcltk/tclmagic.h"
30 #include "utils/magic.h"
31 #include "utils/geometry.h"
32 #include "utils/geofast.h"
33 #include "tiles/tile.h"
34 #include "utils/hash.h"
35 #include "database/database.h"
36 #include "utils/malloc.h"
37 #include "textio/textio.h"
38 #include "debug/debug.h"
39 #include "extract/extract.h"
40 #include "extract/extractInt.h"
41 #include "utils/signals.h"
42 #include "windows/windows.h"
43 #include "dbwind/dbwind.h"
44 #include "utils/styles.h"
45 #include "utils/stack.h"
46 #include "utils/utils.h"
47
48 /* These must be in the order of "known devices" in extract.h. */
49
50 /* Note: "fet" refers to the original fet type; "mosfet" refers to the */
51 /* new type. The main difference is that "fet" records area/perimeter */
52 /* while "mosfet" records length/width. */
53 /* Also: Note that this table is repeated in extflat/EFread.c when */
54 /* ext2spice/ext2sim are compiled as separate programs (i.e., non-Tcl) */
55
56 #ifdef MAGIC_WRAPPER
57 char *extDevTable[] = {"fet", "mosfet", "asymmetric", "bjt", "devres",
58 "devcap", "devcaprev", "vsource", "diode", "pdiode", "ndiode",
59 "subckt", "rsubckt", "msubckt", "csubckt", NULL};
60 #endif
61
62 /* --------------------- Data local to this file ---------------------- */
63
64 /*
65 * The following are used to accumulate perimeter and area
66 * on each layer when building up the node list. They are
67 * used to compute the resistance of each node. Each is
68 * indexed by sheet resistivity class.
69 */
70 int extResistPerim[NT];
71 dlong extResistArea[NT];
72
73 /*
74 * The following structure is used in extracting transistors.
75 *
76 * A "terminal" below refers to any port on the transistor that
77 * is not the gate. In most cases, these are the "diffusion"
78 * ports of the transistor.
79 */
80 #define MAXSD 10 /* Maximum # of terminals per transistor */
81
82
83 typedef struct /* Position of each terminal (below) tile position */
84 {
85 int pnum;
86 Point pt;
87 } TermTilePos;
88
89 /* Field definitions for tr_devmatch */
90 #define MATCH_ID 0x01 /* Device matches identifier in devrec */
91 #define MATCH_SUB 0x02 /* Device matches substrate type in devrec */
92 #define MATCH_TERM 0x04 /* Device matches terminal in devrec */
93 /* (additional fields: bit shifts up by 1 for each defined device terminal) */
94
95 struct transRec
96 {
97 ExtDevice *tr_devrec; /* Device record in ExtCurStyle */
98 int tr_devmatch; /* Fields of tr_devrec that match device */
99 int tr_nterm; /* Number of terminals */
100 int tr_gatelen; /* Perimeter of connection to gate */
101 NodeRegion *tr_gatenode; /* Node region for gate terminal */
102 NodeRegion *tr_termnode[MAXSD]; /* Node region for each diff terminal */
103 NodeRegion *tr_subsnode; /* Substrate node */
104 int tr_termlen[MAXSD]; /* Length of each diff terminal edge,
105 * used for computing L/W for the fet.
106 */
107 Point tr_termvector[MAXSD]; /* Perimeter traversal vector, used to
108 * find and calculate correct parameters
109 * for annular (ring) devices and other
110 * non-rectangular geometries.
111 */
112 int tr_perim; /* Total perimeter */
113 TermTilePos tr_termpos[MAXSD]; /* lowest tile connecting to term */
114 } extTransRec;
115
116 typedef struct LB1
117 {
118 Rect r; /* Boundary segment */
119 int dir; /* Direction of travel */
120 struct LB1 *b_next;
121 } LinkedBoundary;
122
123 LinkedBoundary **extSpecialBounds; /* Linked Boundary List */
124 NodeRegion *glob_subsnode = NULL; /* Global substrate node */
125 NodeRegion *temp_subsnode = NULL; /* Last subsnode found */
126
127 #define EDGENULL(r) ((r)->r_xbot > (r)->r_xtop || (r)->r_ybot > (r)->r_ytop)
128
129 /* Forward declarations */
130 void extOutputNodes();
131 int extTransTileFunc();
132 int extTransPerimFunc();
133 int extTransFindSubs();
134 int extTransFindId();
135
136 int extAnnularTileFunc();
137 int extResistorTileFunc();
138 int extSpecialPerimFunc();
139
140 void extFindDuplicateLabels();
141 void extOutputDevices();
142 void extOutputParameters();
143 void extTransOutTerminal();
144 void extTransBad();
145
146 ExtDevice *extDevFindMatch();
147
148 bool extLabType();
149
150 /* Function returns 1 if a tile is found by DBTreeSrTiles() */
151 /* that is not in the topmost def of the search. */
152
153 int
extFoundFunc(tile,cxp)154 extFoundFunc(tile, cxp)
155 Tile *tile;
156 TreeContext *cxp;
157 {
158 CellDef *def = (CellDef *)cxp->tc_filter->tf_arg;
159 return (def == cxp->tc_scx->scx_use->cu_def) ? 0 : 1;
160 }
161
162 /*
163 * ----------------------------------------------------------------------------
164 *
165 * extBasic --
166 *
167 * Extract a single CellDef, and output the result to the
168 * file 'outFile'.
169 *
170 * Results:
171 * Returns a list of Region structs that comprise all
172 * the nodes in 'def'. It is the caller's responsibility
173 * to call ExtResetTile() and ExtFreeLabRegions() to restore
174 * the CellDef to its original state and to free the list
175 * of regions we build up.
176 *
177 * Side effects:
178 * Writes the result of extracting just the paint of
179 * the CellDef 'def' to the output file 'outFile'.
180 * The following kinds of records are output:
181 *
182 * node
183 * substrate
184 * equiv
185 * fet
186 * device
187 *
188 * Interruptible in a limited sense. We will still return a
189 * Region list, but labels may not have been assigned, and
190 * nodes and fets may not have been output.
191 *
192 * ----------------------------------------------------------------------------
193 */
194
195 NodeRegion *
extBasic(def,outFile)196 extBasic(def, outFile)
197 CellDef *def; /* Cell being extracted */
198 FILE *outFile; /* Output file */
199 {
200 NodeRegion *nodeList, *extFindNodes();
201 bool coupleInitialized = FALSE;
202 TransRegion *transList, *reg;
203 HashTable extCoupleHash;
204 char *propptr;
205 bool propfound = FALSE;
206 bool isabstract = FALSE;
207
208 glob_subsnode = (NodeRegion *)NULL;
209
210 /*
211 * Build up a list of the device regions for extOutputDevices()
212 * below. We're only interested in pointers from each region to
213 * a tile in that region, not the back pointers from the tiles to
214 * the regions.
215 */
216 transList = (TransRegion *) ExtFindRegions(def, &TiPlaneRect,
217 &ExtCurStyle->exts_deviceMask,
218 ExtCurStyle->exts_deviceConn,
219 extUnInit, extTransFirst, extTransEach);
220 ExtResetTiles(def, extUnInit);
221
222 for (reg = transList; reg && !SigInterruptPending; reg = reg->treg_next)
223 {
224 /* For each transistor region, check if there is an equivalent */
225 /* region at the same location in a subcell. The device in the */
226 /* subcell is given priority. This avoids duplicating devices */
227 /* when, for example, a device contact is placed in another */
228 /* cell, which can happen for devices like capacitors and */
229 /* diodes, where the device identifier layer may include */
230 /* a contact type. NOTE: This routine needs to limit the */
231 /* search to devices in the same plane as the transistor under */
232 /* consideration. */
233
234 SearchContext scontext;
235 CellUse dummy;
236 int extFoundFunc();
237 TileTypeBitMask transPlaneMask;
238
239 scontext.scx_use = &dummy;
240 dummy.cu_def = def;
241 dummy.cu_id = NULL;
242 scontext.scx_trans = GeoIdentityTransform;
243 scontext.scx_area.r_ll = scontext.scx_area.r_ur = reg->treg_tile->ti_ll;
244 scontext.scx_area.r_ur.p_x++;
245 scontext.scx_area.r_ur.p_y++;
246
247 TTMaskAndMask3(&transPlaneMask, &ExtCurStyle->exts_deviceMask,
248 &DBPlaneTypes[reg->treg_pnum]);
249
250 if (DBTreeSrTiles(&scontext, &transPlaneMask, 0, extFoundFunc,
251 (ClientData)def) != 0)
252 reg->treg_type = TT_SPACE; /* Disables the trans record */
253 }
254
255 /*
256 * Build up a list of the electrical nodes (equipotentials)
257 * for extOutputNodes() below. For this, we definitely want
258 * to leave each tile pointing to its associated Region struct.
259 * Compute resistance and capacitance on the fly.
260 * Use a special-purpose version of ExtFindRegions for speed.
261 */
262 if (!SigInterruptPending)
263 nodeList = extFindNodes(def, (Rect *) NULL, FALSE);
264
265 glob_subsnode = temp_subsnode; // Keep a record of the def's substrate
266
267 /* Assign the labels to their associated regions */
268 if (!SigInterruptPending)
269 ExtLabelRegions(def, ExtCurStyle->exts_nodeConn, &nodeList, &TiPlaneRect);
270
271 /* Check for "LEFview", for which special output handling */
272 /* can be specified in ext2spice. */
273
274 DBPropGet(def, "LEFview", &isabstract);
275
276 /*
277 * Make sure all geometry with the same label is part of the
278 * same electrical node. However: Unconnected labels are allowed
279 * on abstract views.
280 */
281 if (!SigInterruptPending && (ExtDoWarn & EXTWARN_DUP) && !isabstract)
282 extFindDuplicateLabels(def, nodeList);
283
284 /*
285 * Build up table of coupling capacitances (overlap, sidewall).
286 * This comes before extOutputNodes because we may have to adjust
287 * node capacitances in this step.
288 */
289 if (!SigInterruptPending && (ExtOptions&EXT_DOCOUPLING))
290 {
291 coupleInitialized = TRUE;
292 HashInit(&extCoupleHash, 256, HashSize(sizeof (CoupleKey)));
293 extFindCoupling(def, &extCoupleHash, (Rect *) NULL);
294
295 /* Convert coupling capacitance to the substrate node to
296 * substrate capacitance on each node in nreg_cap
297 */
298
299 if (ExtCurStyle->exts_globSubstratePlane != -1)
300 if (!SigInterruptPending && (ExtOptions&EXT_DOCOUPLING))
301 extRelocateSubstrateCoupling(&extCoupleHash, glob_subsnode);
302 }
303
304 /* Output device parameters for any subcircuit devices */
305 if (!SigInterruptPending)
306 extOutputParameters(def, transList, outFile);
307
308 /* Check for "device", as it modifies handling of parasitics */
309 propptr = (char *)DBPropGet(def, "device", &propfound);
310 if (propfound)
311 {
312 /* Remove parasitics from local nodes */
313 NodeRegion *tnode;
314 for (tnode = nodeList; tnode; tnode = tnode->nreg_next)
315 {
316 tnode->nreg_cap = (CapValue)0.0;
317 tnode->nreg_resist = (ResValue)0;
318 }
319 }
320
321 if (isabstract) fprintf(outFile, "abstract\n");
322
323 /* Output each node, along with its resistance and capacitance to substrate */
324 if (!SigInterruptPending)
325 extOutputNodes(nodeList, outFile, glob_subsnode);
326
327 /* Output coupling capacitances */
328 if (!SigInterruptPending && (ExtOptions&EXT_DOCOUPLING) && (!propfound))
329 extOutputCoupling(&extCoupleHash, outFile);
330
331 /* Output devices and connectivity between nodes */
332 if (!SigInterruptPending)
333 {
334 int llx, lly, urx, ury, devidx, l, w;
335 char *token, *modelname, *subsnode;
336 char *propvalue;
337
338 modelname = NULL;
339 subsnode = NULL;
340 propvalue = NULL;
341
342 if (propfound)
343 {
344 /* Sanity checking on syntax of property line, plus */
345 /* conversion of values to internal units. */
346 propvalue = StrDup((char **)NULL, propptr);
347 token = strtok(propvalue, " ");
348 devidx = Lookup(token, extDevTable);
349 if (devidx < 0)
350 {
351 TxError("Extract error: \"device\" property has unknown "
352 "device type.\n", token);
353 propfound = FALSE;
354 }
355 if (propfound)
356 {
357 token = strtok(NULL, " ");
358 if (token == NULL)
359 propfound = FALSE;
360 else
361 modelname = StrDup((char **)NULL, token);
362 }
363 if (propfound)
364 {
365 token = strtok(NULL, " ");
366 if ((token == NULL) || !sscanf(token, "%d", &llx))
367 propfound = FALSE;
368 else
369 llx *= ExtCurStyle->exts_unitsPerLambda;
370 }
371 if (propfound)
372 {
373 token = strtok(NULL, " ");
374 if ((token == NULL) || !sscanf(token, "%d", &lly))
375 propfound = FALSE;
376 else
377 lly *= ExtCurStyle->exts_unitsPerLambda;
378 }
379 if (propfound)
380 {
381 token = strtok(NULL, " ");
382 if ((token == NULL) || !sscanf(token, "%d", &urx))
383 propfound = FALSE;
384 else
385 urx *= ExtCurStyle->exts_unitsPerLambda;
386 if (urx <= llx) urx++;
387 }
388 if (propfound)
389 {
390 token = strtok(NULL, " ");
391 if ((token == NULL) || !sscanf(token, "%d", &ury))
392 propfound = FALSE;
393 else
394 ury *= ExtCurStyle->exts_unitsPerLambda;
395 if (ury <= lly) ury++;
396 }
397 if (propfound)
398 {
399 switch (devidx)
400 {
401 case DEV_FET:
402 /* Read area */
403 token = strtok(NULL, " ");
404 if ((token == NULL) || !sscanf(token, "%d", &w))
405 propfound = FALSE;
406 else
407 w *= ExtCurStyle->exts_unitsPerLambda *
408 ExtCurStyle->exts_unitsPerLambda;
409 /* Read perimeter */
410 token = strtok(NULL, " ");
411 if ((token == NULL) || !sscanf(token, "%d", &l))
412 propfound = FALSE;
413 else
414 l *= ExtCurStyle->exts_unitsPerLambda;
415 break;
416 case DEV_MOSFET:
417 case DEV_ASYMMETRIC:
418 case DEV_BJT:
419 /* Read width */
420 token = strtok(NULL, " ");
421 if ((token == NULL) || !sscanf(token, "%d", &w))
422 propfound = FALSE;
423 else
424 w *= ExtCurStyle->exts_unitsPerLambda;
425 /* Read length */
426 token = strtok(NULL, " ");
427 if ((token == NULL) || !sscanf(token, "%d", &l))
428 propfound = FALSE;
429 else
430 l *= ExtCurStyle->exts_unitsPerLambda;
431 break;
432 case DEV_RES:
433 if (strcmp(modelname, "None"))
434 {
435 /* Read width */
436 token = strtok(NULL, " ");
437 if ((token == NULL) || !sscanf(token, "%d", &w))
438 propfound = FALSE;
439 else
440 w *= ExtCurStyle->exts_unitsPerLambda;
441 /* Read length */
442 token = strtok(NULL, " ");
443 if ((token == NULL) || !sscanf(token, "%d", &l))
444 propfound = FALSE;
445 else
446 l *= ExtCurStyle->exts_unitsPerLambda;
447 break;
448 }
449 break;
450 case DEV_CAP:
451 case DEV_CAPREV:
452 if (strcmp(modelname, "None"))
453 {
454 /* Read area */
455 token = strtok(NULL, " ");
456 if ((token == NULL) || !sscanf(token, "%d", &w))
457 propfound = FALSE;
458 else
459 w *= ExtCurStyle->exts_unitsPerLambda *
460 ExtCurStyle->exts_unitsPerLambda;
461 /* Read perimeter */
462 token = strtok(NULL, " ");
463 if ((token == NULL) || !sscanf(token, "%d", &l))
464 propfound = FALSE;
465 else
466 l *= ExtCurStyle->exts_unitsPerLambda;
467 break;
468 }
469 break;
470 }
471 }
472
473 if (propfound)
474 {
475 if (devidx == DEV_FET)
476 fprintf(outFile, "fet");
477 else
478 fprintf(outFile, "device %s", extDevTable[devidx]);
479 fprintf(outFile, " %s %d %d %d %d", modelname,
480 llx, lly, urx, ury);
481 switch (devidx) {
482 case DEV_FET:
483 case DEV_MOSFET:
484 case DEV_ASYMMETRIC:
485 case DEV_BJT:
486 fprintf(outFile, " %d %d", w, l);
487 break;
488 case DEV_RES:
489 case DEV_CAP:
490 case DEV_CAPREV:
491 if (strcmp(modelname, "None"))
492 fprintf(outFile, " %d %d", w, l);
493 break;
494 }
495 /* Print remainder of arguments verbatim. */
496 /* Note: There should be additional checks on */
497 /* node triplets including area and perim. conversions */
498 while (1) {
499 token = strtok(NULL, " ");
500 if (token == NULL)
501 break;
502 else
503 fprintf(outFile, " %s", token);
504 }
505 }
506 else if (devidx >= 0)
507 {
508 TxError("Extract error: \"device %s\" property syntax"
509 " error\n", extDevTable[devidx]);
510 }
511 if (modelname) freeMagic(modelname);
512 if (propvalue) freeMagic(propvalue);
513 }
514
515 if (!propfound)
516 extOutputDevices(def, transList, outFile);
517 }
518
519 /* Clean up */
520 if (coupleInitialized)
521 extCapHashKill(&extCoupleHash);
522 ExtFreeLabRegions((LabRegion *) transList);
523 return (nodeList);
524 }
525
526 /*
527 * ----------------------------------------------------------------------------
528 *
529 * extSetResist --
530 *
531 * The input to this procedure is a pointer to a NodeRegion.
532 * Its resistance is computed from the area and perimeter stored
533 * in the arrays extResistPerim[] and extResistArea[]. These arrays
534 * are then reset to zero.
535 *
536 * We approximate the resistive region as a collection of rectangles
537 * of width W and length L, one for each set of layers having a different
538 * sheet resistivity. We do so by noting that for a rectangle,
539 *
540 * Area = L * W
541 * Perimeter = 2 * (L + W)
542 *
543 * Solving the two simultaneous equations for L yields the following
544 * quadratic:
545 *
546 * 2 * (L**2) - Perimeter * L + 2 * Area = 0
547 *
548 * Solving this quadratic for L, the longer dimension, we get
549 *
550 * L = (Perimeter + S) / 4
551 *
552 * where
553 *
554 * S = sqrt( (Perimeter**2) - 16 * Area )
555 *
556 * The smaller dimension is W, ie,
557 *
558 * W = (Perimeter - S) / 4
559 *
560 * The resistance is L / W squares:
561 *
562 * Perimeter + S
563 * R = -------------
564 * Perimeter - S
565 *
566 * Results:
567 * None.
568 *
569 * Side effects:
570 * See the comments above.
571 *
572 * ----------------------------------------------------------------------------
573 */
574
575 void
extSetResist(reg)576 extSetResist(reg)
577 NodeRegion *reg;
578 {
579 int n, perim;
580 dlong area;
581 float s, fperim, v;
582
583 for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
584 {
585 reg->nreg_pa[n].pa_area = area = extResistArea[n];
586 reg->nreg_pa[n].pa_perim = perim = extResistPerim[n];
587 if (area > 0 && perim > 0)
588 {
589 v = (double) (perim*perim - 16*area);
590
591 /* Approximate by one square if v < 0 */
592 if (v < 0) s = 0; else s = sqrt(v);
593
594 fperim = (float) perim;
595 reg->nreg_resist += (fperim + s) / (fperim - s)
596 * ExtCurStyle->exts_resistByResistClass[n];
597 }
598
599 /* Reset for the next pass */
600 extResistArea[n] = extResistPerim[n] = 0;
601 }
602 }
603
604 /*
605 * ----------------------------------------------------------------------------
606 *
607 * extOutputNodes --
608 *
609 * The resistance and capacitance of each node have already been
610 * computed, so all we need do is output them.
611 *
612 * Results:
613 * None.
614 *
615 * Side effects:
616 * Writes a number of 'node' and 'equiv' records to the file 'outFile'.
617 *
618 * Interruptible. If SigInterruptPending is detected, we stop outputting
619 * nodes and return.
620 *
621 * ----------------------------------------------------------------------------
622 */
623
624 void
extOutputNodes(nodeList,outFile)625 extOutputNodes(nodeList, outFile)
626 NodeRegion *nodeList; /* Nodes */
627 FILE *outFile; /* Output file */
628 {
629 ResValue rround = ExtCurStyle->exts_resistScale / 2;
630 CapValue finC;
631 int intR;
632 NodeRegion *reg;
633 LabelList *ll;
634 char *cp;
635 int n;
636 Label *lab;
637 char *text;
638
639 /* If this node is a subcircuit port, it gets special treatment. */
640 /* There may be multiple ports per node. */
641
642 for (reg = nodeList; reg && !SigInterruptPending; reg = reg->nreg_next)
643 for (ll = reg->nreg_labels; ll; ll = ll->ll_next)
644 if (ll->ll_attr == LL_PORTATTR)
645 {
646 fprintf(outFile, "port \"%s\" %d %d %d %d %d %s\n",
647 ll->ll_label->lab_text,
648 ll->ll_label->lab_port,
649 ll->ll_label->lab_rect.r_xbot,
650 ll->ll_label->lab_rect.r_ybot,
651 ll->ll_label->lab_rect.r_xtop,
652 ll->ll_label->lab_rect.r_ytop,
653 DBTypeShortName(ll->ll_label->lab_type));
654
655 /* If the port name matches the node name to be written */
656 /* to the node record, then reassign the node position */
657 /* and type to be that of the port, so we don't have a */
658 /* conflict. */
659
660 if (!strcmp(extNodeName((LabRegion *) reg),
661 ll->ll_label->lab_text))
662 {
663 reg->nreg_ll.p_x = ll->ll_label->lab_rect.r_xbot;
664 reg->nreg_ll.p_y = ll->ll_label->lab_rect.r_ybot;
665 reg->nreg_type = ll->ll_label->lab_type;
666 reg->nreg_pnum = DBPlane(reg->nreg_type);
667 }
668 }
669
670 for (reg = nodeList; reg && !SigInterruptPending; reg = reg->nreg_next)
671 {
672 /* Output the node */
673 text = extNodeName((LabRegion *) reg);
674
675 /* Check if this node is the substrate */
676 if (reg == glob_subsnode)
677 {
678 fprintf(outFile, "substrate \"%s\" 0 0", text);
679 }
680 else
681 {
682 intR = (reg->nreg_resist + rround) / ExtCurStyle->exts_resistScale;
683 finC = reg->nreg_cap/ExtCurStyle->exts_capScale;
684 fprintf(outFile, "node \"%s\" %d %lg", text, intR, finC);
685 }
686
687 /* Output its location (lower-leftmost point and type name) */
688
689 if (reg->nreg_type & TT_DIAGONAL) {
690 /* Node may be recorded as a diagonal tile if no other */
691 /* non-diagonal tiles are adjoining it. */
692
693 TileType loctype = (reg->nreg_type & TT_SIDE) ? ((reg->nreg_type &
694 TT_RIGHTMASK) >> 14) : (reg->nreg_type & TT_LEFTMASK);
695
696 fprintf(outFile, " %d %d %s",
697 reg->nreg_ll.p_x, reg->nreg_ll.p_y,
698 DBTypeShortName(loctype));
699 }
700 else
701 {
702 fprintf(outFile, " %d %d %s",
703 reg->nreg_ll.p_x, reg->nreg_ll.p_y,
704 DBTypeShortName(reg->nreg_type));
705 }
706
707 /* Output its area and perimeter for each resistivity class */
708 for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
709 fprintf(outFile, " %"DLONG_PREFIX"d %d", reg->nreg_pa[n].pa_area,
710 reg->nreg_pa[n].pa_perim);
711 (void) putc('\n', outFile);
712
713 /* Output its attribute list */
714 for (ll = reg->nreg_labels; ll; ll = ll->ll_next)
715 if (extLabType(ll->ll_label->lab_text, LABTYPE_NODEATTR))
716 {
717 /* Don't output the trailing character for node attributes */
718 lab = ll->ll_label;
719 fprintf(outFile, "attr %s %d %d %d %d %s \"",
720 text, lab->lab_rect.r_xbot, lab->lab_rect.r_ybot,
721 lab->lab_rect.r_xtop, lab->lab_rect.r_ytop,
722 DBTypeShortName(lab->lab_type));
723 cp = lab->lab_text;
724 n = strlen(cp) - 1;
725 while (n-- > 0)
726 putc(*cp++, outFile);
727 fprintf(outFile, "\"\n");
728 }
729
730 /* Output the alternate names for the node. Avoid generating */
731 /* unnecessary "equiv A A" entries for labels on disconnected */
732 /* nets. Also avoid multiple "equiv" statements with the same */
733 /* nets (happens when ports with the same name have different */
734 /* port numbers, which should probably just be prohibited), and */
735 /* raise an error if two ports with different names are being */
736 /* marked as equivalent. */
737
738 for (ll = reg->nreg_labels; ll; ll = ll->ll_next)
739 {
740 bool isPort;
741
742 /* Do not export aliases that are not ports unless the */
743 /* "extract do aliases" options was selected. */
744
745 if (ll->ll_label->lab_text == text)
746 {
747 char *portname = NULL;
748 char *lastname = NULL;
749
750 isPort = (ll->ll_attr == LL_PORTATTR) ? TRUE : FALSE;
751 if (isPort) portname = text;
752
753 for (ll = ll->ll_next; ll; ll = ll->ll_next)
754 if (extLabType(ll->ll_label->lab_text, LABTYPE_NAME))
755 if (strcmp(text, ll->ll_label->lab_text))
756 {
757 if ((ll->ll_attr == LL_PORTATTR) ||
758 (ExtOptions & EXT_DOALIASES))
759 {
760 if ((portname == NULL) ||
761 (strcmp(ll->ll_label->lab_text, portname)))
762 {
763 if ((lastname == NULL) ||
764 (strcmp(ll->ll_label->lab_text, lastname)))
765 fprintf(outFile, "equiv \"%s\" \"%s\"\n",
766 text, ll->ll_label->lab_text);
767 lastname = ll->ll_label->lab_text;
768 }
769 if ((portname != NULL) &&
770 (strcmp(ll->ll_label->lab_text, portname)))
771 TxError("Warning: Ports \"%s\" and \"%s\" are"
772 " electrically shorted.\n",
773 text, ll->ll_label->lab_text);
774 if (!isPort && (ll->ll_attr == LL_PORTATTR))
775 portname = ll->ll_label->lab_text;
776 }
777 }
778 break;
779 }
780 }
781 }
782 }
783
784 /*
785 * ---------------------------------------------------------------------
786 *
787 * extSubsName --
788 *
789 * Return the name of the substrate node, if the node belongs to
790 * the substrate region and a global substrate node name has been
791 * specified by the tech file. If the substrate node name is a
792 * Tcl variable name, then perform the variable substitution.
793 *
794 * Results:
795 * Pointer to a character string.
796 *
797 * Side Effects:
798 * None.
799 *
800 * ---------------------------------------------------------------------
801 */
802
803 char *
extSubsName(node)804 extSubsName(node)
805 LabRegion *node;
806 {
807 char *subsName;
808
809 /* If the techfile specifies a global name for the substrate, use */
810 /* that in preference to the default "p_x_y#" name. Use this name */
811 /* only to substitute for nodes with tiles at -(infinity). */
812
813 if (ExtCurStyle->exts_globSubstrateName != NULL)
814 {
815 if (node->lreg_ll.p_x <= (MINFINITY + 3))
816 {
817 if (ExtCurStyle->exts_globSubstrateName[0] == '$' &&
818 ExtCurStyle->exts_globSubstrateName[1] != '$')
819 {
820 // If subsName is a Tcl variable (begins with "$"), make the
821 // variable substitution, if one exists. Ignore double-$.
822 // If the variable is undefined in the interpreter, then
823 // strip the "$" from the front as this is not legal in most
824 // netlist formats.
825
826 char *varsub = (char *)Tcl_GetVar(magicinterp,
827 &ExtCurStyle->exts_globSubstrateName[1],
828 TCL_GLOBAL_ONLY);
829 return (varsub != NULL) ? varsub : ExtCurStyle->exts_globSubstrateName
830 + 1;
831 }
832 else
833 return ExtCurStyle->exts_globSubstrateName;
834 }
835 else return NULL;
836 }
837 return NULL;
838 }
839
840 /*
841 * ----------------------------------------------------------------------------
842 *
843 * extMakeNodeNumPrint --
844 *
845 * Construct a node name from the plane number "plane" and lower left Point
846 * "coord", and place it in the string "buf" (which must be large enough).
847 *
848 * Results:
849 * None.
850 *
851 * Side Effects:
852 * Fills in string "buf".
853 *
854 * ----------------------------------------------------------------------------
855 */
856
857 void
extMakeNodeNumPrint(buf,lreg)858 extMakeNodeNumPrint(buf, lreg)
859 char *buf;
860 LabRegion *lreg;
861 {
862 int plane = lreg->lreg_pnum;
863 Point *p = &lreg->lreg_ll;
864 char *subsName;
865
866 subsName = extSubsName(lreg);
867 if (subsName != NULL)
868 strcpy(buf, subsName);
869 else
870 sprintf(buf, "%s_%s%d_%s%d#",
871 DBPlaneShortName(plane),
872 (p->p_x < 0) ? "n": "", abs(p->p_x),
873 (p->p_y < 0) ? "n": "", abs(p->p_y));
874 }
875
876 /*
877 * ----------------------------------------------------------------------------
878 *
879 * extNodeName --
880 *
881 * Given a pointer to a LabRegion, return a pointer to a string
882 * that can be printed as the name of the node. If the LabRegion
883 * has a list of attached labels, use one of the labels; otherwise,
884 * use its node number.
885 *
886 * Results:
887 * Returns a pointer to a string. If the node had a label, this
888 * is a pointer to the lab_text field of the first label on the
889 * label list for the node; otherwise, it is a pointer to a static
890 * buffer into which we have printed the node number.
891 *
892 * Side effects:
893 * May overwrite the static buffer used to hold the printable
894 * version of a node number.
895 *
896 * ----------------------------------------------------------------------------
897 */
898
899 char *
extNodeName(node)900 extNodeName(node)
901 LabRegion *node;
902 {
903 static char namebuf[256]; /* Big enough to hold a generated nodename */
904 LabelList *ll;
905
906 if (node == (LabRegion *) NULL || SigInterruptPending)
907 return ("(none)");
908
909 for (ll = node->lreg_labels; ll; ll = ll->ll_next)
910 if (extLabType(ll->ll_label->lab_text, LABTYPE_NAME))
911 return (ll->ll_label->lab_text);
912
913 extMakeNodeNumPrint(namebuf, node);
914 return (namebuf);
915 }
916
917 /*
918 * ----------------------------------------------------------------------------
919 *
920 * extFindDuplicateLabels --
921 *
922 * Verify that no node in the list 'nreg' has a label that appears in
923 * any other node in the list. Leave a warning turd if one is.
924 *
925 * Results:
926 * None.
927 *
928 * Side effects:
929 * Leaves feedback attached to each node that contains a label
930 * duplicated in another node.
931 *
932 * ----------------------------------------------------------------------------
933 */
934
935 void
extFindDuplicateLabels(def,nreg)936 extFindDuplicateLabels(def, nreg)
937 CellDef *def;
938 NodeRegion *nreg;
939 {
940 static char *badmesg =
941 "Label \"%s\" attached to more than one unconnected node: %s";
942 bool hashInitialized = FALSE;
943 char message[512], name[512], *text;
944 NodeRegion *np, *np2;
945 LabelList *ll, *ll2;
946 HashEntry *he;
947 NodeRegion *lastreg;
948 NodeRegion badLabel;
949 HashTable labelHash;
950 Rect r;
951
952 for (np = nreg; np; np = np->nreg_next)
953 {
954 for (ll = np->nreg_labels; ll; ll = ll->ll_next)
955 {
956 text = ll->ll_label->lab_text;
957 if (!extLabType(text, LABTYPE_NAME))
958 continue;
959
960 if (!hashInitialized)
961 HashInit(&labelHash, 32, 0), hashInitialized = TRUE;
962 he = HashFind(&labelHash, text);
963 lastreg = (NodeRegion *) HashGetValue(he);
964 if (lastreg == (NodeRegion *) NULL)
965 HashSetValue(he, (ClientData) np);
966 else if (lastreg != np && lastreg != &badLabel)
967 {
968 /*
969 * Make a pass through all labels for all nodes.
970 * Leave a feedback turd over each instance of the
971 * offending label.
972 */
973 for (np2 = nreg; np2; np2 = np2->nreg_next)
974 {
975 for (ll2 = np2->nreg_labels; ll2; ll2 = ll2->ll_next)
976 {
977 if (strcmp(ll2->ll_label->lab_text, text) == 0)
978 {
979 extNumWarnings++;
980 if (!DebugIsSet(extDebugID, extDebNoFeedback))
981 {
982 r.r_ll = r.r_ur = ll2->ll_label->lab_rect.r_ll;
983 r.r_xbot--, r.r_ybot--, r.r_xtop++, r.r_ytop++;
984 extMakeNodeNumPrint(name, np2);
985 (void) sprintf(message, badmesg, text, name);
986 DBWFeedbackAdd(&r, message, def,
987 1, STYLE_PALEHIGHLIGHTS);
988 }
989 }
990 }
991 }
992
993 /* Mark this label as already having generated an error */
994 HashSetValue(he, (ClientData) &badLabel);
995 }
996 }
997 }
998
999 if (hashInitialized)
1000 HashKill(&labelHash);
1001 }
1002
1003 /*
1004 * ---------------------------------------------------------------------
1005 *
1006 * ExtSortTerminals --
1007 *
1008 * Sort the terminals of a transistor so that the terminal with the
1009 * lowest leftmost coordinate on the plane with the lowest number is
1010 * output first.
1011 *
1012 * Results:
1013 * None
1014 *
1015 * Side effects:
1016 * The tr_termnode, tr_termlen, and tr_termpos entries may change.
1017 *
1018 * ---------------------------------------------------------------------
1019 */
1020
1021 void
ExtSortTerminals(tran,ll)1022 ExtSortTerminals(tran, ll)
1023 struct transRec *tran;
1024 LabelList *ll;
1025 {
1026 int nsd, changed;
1027 TermTilePos *p1, *p2;
1028 NodeRegion *tmp_node;
1029 TermTilePos tmp_pos;
1030 int tmp_len;
1031 LabelList *lp;
1032
1033 do
1034 {
1035 changed = 0;
1036 for( nsd = 0; nsd < tran->tr_nterm-1; nsd++ )
1037 {
1038 p1 = &(tran->tr_termpos[nsd]);
1039 p2 = &(tran->tr_termpos[nsd+1]);
1040 if( p2->pnum > p1->pnum )
1041 continue;
1042 else if( p2->pnum == p1->pnum )
1043 {
1044 if( p2->pt.p_x > p1->pt.p_x )
1045 continue;
1046 else if( p2->pt.p_x == p1->pt.p_x && p2->pt.p_y > p1->pt.p_y )
1047 continue;
1048 else if( p2->pt.p_x == p1->pt.p_x && p2->pt.p_y == p1->pt.p_y )
1049 {
1050 TxPrintf("Extract error: Duplicate tile position, ignoring\n");
1051 continue;
1052 }
1053 }
1054 changed = 1;
1055 tmp_node = tran->tr_termnode[nsd];
1056 tmp_pos = tran->tr_termpos[nsd];
1057 tmp_len = tran->tr_termlen[nsd];
1058
1059 tran->tr_termnode[nsd] = tran->tr_termnode[nsd+1];
1060 tran->tr_termpos[nsd] = tran->tr_termpos[nsd+1];
1061 tran->tr_termlen[nsd] = tran->tr_termlen[nsd+1];
1062
1063 tran->tr_termnode[nsd+1] = tmp_node;
1064 tran->tr_termpos[nsd+1] = tmp_pos;
1065 tran->tr_termlen[nsd+1] = tmp_len;
1066 /* Need to SWAP the indices in the labRegion too.
1067 * These for loops within the bubblesort in here are kinda slow
1068 * but S,D attributes are not that common so it should not matter
1069 * that much -- Stefanos 5/96 */
1070 for ( lp = ll ; lp ; lp = lp->ll_next )
1071 if ( lp->ll_attr == nsd ) lp->ll_attr = LL_SORTATTR ;
1072 else if ( lp->ll_attr == nsd+1 ) lp->ll_attr = nsd ;
1073 for ( lp = ll ; lp ; lp = lp->ll_next )
1074 if ( lp->ll_attr == LL_SORTATTR ) lp->ll_attr = nsd+1;
1075 }
1076 }
1077 while( changed );
1078 }
1079
1080 /*
1081 *----------------------------------------------------------------------
1082 *
1083 * extComputeCapLW --
1084 *
1085 * Determine effective length and width of a rectangular capacitor,
1086 * based on the boundary vectors stored in extSpecialBounds. This
1087 * routine should only be called for capacitors that have exactly
1088 * one terminal.
1089 *
1090 * Results:
1091 * None
1092 *
1093 * Side Effects:
1094 * Puts effective length and width into the pointers
1095 * passed as arguments.
1096 *----------------------------------------------------------------------
1097 */
1098
1099 void
extComputeCapLW(rlengthptr,rwidthptr)1100 extComputeCapLW(rlengthptr, rwidthptr)
1101 int *rlengthptr, *rwidthptr;
1102 {
1103 LinkedBoundary *lb;
1104 Rect bbox;
1105
1106 /* Quick algorithm---ignore tabs, compute max extents of */
1107 /* the special bounds vector. */
1108
1109 lb = extSpecialBounds[0];
1110 if (lb == NULL)
1111 {
1112 TxError("extract: Can't get capacitor L and W\n");
1113 return; /* error condition */
1114 }
1115 bbox = lb->r;
1116 for (lb = extSpecialBounds[0]; lb != NULL; lb = lb->b_next)
1117 GeoIncludeAll(&lb->r, &bbox);
1118
1119 *rwidthptr = bbox.r_xtop - bbox.r_xbot;
1120 *rlengthptr = bbox.r_ytop - bbox.r_ybot;
1121 }
1122
1123 /*
1124 *----------------------------------------------------------------------
1125 *
1126 * extComputeEffectiveLW --
1127 *
1128 * Determine effective length and width of an annular (or otherwise
1129 * non-rectangular) transistor structure, based on the boundary vectors
1130 * stored in extSpecialBounds.
1131 *
1132 * Note that "L" and "W" are reversed when this routine is called
1133 * to compute L and W for a resistor. The sense of "length" and
1134 * "width" as used in the routine are appropriate for a transistor.
1135 *
1136 * Also note that this algorithm will tend to over-estimate the width
1137 * of transistors with angled bends. This problem would be eliminated
1138 * if non-Manhattan geometry were evaluated directly rather than being
1139 * first converted to Manhattan geometry.
1140 *
1141 * Results:
1142 * None.
1143 *
1144 * Side Effects:
1145 * Puts effective length and width into the pointers
1146 * passed as arguments.
1147 *----------------------------------------------------------------------
1148 */
1149
1150 void
extComputeEffectiveLW(rlengthptr,rwidthptr,numregions,chop)1151 extComputeEffectiveLW(rlengthptr, rwidthptr, numregions, chop)
1152 int *rlengthptr, *rwidthptr;
1153 int numregions;
1154 float chop;
1155 {
1156 int i, j, p, jmax;
1157 LinkedBoundary *lb, *lb2;
1158 int oppdir, length, loclength, testlen, width;
1159 int locwidth, testwid, cornerw;
1160 int segp, segn, segc, sege;
1161 bool isComplex = FALSE;
1162
1163 /* First, check for MOScap-connected transistors. In such
1164 * cases, one or more extSpecialBounds[] is NULL. Try to
1165 * separate the existing extSpecialBounds[] vectors into
1166 * independent (non-connecting) vectors.
1167 */
1168
1169 /* For each segment in the primary list, find the closest
1170 * segment in the other list which lies on the opposite
1171 * side of the gate area. Calculate the length, and check
1172 * for overlap, treating the length as a corner extension.
1173 *
1174 * The primary list is chosen as the one with the largest
1175 * number of elements. This helps prevent the algorithm from
1176 * producing a different result for devices at different
1177 * orientations.
1178 */
1179
1180 p = 0;
1181 jmax = 0;
1182 for (i = 0; i < numregions; i++)
1183 {
1184 j = 0;
1185 for (lb = extSpecialBounds[i]; lb != NULL; lb = lb->b_next) j++;
1186 if (j > jmax)
1187 {
1188 jmax = j;
1189 p = i;
1190 }
1191 }
1192
1193 /* fprintf(stderr, "Annular transistor detailed L,W computation:\n"); */
1194
1195 width = 0;
1196 length = 0;
1197 for (lb = extSpecialBounds[p]; lb != NULL; lb = lb->b_next)
1198 {
1199 loclength = INFINITY;
1200 switch (lb->dir)
1201 {
1202 case BD_LEFT: oppdir = BD_RIGHT; break;
1203 case BD_RIGHT: oppdir = BD_LEFT; break;
1204 case BD_TOP: oppdir = BD_BOTTOM; break;
1205 case BD_BOTTOM: oppdir = BD_TOP; break;
1206 }
1207
1208 /* First pass: Find the distance of the closest segment within */
1209 /* the range of its corner extension. We do two passes because */
1210 /* there may be more than one segment at this distance. */
1211
1212 for (i = 0; i < numregions; i++)
1213 {
1214 if ((i == p) && (numregions > 1)) continue;
1215 for (lb2 = extSpecialBounds[i]; lb2 != NULL; lb2 = lb2->b_next)
1216 {
1217 if (lb2->dir == oppdir)
1218 {
1219 switch (lb->dir)
1220 {
1221 case BD_LEFT:
1222 if (lb2->r.r_xbot > lb->r.r_xbot)
1223 {
1224 testlen = lb2->r.r_xbot - lb->r.r_xbot;
1225 if (lb2->r.r_ybot < lb->r.r_ytop + testlen &&
1226 lb2->r.r_ytop > lb->r.r_ybot - testlen)
1227 {
1228 /* Adjustments for offset segments */
1229 if (lb2->r.r_ybot > lb->r.r_ytop)
1230 testlen += lb2->r.r_ybot - lb->r.r_ytop;
1231 else if (lb2->r.r_ytop < lb->r.r_ybot)
1232 testlen += lb->r.r_ybot - lb2->r.r_ytop;
1233
1234 if (testlen < loclength) loclength = testlen;
1235 }
1236 }
1237 break;
1238 case BD_RIGHT:
1239 if (lb2->r.r_xtop < lb->r.r_xtop)
1240 {
1241 testlen = lb->r.r_xtop - lb2->r.r_xtop;
1242 if (lb2->r.r_ybot < lb->r.r_ytop + testlen &&
1243 lb2->r.r_ytop > lb->r.r_ybot - testlen)
1244 {
1245 /* Adjustments for offset segments */
1246 if (lb2->r.r_ybot > lb->r.r_ytop)
1247 testlen += lb2->r.r_ybot - lb->r.r_ytop;
1248 else if (lb2->r.r_ytop < lb->r.r_ybot)
1249 testlen += lb->r.r_ybot - lb2->r.r_ytop;
1250
1251 if (testlen < loclength) loclength = testlen;
1252 }
1253 }
1254 break;
1255 case BD_TOP:
1256 if (lb2->r.r_ytop < lb->r.r_ytop)
1257 {
1258 testlen = lb->r.r_ytop - lb2->r.r_ytop;
1259 if (lb2->r.r_xbot < lb->r.r_xtop + testlen &&
1260 lb2->r.r_xtop > lb->r.r_xbot - testlen)
1261 {
1262 /* Adjustments for offset segments */
1263 if (lb2->r.r_xbot > lb->r.r_xtop)
1264 testlen += lb2->r.r_xbot - lb->r.r_xtop;
1265 else if (lb2->r.r_xtop < lb->r.r_xbot)
1266 testlen += lb->r.r_xbot - lb2->r.r_xtop;
1267
1268 if (testlen < loclength) loclength = testlen;
1269 }
1270 }
1271 break;
1272 case BD_BOTTOM:
1273 if (lb2->r.r_ybot > lb->r.r_ybot)
1274 {
1275 testlen = lb2->r.r_ybot - lb->r.r_ybot;
1276 if (lb2->r.r_xbot < lb->r.r_xtop + testlen &&
1277 lb2->r.r_xtop > lb->r.r_xbot - testlen)
1278 {
1279 /* Adjustments for offset segments */
1280 if (lb2->r.r_xbot > lb->r.r_xtop)
1281 testlen += lb2->r.r_xbot - lb->r.r_xtop;
1282 else if (lb2->r.r_xtop < lb->r.r_xbot)
1283 testlen += lb->r.r_xbot - lb2->r.r_xtop;
1284
1285 if (testlen < loclength) loclength = testlen;
1286 }
1287 }
1288 break;
1289 }
1290 }
1291 }
1292 }
1293
1294 /* This segment should not be considered current-carrying; it */
1295 /* only adds to the gate capacitance. Should we output the */
1296 /* extra capacitance somewhere? */
1297
1298 if (loclength == INFINITY) continue;
1299
1300 /* Note that the L/W calculation ignores the possibility that a */
1301 /* transistor may have multiple lengths. Such cases should */
1302 /* either 1) scale the width to one of the lengths, or 2) out- */
1303 /* put a separate transistor record for each length. */
1304
1305 if (length == 0)
1306 length = loclength; /* Default length */
1307
1308 else if ((length != 0) && (length != loclength))
1309 {
1310 /* If the newly computed length is less than the */
1311 /* original, scale the original. Otherwise, scale */
1312 /* the new length. */
1313
1314 if (loclength < length)
1315 {
1316 width *= loclength;
1317 width /= length;
1318 length = loclength;
1319 }
1320 isComplex = TRUE;
1321 }
1322
1323 /* fprintf(stderr, " segment length = %d\n", loclength); */
1324
1325 /* Second pass: All segments at "length" distance add to the */
1326 /* length and width calculation. Sides opposite and corner */
1327 /* extensions are treated separately. Areas outside the corner */
1328 /* extension are ignored. */
1329
1330 locwidth = 0;
1331 cornerw = 0;
1332 for (i = 0; i < numregions; i++)
1333 {
1334 if ((i == p) && (numregions > 1)) continue;
1335 for (lb2 = extSpecialBounds[i]; lb2 != NULL; lb2 = lb2->b_next)
1336 {
1337 if (lb2->dir == oppdir)
1338 {
1339 if (((lb->dir == BD_LEFT) &&
1340 (lb2->r.r_xbot - lb->r.r_xbot == loclength)) ||
1341 ((lb->dir == BD_RIGHT) &&
1342 (lb->r.r_xtop - lb2->r.r_xtop == loclength)))
1343 {
1344 /* opposite */
1345 segp = MIN(lb2->r.r_ytop, lb->r.r_ytop);
1346 segn = MAX(lb2->r.r_ybot, lb->r.r_ybot);
1347 testwid = segp - segn;
1348 if (testwid > 0) locwidth += testwid * 2;
1349 if (testwid <= -loclength) continue;
1350
1351 /* corner extend top */
1352 segc = MAX(lb2->r.r_ytop, lb->r.r_ytop);
1353 sege = MAX(segp, segn);
1354 testwid = segc - sege;
1355 if (testwid > loclength) testwid = loclength;
1356 if (testwid > 0) cornerw += testwid;
1357
1358 /* corner extend bottom */
1359 segc = MIN(lb2->r.r_ybot, lb->r.r_ybot);
1360 sege = MIN(segp, segn);
1361 testwid = sege - segc;
1362 if (testwid > loclength) testwid = loclength;
1363 if (testwid > 0) cornerw += testwid;
1364 }
1365 else if (((lb->dir == BD_TOP) &&
1366 (lb->r.r_ytop - lb2->r.r_ytop == loclength)) ||
1367 ((lb->dir == BD_BOTTOM) &&
1368 (lb2->r.r_ybot - lb->r.r_ybot == loclength)))
1369 {
1370 /* opposite */
1371 segp = MIN(lb2->r.r_xtop, lb->r.r_xtop);
1372 segn = MAX(lb2->r.r_xbot, lb->r.r_xbot);
1373 testwid = segp - segn;
1374 if (testwid > 0) locwidth += testwid * 2;
1375 if (testwid <= -loclength) continue;
1376
1377 /* corner extend right */
1378 segc = MAX(lb2->r.r_xtop, lb->r.r_xtop);
1379 sege = MAX(segp, segn);
1380 testwid = segc - sege;
1381 if (testwid > loclength) testwid = loclength;
1382 if (testwid > 0) cornerw += testwid;
1383
1384 /* corner extend left */
1385 segc = MIN(lb2->r.r_xbot, lb->r.r_xbot);
1386 sege = MIN(segp, segn);
1387 testwid = sege - segc;
1388 if (testwid > loclength) testwid = loclength;
1389 if (testwid > 0) cornerw += testwid;
1390 }
1391 }
1392 }
1393 }
1394 /* if (width > 0)
1395 fprintf(stderr, " segment width = %d\n", width); */
1396
1397 /* Width scaling for transistor sections with different lengths */
1398 locwidth += (int)(0.5 + ((float)cornerw * chop));
1399 if (loclength != length)
1400 {
1401 locwidth *= length;
1402 locwidth /= loclength;
1403 }
1404 width += locwidth;
1405 }
1406 if ((length > 0) && (width > 0))
1407 {
1408 *rlengthptr = length;
1409
1410 // If numregions == 1 then everything was put in one record,
1411 // and we have double-counted the width.
1412
1413 if (numregions == 1)
1414 *rwidthptr = (width >> 2);
1415 else
1416 *rwidthptr = (width >> 1);
1417
1418 /* fprintf(stderr, "total L = %d, W = %d\n", length, width); */
1419 /* fflush(stderr); */
1420
1421 if (isComplex)
1422 TxError("Device has multiple lengths: scaling"
1423 " all widths to length %d\n", length);
1424 }
1425 }
1426
1427 /*
1428 * ----------------------------------------------------------------------------
1429 *
1430 * extSeparateBounds --
1431 *
1432 * Because the non-source/drain perimeter is not a node, all the
1433 * boundary vectors end up in one record. So we have to pry them
1434 * apart.
1435 *
1436 * Results:
1437 * None.
1438 *
1439 * Side effects:
1440 * Messes with the extSpecialBounds[] linked lists.
1441 *
1442 * ----------------------------------------------------------------------------
1443 */
1444
1445 void
extSeparateBounds(nterm)1446 extSeparateBounds(nterm)
1447 int nterm; /* last terminal (# terminals - 1) */
1448 {
1449 Rect lbrect;
1450 LinkedBoundary *lb, *lbstart, *lbend, *lblast, *lbnext;
1451 bool found;
1452
1453 /* Avoid crash condition on a badly-defined extract definition */
1454 if ((nterm < 0) || (extSpecialBounds[0] == NULL)) return;
1455
1456 if (extSpecialBounds[nterm] == NULL)
1457 {
1458 /* Put first record into the unused terminal entry */
1459 extSpecialBounds[nterm] = extSpecialBounds[0];
1460 extSpecialBounds[0] = extSpecialBounds[nterm]->b_next;
1461 extSpecialBounds[nterm]->b_next = NULL;
1462
1463 /* Add connected segments until no more are found */
1464 lbstart = lbend = extSpecialBounds[nterm];
1465 lbrect = lbstart->r;
1466 found = TRUE;
1467 while (found == TRUE)
1468 {
1469 lblast = NULL;
1470 found = FALSE;
1471 for (lb = extSpecialBounds[0]; lb != NULL; lb = lbnext)
1472 {
1473 /* perhaps we should cut down on these cases by */
1474 /* checking the direction of the segment. . . */
1475
1476 lbnext = lb->b_next;
1477 if (((lb->r.r_xbot == lbrect.r_xbot) &&
1478 (lb->r.r_ybot == lbrect.r_ybot)))
1479 {
1480 if (lblast == NULL)
1481 extSpecialBounds[0] = lb->b_next;
1482 else
1483 lblast->b_next = lb->b_next;
1484 // Insert lb after lbstart
1485 lb->b_next = lbstart->b_next;
1486 lbstart->b_next = lb;
1487 lbstart = lb;
1488 lbrect.r_xbot = lb->r.r_xtop;
1489 lbrect.r_ybot = lb->r.r_ytop;
1490 found = TRUE;
1491 }
1492 else if (((lb->r.r_xtop == lbrect.r_xbot) &&
1493 (lb->r.r_ytop == lbrect.r_ybot)))
1494 {
1495 if (lblast == NULL)
1496 extSpecialBounds[0] = lb->b_next;
1497 else
1498 lblast->b_next = lb->b_next;
1499 lb->b_next = lbstart->b_next;
1500 lbstart->b_next = lb;
1501 lbstart = lb;
1502 lbrect.r_xbot = lb->r.r_xbot;
1503 lbrect.r_ybot = lb->r.r_ybot;
1504 found = TRUE;
1505 }
1506 else if (((lb->r.r_xtop == lbrect.r_xtop) &&
1507 (lb->r.r_ytop == lbrect.r_ytop)))
1508 {
1509 if (lblast == NULL)
1510 extSpecialBounds[0] = lb->b_next;
1511 else
1512 lblast->b_next = lb->b_next;
1513 lb->b_next = lbend->b_next;
1514 lbend->b_next = lb;
1515 lbend = lb;
1516 lbrect.r_xtop = lb->r.r_xbot;
1517 lbrect.r_ytop = lb->r.r_ybot;
1518 found = TRUE;
1519 }
1520 else if (((lb->r.r_xbot == lbrect.r_xtop) &&
1521 (lb->r.r_ybot == lbrect.r_ytop)))
1522 {
1523 if (lblast == NULL)
1524 extSpecialBounds[0] = lb->b_next;
1525 else
1526 lblast->b_next = lb->b_next;
1527 lb->b_next = lbend->b_next;
1528 lbend->b_next = lb;
1529 lbend = lb;
1530 lbrect.r_xtop = lb->r.r_xtop;
1531 lbrect.r_ytop = lb->r.r_ytop;
1532 found = TRUE;
1533 }
1534 else
1535 lblast = lb;
1536 }
1537 }
1538 }
1539 }
1540
1541 /*
1542 * ----------------------------------------------------------------------------
1543 *
1544 * extOutputParameters --
1545 *
1546 * Scan through the TransRegion in the supplied list, and collect a mask of
1547 * all transistor types used in the layout. Then for each transistor type,
1548 * find if it belongs to a "subcircuit" (including "rsubcircuit" and
1549 * "msubcircuit") definition. If it does, output a record containing the
1550 * list of parameter names used by that subcircuit.
1551 *
1552 * Results:
1553 * None.
1554 *
1555 * Side effects:
1556 * Possibly writes to outFile. The purpose of this scan is not to have
1557 * to write out shared parameter information for every individual device.
1558 * ----------------------------------------------------------------------------
1559 */
1560
1561 void
extOutputParameters(def,transList,outFile)1562 extOutputParameters(def, transList, outFile)
1563 CellDef *def; /* Cell being extracted */
1564 TransRegion *transList; /* Transistor regions built up in first pass */
1565 FILE *outFile; /* Output file */
1566 {
1567 ParamList *plist;
1568 TransRegion *reg;
1569 TileType t;
1570 TileTypeBitMask tmask;
1571 ExtDevice *devptr;
1572
1573 TTMaskZero(&tmask);
1574
1575 for (reg = transList; reg && !SigInterruptPending; reg = reg->treg_next)
1576 {
1577 TileType loctype = reg->treg_type;
1578
1579 if (loctype == TT_SPACE) continue; /* This has been disabled */
1580
1581 /* Watch for rare split reg->treg_type */
1582 if (loctype & TT_DIAGONAL)
1583 loctype = (reg->treg_type & TT_SIDE) ? ((reg->treg_type &
1584 TT_RIGHTMASK) >> 14) : (reg->treg_type & TT_LEFTMASK);
1585
1586 TTMaskSetType(&tmask, loctype);
1587 }
1588
1589 for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
1590 {
1591 if (TTMaskHasType(&tmask, t))
1592 {
1593 /* Note: If there are multiple variants of a device type, they */
1594 /* will all be listed even if they are not all present in the */
1595 /* design. */
1596
1597 for (devptr = ExtCurStyle->exts_device[t]; devptr; devptr = devptr->exts_next)
1598 {
1599 /* Do not output parameters for ignored devices */
1600 if (!strcmp(devptr->exts_deviceName, "Ignore")) continue;
1601
1602 plist = devptr->exts_deviceParams;
1603 if (plist != (ParamList *)NULL)
1604 {
1605 fprintf(outFile, "parameters %s", devptr->exts_deviceName);
1606 for (; plist != NULL; plist = plist->pl_next)
1607 {
1608 if (plist->pl_param[1] != '\0')
1609 {
1610 if (plist->pl_scale != 1.0)
1611 fprintf(outFile, " %c%c=%s*%g",
1612 plist->pl_param[0], plist->pl_param[1],
1613 plist->pl_name, plist->pl_scale);
1614 else
1615 fprintf(outFile, " %c%c=%s", plist->pl_param[0],
1616 plist->pl_param[1], plist->pl_name);
1617 }
1618 else
1619 {
1620 if (plist->pl_scale != 1.0)
1621 fprintf(outFile, " %c=%s*%g",
1622 plist->pl_param[0],
1623 plist->pl_name, plist->pl_scale);
1624 else
1625 fprintf(outFile, " %c=%s", plist->pl_param[0],
1626 plist->pl_name);
1627
1628 }
1629 }
1630 fprintf(outFile, "\n");
1631 }
1632 }
1633 }
1634 }
1635 }
1636
1637 /*
1638 * ----------------------------------------------------------------------------
1639 *
1640 * extOutputDevParams ---
1641 *
1642 * Write information to the output in the form of parameters
1643 * representing pre-defined aspects of the device geometry
1644 * that may be specified for any device.
1645 *
1646 * Results:
1647 * None.
1648 *
1649 * Side effects:
1650 * Writes non-terminated output to the file 'outFile'.
1651 *
1652 * ----------------------------------------------------------------------------
1653 */
1654
1655 void
extOutputDevParams(reg,devptr,outFile,length,width)1656 extOutputDevParams(reg, devptr, outFile, length, width)
1657 TransRegion *reg;
1658 ExtDevice *devptr;
1659 FILE *outFile;
1660 int length;
1661 int width;
1662 {
1663 ParamList *chkParam;
1664
1665 for (chkParam = devptr->exts_deviceParams; chkParam
1666 != NULL; chkParam = chkParam->pl_next)
1667 {
1668 switch(tolower(chkParam->pl_param[0]))
1669 {
1670 case 'a':
1671 if (chkParam->pl_param[1] == '\0' ||
1672 chkParam->pl_param[1] == '0')
1673 fprintf(outFile, " %c=%d", chkParam->pl_param[0],
1674 reg->treg_area);
1675 break;
1676 case 'p':
1677 if (chkParam->pl_param[1] == '\0' ||
1678 chkParam->pl_param[1] == '0')
1679 fprintf(outFile, " %c=%d", chkParam->pl_param[0],
1680 extTransRec.tr_perim);
1681 break;
1682 case 'l':
1683 fprintf(outFile, " %c=%d", chkParam->pl_param[0],
1684 length);
1685 break;
1686 case 'w':
1687 fprintf(outFile, " %c=%d", chkParam->pl_param[0],
1688 width);
1689 break;
1690 case 'c':
1691 fprintf(outFile, " %c=%g", chkParam->pl_param[0],
1692 (extTransRec.tr_devrec->exts_deviceGateCap
1693 * reg->treg_area) +
1694 (extTransRec.tr_devrec->exts_deviceSDCap
1695 * extTransRec.tr_perim));
1696 break;
1697 case 's':
1698 case 'x':
1699 case 'y':
1700 /* Do nothing; these values are standard output */
1701 break;
1702 default:
1703 fprintf(outFile, " %c=", chkParam->pl_param[0]);
1704 break;
1705 }
1706 }
1707 }
1708
1709 /*
1710 * ----------------------------------------------------------------------------
1711 *
1712 * extOutputDevices --
1713 *
1714 * For each TransRegion in the supplied list, corresponding to a single
1715 * transistor in the layout, compute and output:
1716 * - Its type
1717 * - Its area and perimeter OR length and width OR capacitance OR resistance
1718 * - Its substrate node
1719 * - For each of the gate, and the various diff terminals (eg,
1720 * source, drain):
1721 * Node to which the terminal connects
1722 * Length of the terminal
1723 * Attributes (comma-separated), or 0 if none.
1724 *
1725 * The tiles in 'def' don't point back to the TransRegions in this list,
1726 * but rather to the NodeRegions corresponding to their electrical nodes.
1727 *
1728 * Results:
1729 * None.
1730 *
1731 * Side effects:
1732 * Writes a number of 'device' records to the file 'outFile'.
1733 *
1734 * Interruptible. If SigInterruptPending is detected, we stop traversing
1735 * the transistor list and return.
1736 *
1737 * ----------------------------------------------------------------------------
1738 */
1739
1740 void
extOutputDevices(def,transList,outFile)1741 extOutputDevices(def, transList, outFile)
1742 CellDef *def; /* Cell being extracted */
1743 TransRegion *transList; /* Transistor regions built up in first pass */
1744 FILE *outFile; /* Output file */
1745 {
1746 NodeRegion *node, *subsNode;
1747 TransRegion *reg;
1748 ExtDevice *devptr, *deventry;
1749 char *subsName;
1750 FindRegion arg;
1751 LabelList *ll;
1752 TileType t;
1753 int nsd, length, width, n, i, ntiles, corners, tn, rc, termcount;
1754 double dres, dcap;
1755 char mesg[256];
1756 bool isAnnular, hasModel;
1757
1758 for (reg = transList; reg && !SigInterruptPending; reg = reg->treg_next)
1759 {
1760 if (reg->treg_type == TT_SPACE) continue; /* This has been disabled */
1761
1762 /*
1763 * Visit all of the tiles in the transistor region, updating
1764 * extTransRec.tr_termnode[] and extTransRec.tr_termlen[],
1765 * and the attribute lists for this transistor.
1766 *
1767 * Algorithm: first visit all tiles in the transistor, marking
1768 * them with 'reg', then visit them again re-marking them with
1769 * the gate node (extGetRegion(reg->treg_tile)).
1770 */
1771 extTransRec.tr_devrec = (ExtDevice *)NULL;
1772 extTransRec.tr_devmatch = 0;
1773 extTransRec.tr_nterm = 0;
1774 extTransRec.tr_gatelen = 0;
1775 extTransRec.tr_perim = 0;
1776 extTransRec.tr_subsnode = (NodeRegion *)NULL;
1777
1778 arg.fra_def = def;
1779 arg.fra_connectsTo = ExtCurStyle->exts_deviceConn;
1780
1781 extTransRec.tr_gatenode = (NodeRegion *) extGetRegion(reg->treg_tile);
1782 t = reg->treg_type;
1783
1784 /* Watch for rare split reg->treg_type */
1785 if (t & TT_DIAGONAL)
1786 t = (reg->treg_type & TT_SIDE) ? ((reg->treg_type &
1787 TT_RIGHTMASK) >> 14) : (reg->treg_type & TT_LEFTMASK);
1788
1789 arg.fra_pNum = DBPlane(t);
1790
1791 /* Set all terminals to NULL to guard against */
1792 /* asymmetric devices missing a terminal. */
1793 /* 5/30/09---but, reinitialize the array out to MAXSD, */
1794 /* or devices declaring minterms < maxterms screw up! */
1795
1796 for (i = 0; i < MAXSD; i++) extTransRec.tr_termnode[i] = NULL;
1797
1798 /* Mark with reg and process each perimeter segment */
1799 arg.fra_uninit = (ClientData) extTransRec.tr_gatenode;
1800 arg.fra_region = (Region *) reg;
1801 arg.fra_each = extTransTileFunc;
1802 ntiles = ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg);
1803
1804 /* Re-mark with extTransRec.tr_gatenode */
1805 arg.fra_uninit = (ClientData) reg;
1806 arg.fra_region = (Region *) extTransRec.tr_gatenode;
1807 arg.fra_each = (int (*)()) NULL;
1808 (void) ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg);
1809
1810 /* Are the terminal types on a compeletely different */
1811 /* plane than the top type? If so, do an area search */
1812 /* on that plane in the area under the device node. */
1813
1814 /* Devices may define one terminal per plane, but this */
1815 /* method cannot handle several different layer types */
1816 /* on one plane under the device identifier layer */
1817 /* acting as separate device nodes. If any terminal */
1818 /* search fails, give up and proceed with the reduced */
1819 /* number of terminals. */
1820
1821 devptr = extTransRec.tr_devrec;
1822 if (devptr == NULL) continue; /* Bad device; do not output */
1823 deventry = devptr;
1824
1825 /* Use devmatch flags to determine if the specific S/D */
1826 /* terminal was handled by extTransPerimFunc already. */
1827 /* Only look at required S/D terminals that have not */
1828 /* yet been found. */
1829
1830 while (TRUE)
1831 {
1832 if (devptr == NULL) break; /* Bad device */
1833 nsd = devptr->exts_deviceSDCount;
1834 for (termcount = 0; termcount < nsd; termcount++)
1835 {
1836 TileTypeBitMask *tmask;
1837
1838 if ((extTransRec.tr_devmatch & (MATCH_TERM << termcount)) != 0)
1839 continue; /* This terminal already found by perimeter search */
1840
1841 tmask = &devptr->exts_deviceSDTypes[termcount];
1842 if (TTMaskIsZero(tmask)) {
1843 if (termcount < nsd) {
1844 ExtDevice *devcheck;
1845
1846 /* Not finding another device record just means that */
1847 /* terminals are tied together on the same net, such as */
1848 /* with a MOS cap. Accept this fact and move on. */
1849 }
1850 break; /* End of SD terminals */
1851 }
1852 else if (!TTMaskIntersect(tmask, &DBPlaneTypes[reg->treg_pnum])
1853 || (TTMaskHasType(tmask, TT_SPACE)))
1854 {
1855 node = NULL;
1856
1857 /* First try to find a region under the device */
1858 extTransFindSubs(reg->treg_tile, t, tmask, def, &node, NULL);
1859
1860 if ((node == NULL) && (TTMaskHasType(tmask, TT_SPACE))) {
1861 /* Device node is the global substrate. */
1862 node = glob_subsnode;
1863 }
1864 else if (node == NULL) {
1865 /* See if there is another matching device record */
1866 /* with a different terminal type, and try again. */
1867 devptr = extDevFindMatch(devptr, t);
1868 break;
1869 }
1870 extTransRec.tr_devmatch |= (MATCH_TERM << termcount);
1871 extTransRec.tr_termnode[termcount] = node;
1872 }
1873 else {
1874 /* Determine if there is another matching device record */
1875 /* that has fewer required terminals. */
1876 devptr = extDevFindMatch(devptr, t);
1877 break;
1878 }
1879 if (termcount == nsd) break; /* All terminals accounted for */
1880 }
1881 if (termcount == nsd) break; /* All terminals accounted for */
1882 if (devptr == deventry) break; /* No other device records available */
1883 /* Try again with a different device record */
1884 }
1885 extTransRec.tr_nterm = termcount;
1886
1887 /*
1888 * For types that require a minimum number of terminals,
1889 * check to make sure that they all exist. If they don't,
1890 * issue a warning message and make believe the missing
1891 * terminals are the same as the last terminal we do have.
1892 */
1893 if (extTransRec.tr_nterm < nsd)
1894 {
1895 int missing = nsd - extTransRec.tr_nterm;
1896
1897 (void) sprintf(mesg, "device missing %d terminal%s", missing,
1898 missing == 1 ? "" : "s");
1899 if (extTransRec.tr_nterm > 0)
1900 {
1901 node = extTransRec.tr_termnode[extTransRec.tr_nterm - 1];
1902 (void) strcat(mesg, ";\n connecting remainder to node ");
1903 (void) strcat(mesg, extNodeName((LabRegion *) node));
1904 while (extTransRec.tr_nterm < nsd)
1905 {
1906 extTransRec.tr_termlen[extTransRec.tr_nterm] = 0;
1907 extTransRec.tr_termnode[extTransRec.tr_nterm++] = node;
1908 }
1909 }
1910 if (ExtDoWarn & EXTWARN_FETS)
1911 extTransBad(def, reg->treg_tile, mesg);
1912
1913 /* Devices with no terminals or a null node are badly */
1914 /* formed and should not be output. This can happen when */
1915 /* parts of devices are split into different cells. */
1916
1917 if ((extTransRec.tr_nterm == 0) || (node == NULL))
1918 continue;
1919 }
1920 else if (extTransRec.tr_nterm > nsd)
1921 {
1922 /* It is not an error condition to have more terminals */
1923 /* than the minimum. */
1924 }
1925 if (devptr == NULL) {
1926 TxError("Warning: No matching extraction type for device at (%d %d)\n",
1927 reg->treg_tile->ti_ll.p_x, reg->treg_tile->ti_ll.p_y);
1928 continue;
1929 }
1930
1931 /*
1932 * Output the transistor record.
1933 * The type is devptr->exts_deviceName, which should have
1934 * some meaning to the simulator we are producing this file for.
1935 * Use the default substrate node unless the transistor overlaps
1936 * material whose type is in exts_deviceSubstrateTypes, in which
1937 * case we use the node of the overlapped material.
1938 *
1939 * Technology files using the "substrate" keyword (magic-8.1 or
1940 * newer) should have the text "error" in the substrate node
1941 * name.
1942 */
1943 subsName = devptr->exts_deviceSubstrateName;
1944 if (!TTMaskIsZero(&devptr->exts_deviceSubstrateTypes)
1945 && (subsNode = extTransRec.tr_subsnode))
1946 {
1947 subsName = extNodeName(subsNode);
1948 }
1949
1950 #ifdef MAGIC_WRAPPER
1951
1952 // Substrate variable substitution when in backwards-compatibility
1953 // substrate mode.
1954
1955 else if ((ExtCurStyle->exts_globSubstratePlane == -1) &&
1956 (subsName && subsName[0] == '$' && subsName[1] != '$'))
1957 {
1958 // If subsName is a Tcl variable (begins with "$"), make the
1959 // variable substitution, if one exists. Ignore double-$.
1960
1961 char *varsub = (char *)Tcl_GetVar(magicinterp, &subsName[1],
1962 TCL_GLOBAL_ONLY);
1963 if (varsub != NULL) subsName = varsub;
1964 }
1965 #endif
1966 extTransRec.tr_devrec = devptr;
1967
1968 /* Model type "Ignore" in the techfile indicates a device */
1969 /* to be ignored (i.e., a specific combination of layers */
1970 /* does not form an extractable device, or overlaps another */
1971 /* device type that should take precedence). */
1972
1973 if (!strcmp(devptr->exts_deviceName, "Ignore"))
1974 continue;
1975
1976 /* Original-style FET record backward compatibility */
1977 if (devptr->exts_deviceClass != DEV_FET)
1978 fprintf(outFile, "device ");
1979
1980 fprintf(outFile, "%s %s",
1981 extDevTable[devptr->exts_deviceClass],
1982 devptr->exts_deviceName);
1983
1984 fprintf(outFile, " %d %d %d %d",
1985 reg->treg_ll.p_x, reg->treg_ll.p_y,
1986 reg->treg_ll.p_x + 1, reg->treg_ll.p_y + 1);
1987
1988 /* NOTE: The following code makes unreasonable simplifying */
1989 /* assumptions about how to calculate device length and width. */
1990 /* However, it is the same as was always used by ext2sim and */
1991 /* ext2spice. By putting it here, where all the tile */
1992 /* information exists, it is at least theoretically possible to */
1993 /* write better routines that can deal with bends in resistors */
1994 /* and transistors, annular devices, multiple-drain devices, */
1995 /* etc., etc. */
1996 /* Tim, 2/20/03 */
1997
1998 switch (devptr->exts_deviceClass)
1999 {
2000 case DEV_FET: /* old style, perimeter & area */
2001 fprintf(outFile, " %d %d \"%s\"",
2002 reg->treg_area, extTransRec.tr_perim,
2003 (subsName == NULL) ? "None" : subsName);
2004 break;
2005
2006 /* "device <class>" types, calculation of length & width */
2007
2008 case DEV_MOSFET:
2009 case DEV_BJT:
2010 case DEV_SUBCKT:
2011 case DEV_MSUBCKT:
2012 case DEV_ASYMMETRIC:
2013 length = extTransRec.tr_gatelen / 2; /* (default) */
2014 width = 0;
2015 isAnnular = FALSE;
2016
2017 /* Note that width is accumulated on one tr_termlen */
2018 /* record when nodes are merged, so proper behavior */
2019 /* for transistors w/connected S-D is to count over */
2020 /* non-NULL termnodes, not non-zero termlens. */
2021
2022 for (n = 0; n < extTransRec.tr_nterm; n++)
2023 {
2024 if (extTransRec.tr_termnode[n] == NULL) continue;
2025
2026 width += extTransRec.tr_termlen[n];
2027
2028 /* Mark annular transistors as requiring extra processing */
2029 if (extTransRec.tr_termvector[n].p_x == 0 &&
2030 extTransRec.tr_termvector[n].p_y == 0)
2031 isAnnular = TRUE;
2032 }
2033 if (n) width /= n;
2034
2035 /*------------------------------------------------------*/
2036 /* Note that the tr_termvector says a lot about the */
2037 /* device geometry. If the sum of x and y for any */
2038 /* vector is 0, then the terminal is enclosed (annular */
2039 /* device). If the sum of x and y for all vectors is */
2040 /* zero, then we have a normal rectangular device. But */
2041 /* if the sum of all x and y is nonzero, then the */
2042 /* device length changes along the device (including */
2043 /* bends). This is a trigger to do a more extensive */
2044 /* boundary search to find the exact dimensions of the */
2045 /* device. */
2046 /*------------------------------------------------------*/
2047
2048 if (n == 0)
2049 {
2050 /* Don't issue a warning on devices such as a */
2051 /* vertical diode that may declare zero terminals */
2052 /* because the default substrate node is the other */
2053 /* terminal. */
2054
2055 if (ExtDoWarn && (devptr->exts_deviceSDCount > 0))
2056 extTransBad(def, reg->treg_tile,
2057 "Could not determine device boundary");
2058 length = width = 0;
2059 }
2060 else
2061 {
2062 LinkedBoundary *lb;
2063
2064 extSpecialBounds = (LinkedBoundary **)mallocMagic(n *
2065 sizeof(LinkedBoundary *));
2066
2067 for (i = 0; i < n; i++) extSpecialBounds[i] = NULL;
2068
2069 /* Mark with reg and process each perimeter segment */
2070
2071 arg.fra_uninit = (ClientData) extTransRec.tr_gatenode;
2072 arg.fra_region = (Region *) reg;
2073 arg.fra_each = extAnnularTileFunc;
2074
2075 (void) ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg);
2076
2077 extSeparateBounds(n - 1); /* Handle MOScaps (if necessary) */
2078 extComputeEffectiveLW(&length, &width, n,
2079 ExtCurStyle->exts_cornerChop[t]);
2080
2081 /* Free the lists */
2082
2083 for (i = 0; i < n; i++)
2084 for (lb = extSpecialBounds[i]; lb != NULL; lb = lb->b_next)
2085 freeMagic((char *)lb);
2086 freeMagic((char *)extSpecialBounds);
2087
2088 /* Put the region list back the way we found it: */
2089 /* Re-mark with extTransRec.tr_gatenode */
2090
2091 arg.fra_uninit = (ClientData) reg;
2092 arg.fra_region = (Region *) extTransRec.tr_gatenode;
2093 arg.fra_each = (int (*)()) NULL;
2094 (void) ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg);
2095
2096 }
2097
2098 if (devptr->exts_deviceClass == DEV_MOSFET ||
2099 devptr->exts_deviceClass == DEV_ASYMMETRIC ||
2100 devptr->exts_deviceClass == DEV_BJT)
2101 {
2102 fprintf(outFile, " %d %d", length, width);
2103 }
2104
2105 extOutputDevParams(reg, devptr, outFile, length, width);
2106
2107 fprintf(outFile, " \"%s\"", (subsName == NULL) ?
2108 "None" : subsName);
2109 break;
2110
2111 case DEV_DIODE: /* Only handle the optional substrate node */
2112 case DEV_NDIODE:
2113 case DEV_PDIODE:
2114 extOutputDevParams(reg, devptr, outFile, length, width);
2115 if (subsName != NULL)
2116 fprintf(outFile, " \"%s\"", subsName);
2117 break;
2118
2119 case DEV_RES:
2120 case DEV_RSUBCKT:
2121 hasModel = strcmp(devptr->exts_deviceName, "None");
2122 length = extTransRec.tr_perim;
2123 isAnnular = FALSE;
2124
2125 /* Boundary perimeter scan for resistors with more than */
2126 /* one tile. */
2127
2128 for (n = 0; n < extTransRec.tr_nterm; n++)
2129 {
2130 if (extTransRec.tr_termnode[n] == NULL) continue;
2131
2132 /* Mark annular resistors as requiring extra processing */
2133 if (extTransRec.tr_termvector[n].p_x == 0 &&
2134 extTransRec.tr_termvector[n].p_y == 0)
2135 isAnnular = TRUE;
2136 }
2137
2138 if (n == 0)
2139 width = length = 0;
2140 else if (ntiles > 1)
2141 {
2142 LinkedBoundary *lb;
2143
2144 extSpecialBounds = (LinkedBoundary **)mallocMagic(n *
2145 sizeof(LinkedBoundary *));
2146
2147 for (i = 0; i < n; i++) extSpecialBounds[i] = NULL;
2148
2149 /* Mark with reg and process each perimeter segment */
2150
2151 arg.fra_uninit = (ClientData) extTransRec.tr_gatenode;
2152 arg.fra_region = (Region *) reg;
2153 if (isAnnular)
2154 arg.fra_each = extAnnularTileFunc;
2155 else
2156 arg.fra_each = extResistorTileFunc;
2157 (void) ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg);
2158
2159 if (extSpecialBounds[0] != NULL)
2160 {
2161 extSeparateBounds(n - 1);
2162 if (isAnnular)
2163 extComputeEffectiveLW(&length, &width, n,
2164 ExtCurStyle->exts_cornerChop[t]);
2165 else
2166 extComputeEffectiveLW(&width, &length, n,
2167 ExtCurStyle->exts_cornerChop[t]);
2168 }
2169 else
2170 {
2171 if (ExtDoWarn)
2172 extTransBad(def, reg->treg_tile,
2173 "Could not determine resistor boundary");
2174 length = width = 0;
2175 }
2176
2177 /* Free the lists */
2178
2179 for (i = 0; i < n; i++)
2180 for (lb = extSpecialBounds[i]; lb != NULL; lb = lb->b_next)
2181 freeMagic((char *)lb);
2182 freeMagic((char *)extSpecialBounds);
2183
2184 /* Put the region list back the way we found it: */
2185 /* Re-mark with extTransRec.tr_gatenode */
2186
2187 arg.fra_uninit = (ClientData) reg;
2188 arg.fra_region = (Region *) extTransRec.tr_gatenode;
2189 arg.fra_each = (int (*)()) NULL;
2190 (void) ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg);
2191 }
2192 else
2193 {
2194 /* Single tile resistor means a simple L,W */
2195 /* calculation from perimeter & area. */
2196
2197 width = 0;
2198 for (n = 0; extTransRec.tr_termlen[n] != 0; n++)
2199 {
2200 width += extTransRec.tr_termlen[n];
2201 length -= extTransRec.tr_termlen[n];
2202 }
2203 width >>= 1;
2204 length >>= 1;
2205 }
2206 if (width)
2207 {
2208 dres = ExtCurStyle->exts_sheetResist[t] * (double)length /
2209 (double)width;
2210 if (ExtDoWarn && (n > 2))
2211 {
2212 if (hasModel)
2213 sprintf(mesg, "Resistor has %d terminals: "
2214 "extracted L/W will be wrong", n);
2215 else
2216 sprintf(mesg, "Resistor has %d terminals: "
2217 "extracted value will be wrong", n);
2218 extTransBad(def, reg->treg_tile, mesg);
2219 }
2220 }
2221 else {
2222 dres = 0.0;
2223 if (ExtDoWarn)
2224 extTransBad(def, reg->treg_tile,
2225 "Resistor has zero width");
2226 }
2227
2228 if (devptr->exts_deviceClass == DEV_RSUBCKT)
2229 {
2230 /* (Nothing) */
2231 }
2232 else if (hasModel) /* SPICE semiconductor resistor */
2233 {
2234 fprintf(outFile, " %d %d", length, width);
2235 if (subsName != NULL)
2236 fprintf(outFile, " \"%s\"", subsName);
2237 }
2238 else /* regular resistor */
2239 fprintf(outFile, " %g", dres / 1000.0); /* mOhms -> Ohms */
2240
2241 extOutputDevParams(reg, devptr, outFile, length, width);
2242
2243 if (devptr->exts_deviceClass == DEV_RSUBCKT)
2244 {
2245 fprintf(outFile, " \"%s\"", (subsName == NULL) ?
2246 "None" : subsName);
2247 }
2248 break;
2249
2250 case DEV_CAP:
2251 case DEV_CAPREV:
2252 case DEV_CSUBCKT:
2253 hasModel = strcmp(devptr->exts_deviceName, "None");
2254 if (hasModel)
2255 {
2256 for (n = 0; n < extTransRec.tr_nterm &&
2257 extTransRec.tr_termnode[n] != NULL; n++);
2258
2259 /* Don't know what to do (yet) with capacitors */
2260 /* multiple terminals (see below); treat them in */
2261 /* the original naive manner. */
2262
2263 if (n == 0)
2264 {
2265 width = 0;
2266 extTransBad(def, reg->treg_tile,
2267 "Capacitor has zero size");
2268 fprintf(outFile, " 0 0");
2269 }
2270 else
2271 {
2272 /* Special handling of multiple-tile areas. */
2273 /* This algorithm assumes that the capacitor */
2274 /* has one terminal and that the area is a */
2275 /* rectangle. It should be extended to output */
2276 /* multiple capacitors for multiple rectangular */
2277 /* areas, combining to form any arbitrary shape */
2278
2279 LinkedBoundary *lb;
2280
2281 extSpecialBounds = (LinkedBoundary **)mallocMagic(n *
2282 sizeof(LinkedBoundary *));
2283
2284 for (i = 0; i < n; i++) extSpecialBounds[i] = NULL;
2285
2286 /* Mark with reg and process each perimeter segment */
2287
2288 arg.fra_uninit = (ClientData) extTransRec.tr_gatenode;
2289 arg.fra_region = (Region *) reg;
2290 arg.fra_each = extAnnularTileFunc;
2291 (void) ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg);
2292
2293 extComputeCapLW(&length, &width);
2294
2295 /* Free the lists */
2296
2297 for (i = 0; i < n; i++)
2298 for (lb = extSpecialBounds[i]; lb != NULL; lb = lb->b_next)
2299 freeMagic((char *)lb);
2300 freeMagic((char *)extSpecialBounds);
2301
2302 /* Put the region list back the way we found it: */
2303 /* Re-mark with extTransRec.tr_gatenode */
2304
2305 arg.fra_uninit = (ClientData) reg;
2306 arg.fra_region = (Region *) extTransRec.tr_gatenode;
2307 arg.fra_each = (int (*)()) NULL;
2308 (void) ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg);
2309 }
2310
2311 if (devptr->exts_deviceClass == DEV_CSUBCKT)
2312 {
2313 /* (Nothing) */
2314 }
2315 else /* SPICE semiconductor resistor */
2316 {
2317 if ((length * width) > reg->treg_area)
2318 {
2319 if (ExtDoWarn)
2320 extTransBad(def, reg->treg_tile, "L,W estimated "
2321 "for non-rectangular capacitor.");
2322 fprintf(outFile, " %d %d", width,
2323 reg->treg_area / width);
2324 }
2325 else
2326 fprintf(outFile, " %d %d", length, width);
2327 if (subsName != NULL)
2328 fprintf(outFile, " \"%s\"", subsName);
2329 }
2330
2331 extOutputDevParams(reg, devptr, outFile, length, width);
2332
2333 if (devptr->exts_deviceClass == DEV_CSUBCKT)
2334 {
2335 fprintf(outFile, " \"%s\"", (subsName == NULL) ?
2336 "None" : subsName);
2337 }
2338 }
2339 else
2340 {
2341 dcap = (devptr->exts_deviceGateCap * reg->treg_area) +
2342 (devptr->exts_deviceSDCap * extTransRec.tr_perim);
2343
2344 fprintf(outFile, " %g", dcap / 1000.0); /* aF -> fF */
2345 }
2346 break;
2347 }
2348
2349 /* gate */
2350 node = (NodeRegion *) extGetRegion(reg->treg_tile);
2351 ll = node->nreg_labels;
2352 extTransOutTerminal((LabRegion *) node, ll, LL_GATEATTR,
2353 extTransRec.tr_gatelen, outFile);
2354
2355 /* Sort source and drain terminals by position, unless the */
2356 /* device is asymmetric, in which case source and drain do not */
2357 /* permute, and the terminal order is fixed. */
2358
2359 if (TTMaskIsZero(&devptr->exts_deviceSDTypes[1]))
2360 ExtSortTerminals(&extTransRec, ll);
2361
2362 /* each non-gate terminal */
2363 for (nsd = 0; nsd < extTransRec.tr_nterm; nsd++)
2364 extTransOutTerminal((LabRegion *) extTransRec.tr_termnode[nsd], ll,
2365 nsd, extTransRec.tr_termlen[nsd], outFile);
2366
2367 (void) fputs("\n", outFile);
2368 }
2369 }
2370
2371 /* Structure to hold a node region and a tile type */
2372
2373 typedef struct _node_type {
2374 NodeRegion *region;
2375 TileType layer;
2376 } NodeAndType;
2377
2378 int
extTransFindSubs(tile,t,mask,def,sn,layerptr)2379 extTransFindSubs(tile, t, mask, def, sn, layerptr)
2380 Tile *tile;
2381 TileType t;
2382 TileTypeBitMask *mask;
2383 CellDef *def;
2384 NodeRegion **sn;
2385 TileType *layerptr;
2386 {
2387 Rect tileArea, tileAreaPlus;
2388 int pNum;
2389 int extTransFindSubsFunc1(); /* Forward declaration */
2390 NodeAndType noderec;
2391
2392 noderec.region = (NodeRegion *)NULL;
2393 noderec.layer = TT_SPACE;
2394
2395 TiToRect(tile, &tileArea);
2396
2397 /* Expand tile area by 1 in all directions. This catches terminals */
2398 /* on certain extended drain MOSFET devices. */
2399 GEO_EXPAND(&tileArea, 1, &tileAreaPlus);
2400
2401 for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
2402 {
2403 if (TTMaskIntersect(&DBPlaneTypes[pNum], mask))
2404 {
2405 if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum], &tileAreaPlus,
2406 mask, extTransFindSubsFunc1, (ClientData)&noderec))
2407 {
2408 *sn = noderec.region;
2409 if (layerptr) *layerptr = noderec.layer;
2410 return 1;
2411 }
2412 }
2413 }
2414 return 0;
2415 }
2416
2417 int
extTransFindSubsFunc1(tile,noderecptr)2418 extTransFindSubsFunc1(tile, noderecptr)
2419 Tile *tile;
2420 NodeAndType *noderecptr;
2421 {
2422 TileType type;
2423
2424 /* Report split substrate region errors (two different substrate
2425 * regions under the same device)
2426 */
2427
2428 if (tile->ti_client != (ClientData) extUnInit)
2429 {
2430 if ((noderecptr->region != (NodeRegion *)NULL) &&
2431 (noderecptr->region != tile->ti_client))
2432 TxError("Warning: Split substrate under device at (%d %d)\n",
2433 tile->ti_ll.p_x, tile->ti_ll.p_y);
2434 if (IsSplit(tile))
2435 type = (SplitSide(tile)) ? SplitRightType(tile): SplitLeftType(tile);
2436 else
2437 type = TiGetTypeExact(tile);
2438
2439 noderecptr->region = (NodeRegion *)tile->ti_client;
2440 noderecptr->layer = type;
2441 return 1;
2442 }
2443 return 0;
2444 }
2445
2446 int
extTransFindId(tile,mask,def,idtypeptr)2447 extTransFindId(tile, mask, def, idtypeptr)
2448 Tile *tile;
2449 TileTypeBitMask *mask;
2450 CellDef *def;
2451 TileType *idtypeptr;
2452 {
2453 TileType type;
2454 Rect tileArea;
2455 int pNum;
2456 int extTransFindIdFunc1(); /* Forward declaration */
2457
2458 TiToRect(tile, &tileArea);
2459 for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
2460 {
2461 if (TTMaskIntersect(&DBPlaneTypes[pNum], mask))
2462 {
2463 if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum], &tileArea,
2464 mask, extTransFindIdFunc1, (ClientData)idtypeptr))
2465 return 1;
2466 }
2467 }
2468 return 0;
2469 }
2470
2471 int
extTransFindIdFunc1(tile,idtypeptr)2472 extTransFindIdFunc1(tile, idtypeptr)
2473 Tile *tile;
2474 TileType *idtypeptr;
2475 {
2476 /*
2477 * ID Layer found overlapping device area, so return 1 to halt search.
2478 */
2479 if (IsSplit(tile))
2480 *idtypeptr = (SplitSide(tile)) ? SplitRightType(tile): SplitLeftType(tile);
2481 else
2482 *idtypeptr = TiGetTypeExact(tile);
2483
2484 return 1;
2485 }
2486
2487 /*
2488 * ----------------------------------------------------------------------------
2489 *
2490 * extDevFindMatch --
2491 *
2492 * Find and return the next matching device record. extTransRec is queried
2493 * to find how many fields have been matched to the device already. Then
2494 * it finds the next record with the same matching fields. Because records
2495 * are in no specific order, it will loop to the beginning of the records
2496 * after reaching the end. It is the responsibility of the calling routine to
2497 * determine if all matching devices have been tested.
2498 *
2499 * deventry is the record position to start the search.
2500 * t is the tile type of the device.
2501 * ----------------------------------------------------------------------------
2502 */
2503
2504 ExtDevice *
extDevFindMatch(deventry,t)2505 extDevFindMatch(deventry, t)
2506 ExtDevice *deventry;
2507 TileType t;
2508 {
2509 ExtDevice *devptr;
2510 int i, j, k, matchflags;
2511 bool match;
2512
2513 matchflags = extTransRec.tr_devmatch;
2514
2515 if (deventry->exts_next == NULL)
2516 devptr = ExtCurStyle->exts_device[t];
2517 else
2518 devptr = deventry->exts_next;
2519
2520 for (; devptr != deventry;
2521 devptr = (devptr->exts_next) ? devptr->exts_next :
2522 ExtCurStyle->exts_device[t])
2523 {
2524 if (matchflags == 0) break; /* Always return next entry */
2525
2526 if (matchflags & MATCH_ID) /* Must have the same identifier */
2527 if (!TTMaskEqual(&devptr->exts_deviceIdentifierTypes,
2528 &deventry->exts_deviceIdentifierTypes)) continue;
2529
2530 if (matchflags & MATCH_SUB) /* Must have the same substrate type */
2531 if (!TTMaskEqual(&devptr->exts_deviceSubstrateTypes,
2532 &deventry->exts_deviceSubstrateTypes)) continue;
2533
2534 j = MATCH_TERM;
2535 i = 0;
2536 match = True;
2537 for (k = 0; k < devptr->exts_deviceSDCount; k++)
2538 {
2539 if (extTransRec.tr_termnode[k] == NULL) break;
2540 if (matchflags & j) /* Must have the same terminal type */
2541 {
2542 if (TTMaskIsZero(&devptr->exts_deviceSDTypes[i]))
2543 {
2544 match = False;
2545 break;
2546 }
2547 if (!TTMaskEqual(&devptr->exts_deviceSDTypes[i],
2548 &deventry->exts_deviceSDTypes[i]))
2549 {
2550 match = False;
2551 break;
2552 }
2553 }
2554 j <<= 1;
2555
2556 /* NOTE: There are fewer exts_deviceSDTypes records than */
2557 /* terminals if all S/D terminals are the same type. In */
2558 /* that case k increments and j bit shifts but i remains */
2559 /* the same. */
2560 if (!TTMaskIsZero(&devptr->exts_deviceSDTypes[i + 1])) i++;
2561 }
2562 if (match) break;
2563 }
2564 return (devptr == deventry) ? NULL : devptr;
2565 }
2566
2567 /*
2568 * ----------------------------------------------------------------------------
2569 *
2570 * extTransTileFunc --
2571 *
2572 * Filter function called by ExtFindNeighbors for each tile in a
2573 * transistor. Responsible for collecting the nodes, lengths,
2574 * and attributes of all the terminals on this transistor.
2575 *
2576 * Results:
2577 * Returns 0 always.
2578 *
2579 * Side effects:
2580 * Fills in the transRec structure extTransRec.
2581 *
2582 * ----------------------------------------------------------------------------
2583 */
2584
2585 int
extTransTileFunc(tile,pNum,arg)2586 extTransTileFunc(tile, pNum, arg)
2587 Tile *tile;
2588 int pNum;
2589 FindRegion *arg;
2590 {
2591 TileTypeBitMask mask, cmask, *smask;
2592 TileType loctype, idlayer, sublayer;
2593 int perim, result;
2594 bool allow_globsubsnode;
2595 ExtDevice *devptr, *deventry, *devtest;
2596 NodeRegion *region;
2597
2598 LabelList *ll;
2599 Label *lab;
2600 Rect r;
2601
2602 for (ll = extTransRec.tr_gatenode->nreg_labels; ll; ll = ll->ll_next)
2603 {
2604 /* Skip if already marked */
2605 if (ll->ll_attr != LL_NOATTR) continue;
2606 lab = ll->ll_label;
2607 TITORECT(tile, &r);
2608 if (GEO_TOUCH(&r, &lab->lab_rect) &&
2609 extLabType(lab->lab_text, LABTYPE_GATEATTR))
2610 {
2611 ll->ll_attr = LL_GATEATTR;
2612 }
2613 }
2614 /*
2615 * Visit each segment of the perimeter of this tile that
2616 * that borders on something of a different type.
2617 */
2618 if (IsSplit(tile))
2619 {
2620 loctype = (SplitSide(tile)) ? SplitRightType(tile): SplitLeftType(tile);
2621 // return (0); /* Hack alert! We must properly handle diagonals! */
2622 }
2623 else
2624 loctype = TiGetTypeExact(tile);
2625
2626 mask = ExtCurStyle->exts_deviceConn[loctype];
2627 TTMaskCom(&mask);
2628
2629 /* NOTE: DO NOT USE extTransRec.tr_perim += extEnumTilePerim(...) */
2630 /* The AMD target gcc compile works and the Intel target gcc */
2631 /* compile doesn't! The following code works the same on both. */
2632
2633 perim = extEnumTilePerim(tile, mask, pNum,
2634 extTransPerimFunc, (ClientData)NULL);
2635 extTransRec.tr_perim += perim;
2636
2637 devptr = extTransRec.tr_devrec;
2638 if (devptr == NULL) return 0; /* No matching devices, so forget it. */
2639
2640 allow_globsubsnode = FALSE;
2641
2642 /* Create a mask of all substrate types of all device records, and */
2643 /* search for substrate types on this combined mask. */
2644
2645 TTMaskZero(&cmask);
2646 for (devtest = ExtCurStyle->exts_device[loctype]; devtest;
2647 devtest = devtest->exts_next)
2648 TTMaskSetMask(&cmask, &devtest->exts_deviceSubstrateTypes);
2649
2650 if (!TTMaskIsZero(&cmask))
2651 {
2652 if (TTMaskHasType(&cmask, TT_SPACE))
2653 {
2654 allow_globsubsnode = TRUE;
2655 TTMaskClearType(&cmask, TT_SPACE);
2656 }
2657
2658 if (extTransRec.tr_subsnode == (NodeRegion *)NULL)
2659 {
2660 sublayer = TT_SPACE;
2661 region = NULL;
2662 extTransFindSubs(tile, loctype, &cmask, arg->fra_def, ®ion, &sublayer);
2663
2664 /* If the device does not connect to a defined node, and
2665 * the substrate types include "space", then it is assumed to
2666 * connect to the global substrate.
2667 */
2668
2669 if (region == (NodeRegion *)NULL)
2670 if (allow_globsubsnode)
2671 region = glob_subsnode;
2672
2673 extTransRec.tr_subsnode = region;
2674
2675 if ((region != (NodeRegion *)NULL) &&
2676 !(TTMaskHasType(&devptr->exts_deviceSubstrateTypes, sublayer)))
2677 {
2678 /* A substrate layer was found but is not compatible with the */
2679 /* current device. Find a device record with the substrate */
2680 /* layer that was found, and set the substrate match flag. */
2681
2682 deventry = devptr;
2683 while (devptr != NULL)
2684 {
2685 devptr = extDevFindMatch(devptr, loctype);
2686 if ((devptr == NULL) || (devptr == deventry))
2687 {
2688 TxError("No matching device for %s with substrate layer %s\n",
2689 DBTypeLongNameTbl[loctype], DBTypeLongNameTbl[sublayer]);
2690 devptr = NULL;
2691 break;
2692 }
2693 if (TTMaskHasType(&devptr->exts_deviceSubstrateTypes, sublayer))
2694 {
2695 extTransRec.tr_devmatch |= MATCH_SUB;
2696 break;
2697 }
2698 }
2699 }
2700 else if (region == (NodeRegion *)NULL)
2701 {
2702 /* If ExtCurStyle->exts_globSubstrateTypes contains no types */
2703 /* then this is an older style techfile without a "substrate" */
2704 /* definition in the extract section. In that case, it is */
2705 /* expected that the substrate name in the device line will be */
2706 /* used. */
2707
2708 if (!TTMaskIsZero(&ExtCurStyle->exts_globSubstrateTypes) ||
2709 (devptr->exts_deviceSubstrateName == NULL))
2710 {
2711 TxError("Device %s does not have a compatible substrate node!\n",
2712 DBTypeLongNameTbl[loctype]);
2713 devptr = NULL;
2714 }
2715 }
2716 }
2717 extTransRec.tr_devrec = devptr;
2718 if (devptr == NULL) return 0; /* No matching devices, so forget it. */
2719 }
2720
2721 /* If at least one device type declares an ID layer, then make a */
2722 /* mask of all device ID types, and search on the area of the */
2723 /* device to see if any device identifier layers are found. */
2724
2725 TTMaskZero(&cmask);
2726 for (devtest = ExtCurStyle->exts_device[loctype]; devtest;
2727 devtest = devtest->exts_next)
2728 TTMaskSetMask(&cmask, &devtest->exts_deviceIdentifierTypes);
2729
2730 if (!TTMaskIsZero(&cmask))
2731 {
2732 idlayer = TT_SPACE;
2733 extTransFindId(tile, &cmask, arg->fra_def, &idlayer);
2734
2735 if ((idlayer == TT_SPACE) && !TTMaskIsZero(&devptr->exts_deviceIdentifierTypes))
2736 {
2737 /* Device expected an ID layer but none was present. Find a device */
2738 /* record with no ID layer, and set the ID match flag. */
2739
2740 deventry = devptr;
2741 while (devptr != NULL)
2742 {
2743 devptr = extDevFindMatch(devptr, loctype);
2744 if ((devptr == NULL) || (devptr == deventry))
2745 {
2746 TxError("No matching device for %s with no ID layer\n",
2747 DBTypeLongNameTbl[loctype]);
2748 devptr = NULL;
2749 break;
2750 }
2751 if (TTMaskIsZero(&devptr->exts_deviceIdentifierTypes))
2752 {
2753 extTransRec.tr_devmatch |= MATCH_ID;
2754 break;
2755 }
2756 }
2757 }
2758 else if ((idlayer != TT_SPACE) &&
2759 !TTMaskHasType(&devptr->exts_deviceIdentifierTypes, idlayer))
2760 {
2761 /* Device expected no ID layer but one was present. Find a device */
2762 /* record with the ID layer and set the ID match flag. If there is */
2763 /* a valid device without the ID layer, then ignore the ID layer */
2764 /* and flag a warning. */
2765
2766 deventry = devptr;
2767 while (devptr != NULL)
2768 {
2769 devptr = extDevFindMatch(devptr, loctype);
2770 if ((devptr == NULL) || (devptr == deventry))
2771 {
2772 TxError("ID layer %s on non-matching device %s was ignored.\n",
2773 DBTypeLongNameTbl[idlayer], DBTypeLongNameTbl[loctype]);
2774 devptr = deventry;
2775 break;
2776 }
2777 if (TTMaskHasType(&devptr->exts_deviceIdentifierTypes, idlayer))
2778 {
2779 extTransRec.tr_devmatch |= MATCH_ID;
2780 break;
2781 }
2782 }
2783 }
2784 else
2785 extTransRec.tr_devmatch |= MATCH_ID;
2786 }
2787 extTransRec.tr_devrec = devptr;
2788
2789 return 0;
2790 }
2791
2792 int
extTransPerimFunc(bp)2793 extTransPerimFunc(bp)
2794 Boundary *bp;
2795 {
2796 TileType tinside, toutside;
2797 Tile *tile;
2798 NodeRegion *diffNode = (NodeRegion *) extGetRegion(bp->b_outside);
2799 ExtDevice *devptr, *deventry;
2800 int i, len = BoundaryLength(bp);
2801 int thisterm;
2802 LabelList *ll;
2803 Label *lab;
2804 Rect r;
2805 bool SDterm = FALSE;
2806
2807 tile = bp->b_inside;
2808 if (IsSplit(tile))
2809 tinside = (SplitSide(tile)) ? SplitRightType(tile): SplitLeftType(tile);
2810 else
2811 tinside = TiGetTypeExact(bp->b_inside);
2812 tile = bp->b_outside;
2813 if (IsSplit(tile))
2814 toutside = (SplitSide(tile)) ? SplitRightType(tile): SplitLeftType(tile);
2815 else
2816 toutside = TiGetTypeExact(bp->b_outside);
2817
2818 if (extTransRec.tr_devrec != NULL)
2819 devptr = extTransRec.tr_devrec;
2820 else
2821 devptr = ExtCurStyle->exts_device[tinside];
2822
2823 deventry = devptr;
2824 while(devptr)
2825 {
2826 extTransRec.tr_devrec = devptr;
2827 for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++)
2828 {
2829 /* TT_SPACE is allowed, for declaring that a device terminal is */
2830 /* the substrate. However, it should not be in the plane of */
2831 /* the device identifier layer, so space tiles should never be */
2832 /* flagged during a device perimeter search. */
2833
2834 if (toutside == TT_SPACE) break;
2835
2836 if (TTMaskHasType(&devptr->exts_deviceSDTypes[i], toutside))
2837 {
2838 /*
2839 * It's a diffusion terminal (source or drain). See if the node is
2840 * already in our table; add it if it wasn't already there.
2841 * Asymmetric devices must have terminals in order.
2842 */
2843 if (TTMaskIsZero(&devptr->exts_deviceSDTypes[1]))
2844 {
2845 for (thisterm = 0; thisterm < extTransRec.tr_nterm; thisterm++)
2846 if (extTransRec.tr_termnode[thisterm] == diffNode)
2847 break;
2848 }
2849 else
2850 thisterm = i;
2851
2852 if (extTransRec.tr_termnode[thisterm] == NULL)
2853 {
2854 extTransRec.tr_nterm++;
2855 extTransRec.tr_termnode[thisterm] = diffNode;
2856 extTransRec.tr_termlen[thisterm] = 0;
2857 extTransRec.tr_termvector[thisterm].p_x = 0;
2858 extTransRec.tr_termvector[thisterm].p_y = 0;
2859 extTransRec.tr_termpos[thisterm].pnum = DBPlane(toutside);
2860 extTransRec.tr_termpos[thisterm].pt = bp->b_outside->ti_ll;
2861
2862 /* Find the total area of this terminal */
2863 }
2864 else if (extTransRec.tr_termnode[thisterm] == diffNode)
2865 {
2866 TermTilePos *pos = &(extTransRec.tr_termpos[thisterm]);
2867 Tile *otile = bp->b_outside;
2868
2869 /* update the region tile position */
2870
2871 if( DBPlane(TiGetType(otile)) < pos->pnum )
2872 {
2873 pos->pnum = DBPlane(TiGetType(otile));
2874 pos->pt = otile->ti_ll;
2875 }
2876 else if( DBPlane(TiGetType(otile)) == pos->pnum )
2877 {
2878 if( LEFT(otile) < pos->pt.p_x )
2879 pos->pt = otile->ti_ll;
2880 else if( LEFT(otile) == pos->pt.p_x &&
2881 BOTTOM(otile) < pos->pt.p_y )
2882 pos->pt.p_y = BOTTOM(otile);
2883 }
2884 }
2885 else
2886 {
2887 TxError("Error: Asymmetric device with multiple terminals!\n");
2888 break;
2889 }
2890
2891 /* Add the length to this terminal's perimeter */
2892 extTransRec.tr_termlen[thisterm] += len;
2893
2894 /* Update the boundary traversal vector */
2895 switch(bp->b_direction) {
2896 case BD_LEFT:
2897 extTransRec.tr_termvector[thisterm].p_y += len;
2898 break;
2899 case BD_TOP:
2900 extTransRec.tr_termvector[thisterm].p_x += len;
2901 break;
2902 case BD_RIGHT:
2903 extTransRec.tr_termvector[thisterm].p_y -= len;
2904 break;
2905 case BD_BOTTOM:
2906 extTransRec.tr_termvector[thisterm].p_x -= len;
2907 break;
2908 }
2909
2910 /*
2911 * Mark this attribute as belonging to this transistor
2912 * if it is either:
2913 * (1) a terminal attribute whose LL corner touches bp->b_segment,
2914 * or (2) a gate attribute that lies inside bp->b_inside.
2915 */
2916 for (ll = extTransRec.tr_gatenode->nreg_labels; ll; ll = ll->ll_next)
2917 {
2918 /* Skip if already marked */
2919 if (ll->ll_attr != LL_NOATTR)
2920 continue;
2921 lab = ll->ll_label;
2922 if (GEO_ENCLOSE(&lab->lab_rect.r_ll, &bp->b_segment)
2923 && extLabType(lab->lab_text, LABTYPE_TERMATTR))
2924 {
2925 ll->ll_attr = thisterm;
2926 }
2927 }
2928
2929 /* Check if number of terminals exceeds the number allowed in */
2930 /* this device record. If so, check if there is another device */
2931 /* record with a different number of terminals. */
2932
2933 extTransRec.tr_devmatch |= (MATCH_TERM << thisterm);
2934 if (thisterm >= devptr->exts_deviceSDCount)
2935 {
2936 devptr = extDevFindMatch(devptr, tinside);
2937
2938 /* Should this be an error instead of a warning? */
2939 /* Traditionally more terminals than defined was allowed */
2940 /* but not necessarily handled correctly by ext2spice. */
2941
2942 if (devptr == deventry)
2943 TxError("Warning: Device has more terminals than defined "
2944 "for type!\n");
2945 else
2946 extTransRec.tr_devrec = devptr;
2947 }
2948 SDterm = TRUE;
2949 break;
2950 }
2951 }
2952 if (toutside == TT_SPACE) break;
2953 if (SDterm) break;
2954 if (extConnectsTo(tinside, toutside, ExtCurStyle->exts_nodeConn))
2955 {
2956 /* Not in a terminal, but are in something that connects to gate */
2957 extTransRec.tr_gatelen += len;
2958 break;
2959 }
2960
2961 /* Did not find a matching terminal, so see if a different extraction */
2962 /* record matches the terminal type. */
2963
2964 devptr = extDevFindMatch(devptr, tinside);
2965 if (devptr == deventry) devptr = NULL;
2966 }
2967
2968 if (devptr == NULL)
2969 {
2970 /* Outside type is not a terminal, so return to the original */
2971 /* device record. NOTE: Should probably check if this device */
2972 /* type is a FET, as being here would indicate an error. */
2973 /* However, failure to find all terminals will be flagged as an */
2974 /* error elsewhere. */
2975
2976 extTransRec.tr_devrec = deventry;
2977 }
2978
2979 /*
2980 * Total perimeter (separate from terminals, for dcaps
2981 * that might not be surrounded by terminals on all sides).
2982 */
2983
2984 /* Don't double-count contact perimeters (added by Tim 1/9/07) */
2985 if ((!DBIsContact(toutside) && !DBIsContact(tinside)) ||
2986 (bp->b_plane == extTransRec.tr_gatenode->nreg_pnum))
2987 extTransRec.tr_perim += len;
2988
2989 return (0);
2990 }
2991
2992 /*
2993 * ----------------------------------------------------------------------------
2994 *
2995 * extAnnularTileFunc --
2996 *
2997 * Filter function called by ExtFindNeighbors for each tile in a
2998 * transistor. Responsible for doing an extensive boundary
2999 * survey to determine the length of the transistor.
3000 * This is basically a subset of the code in extTransTileFunc()
3001 * but passes a different function to extEnumTilePerim().
3002 *
3003 * Results:
3004 * Returns 0 always.
3005 *
3006 * Side effects:
3007 *
3008 * ----------------------------------------------------------------------------
3009 */
3010
3011 int
extAnnularTileFunc(tile,pNum)3012 extAnnularTileFunc(tile, pNum)
3013 Tile *tile;
3014 int pNum;
3015 {
3016 TileTypeBitMask mask;
3017 TileType loctype;
3018
3019 /*
3020 * Visit each segment of the perimeter of this tile that
3021 * that borders on something of a different type.
3022 */
3023 if (IsSplit(tile))
3024 {
3025 loctype = (SplitSide(tile)) ? SplitRightType(tile): SplitLeftType(tile);
3026 }
3027 else
3028 loctype = TiGetTypeExact(tile);
3029
3030 mask = ExtCurStyle->exts_deviceConn[loctype];
3031 TTMaskCom(&mask);
3032 extEnumTilePerim(tile, mask, pNum, extSpecialPerimFunc, (ClientData) TRUE);
3033 return (0);
3034 }
3035
3036 /*
3037 * ----------------------------------------------------------------------------
3038 *
3039 * extResistorTileFunc --
3040 *
3041 * Filter function called by ExtFindNeighbors for each tile in a
3042 * resistor. This is very similar to the extAnnularTileFunc
3043 * above, but it looks a boundaries with non-source/drain types
3044 * rather than the source/drain boundaries themselves. This is
3045 * correct for tracing the detailed perimeter of a device where
3046 * L > W.
3047 *
3048 * Ideally, one wants to call both of these functions to check
3049 * both the case of L > W and the case W > L, assuming that both
3050 * are legal resistor layouts.
3051 *
3052 * Results:
3053 * Returns 0 always.
3054 *
3055 * Side effects:
3056 *
3057 * ----------------------------------------------------------------------------
3058 */
3059
3060 int
extResistorTileFunc(tile,pNum)3061 extResistorTileFunc(tile, pNum)
3062 Tile *tile;
3063 int pNum;
3064 {
3065 TileTypeBitMask mask;
3066 TileType loctype;
3067 ExtDevice *devptr;
3068
3069 /*
3070 * Visit each segment of the perimeter of this tile that
3071 * that borders on something of a different type.
3072 */
3073 if (IsSplit(tile))
3074 {
3075 loctype = (SplitSide(tile)) ? SplitRightType(tile): SplitLeftType(tile);
3076 }
3077 else
3078 loctype = TiGetTypeExact(tile);
3079
3080 mask = ExtCurStyle->exts_deviceConn[loctype];
3081
3082 devptr = extTransRec.tr_devrec;
3083 if (devptr == NULL) devptr = ExtCurStyle->exts_device[loctype];
3084
3085 while (devptr)
3086 {
3087 TTMaskSetMask(&mask, &devptr->exts_deviceSDTypes[0]);
3088 TTMaskCom(&mask);
3089
3090 extEnumTilePerim(tile, mask, pNum, extSpecialPerimFunc, (ClientData)FALSE);
3091
3092 if (extSpecialBounds[0] != NULL) break;
3093 devptr = devptr->exts_next;
3094 }
3095 if (devptr != NULL) extTransRec.tr_devrec = devptr;
3096
3097 return (0);
3098 }
3099
3100 /*----------------------------------------------------------------------*/
3101 /* Detailed boundary survey for unusual transistor geometries (esp. */
3102 /* annular). If "sense" is TRUE, look at boundaries with source/drain */
3103 /* types. If "sense" is FALSE, looks at non-source/drain boundaries. */
3104 /*----------------------------------------------------------------------*/
3105
3106 int
extSpecialPerimFunc(bp,sense)3107 extSpecialPerimFunc(bp, sense)
3108 Boundary *bp;
3109 bool sense;
3110 {
3111 TileType tinside, toutside;
3112 NodeRegion *diffNode = (NodeRegion *) extGetRegion(bp->b_outside);
3113 int thisterm, extended, i;
3114 LinkedBoundary *newBound, *lb, *lastlb;
3115 ExtDevice *devptr;
3116 bool needSurvey;
3117
3118 /* Note that extEnumTilePerim() assumes for the non-Manhattan case */
3119 /* that non-Manhattan tiles should be incorporated into the device */
3120 /* gate for purposes of computing effective length and width. In */
3121 /* most cases this will be only a slight deviation from the true */
3122 /* result. */
3123
3124 switch (bp->b_direction)
3125 {
3126 case BD_TOP:
3127 tinside = TiGetTopType(bp->b_inside);
3128 toutside = TiGetBottomType(bp->b_outside);
3129 break;
3130 case BD_BOTTOM:
3131 tinside = TiGetBottomType(bp->b_inside);
3132 toutside = TiGetTopType(bp->b_outside);
3133 break;
3134 case BD_RIGHT:
3135 tinside = TiGetRightType(bp->b_inside);
3136 toutside = TiGetLeftType(bp->b_outside);
3137 break;
3138 case BD_LEFT:
3139 tinside = TiGetLeftType(bp->b_inside);
3140 toutside = TiGetRightType(bp->b_outside);
3141 break;
3142 }
3143
3144 /* Required to use the same device record that was used to find */
3145 /* the terminals. */
3146 if ((devptr = extTransRec.tr_devrec) == NULL) return 0;
3147
3148 /* Check all terminal classes for a matching type */
3149 needSurvey = FALSE;
3150 for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++)
3151 {
3152 if (TTMaskHasType(&devptr->exts_deviceSDTypes[i], toutside))
3153 {
3154 needSurvey = TRUE;
3155 break;
3156 }
3157 }
3158
3159 if (!sense || needSurvey)
3160 {
3161 if (toutside == TT_SPACE)
3162 if (glob_subsnode != NULL)
3163 diffNode = glob_subsnode;
3164 }
3165
3166 /* Check for terminal on different plane than the device */
3167 if (!needSurvey)
3168 {
3169 for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++)
3170 {
3171 TileTypeBitMask mmask;
3172 PlaneMask pmask;
3173
3174 mmask = devptr->exts_deviceSDTypes[i];
3175 if (toutside != TT_SPACE) TTMaskClearType(&mmask, TT_SPACE);
3176 pmask = DBTechTypesToPlanes(&mmask);
3177
3178 if (!PlaneMaskHasPlane(pmask, DBPlane(tinside)))
3179 {
3180 diffNode = extTransRec.tr_termnode[i];
3181 needSurvey = TRUE;
3182 break;
3183 }
3184 }
3185 }
3186
3187 if (!sense || needSurvey)
3188 {
3189 /*
3190 * Since we're repeating the search, all terminals should be there.
3191 */
3192 if (!sense)
3193 thisterm = 0;
3194 else
3195 {
3196 for (thisterm = 0; thisterm < extTransRec.tr_nterm; thisterm++)
3197 if (extTransRec.tr_termnode[thisterm] == diffNode)
3198 break;
3199 if (thisterm >= extTransRec.tr_nterm)
3200 {
3201 /* This is not necessarily an error; e.g., happens for */
3202 /* a device like a diode with TT_SPACE in the source/ */
3203 /* drain list. */
3204 return 1;
3205 }
3206 }
3207
3208 /*
3209 * Check the existing segment list to see if this segment
3210 * extends an existing segment.
3211 */
3212
3213 extended = 0;
3214 for (lb = extSpecialBounds[thisterm]; lb != NULL; lb = lb->b_next)
3215 {
3216 if (bp->b_direction == lb->dir)
3217 {
3218 switch(lb->dir)
3219 {
3220 case BD_LEFT:
3221 case BD_RIGHT:
3222 if (bp->b_segment.r_xbot == lb->r.r_xbot)
3223 {
3224 if (bp->b_segment.r_ybot == lb->r.r_ytop)
3225 {
3226 if (extended)
3227 lastlb->r.r_ybot = lb->r.r_ybot;
3228 else
3229 lb->r.r_ytop = bp->b_segment.r_ytop;
3230 extended++;
3231 lastlb = lb;
3232 }
3233 else if (bp->b_segment.r_ytop == lb->r.r_ybot)
3234 {
3235 if (extended)
3236 lastlb->r.r_ytop = lb->r.r_ytop;
3237 else
3238 lb->r.r_ybot = bp->b_segment.r_ybot;
3239 extended++;
3240 lastlb = lb;
3241 }
3242 }
3243 break;
3244 case BD_TOP:
3245 case BD_BOTTOM:
3246 if (bp->b_segment.r_ybot == lb->r.r_ybot)
3247 {
3248 if (bp->b_segment.r_xbot == lb->r.r_xtop)
3249 {
3250 if (extended)
3251 lastlb->r.r_xbot = lb->r.r_xbot;
3252 else
3253 lb->r.r_xtop = bp->b_segment.r_xtop;
3254 extended++;
3255 lastlb = lb;
3256 }
3257 else if (bp->b_segment.r_xtop == lb->r.r_xbot)
3258 {
3259 if (extended)
3260 lastlb->r.r_xtop = lb->r.r_xtop;
3261 else
3262 lb->r.r_xbot = bp->b_segment.r_xbot;
3263 extended++;
3264 lastlb = lb;
3265 }
3266 }
3267 break;
3268 }
3269 }
3270 if (extended == 2)
3271 {
3272 /* Connected two existing entries---need to remove lastlb, */
3273 /* which is now a redundant segment. */
3274
3275 if (lastlb == extSpecialBounds[thisterm])
3276 extSpecialBounds[thisterm] = lastlb->b_next;
3277 else
3278 {
3279 for (lb = extSpecialBounds[thisterm]; lb != NULL;
3280 lb = lb->b_next)
3281 {
3282 if (lastlb == lb->b_next)
3283 {
3284 lb->b_next = lastlb->b_next;
3285 break;
3286 }
3287 }
3288 }
3289 freeMagic((char *)lastlb);
3290
3291 /* New segment cannot extend more than two existing segments */
3292 break;
3293 }
3294 }
3295
3296 if (!extended)
3297 {
3298 newBound = (LinkedBoundary *)mallocMagic(sizeof(LinkedBoundary));
3299 newBound->r = bp->b_segment;
3300 newBound->dir = bp->b_direction;
3301 newBound->b_next = extSpecialBounds[thisterm];
3302 extSpecialBounds[thisterm] = newBound;
3303 }
3304 }
3305 return (0);
3306 }
3307
3308
3309 /*
3310 * ----------------------------------------------------------------------------
3311 *
3312 * extTransOutTerminal --
3313 *
3314 * Output the information associated with one terminal of a
3315 * transistor. This consists of three things:
3316 * - the name of the node to which the terminal is connected
3317 * - the length of the terminal along the perimeter of the transistor
3318 * - a list of attributes pertinent to this terminal.
3319 *
3320 * If 'whichTerm' is LL_GATEATTR, this is the gate; otherwise, it is one
3321 * of the diffusion terminals.
3322 *
3323 * Results:
3324 * None.
3325 *
3326 * Side effects:
3327 * Writes the above information to 'outFile'.
3328 * Resets ll_attr for each attribute we output to LL_NOATTR.
3329 *
3330 * ----------------------------------------------------------------------------
3331 */
3332
3333 void
extTransOutTerminal(lreg,ll,whichTerm,len,outFile)3334 extTransOutTerminal(lreg, ll, whichTerm, len, outFile)
3335 LabRegion *lreg; /* Node connected to terminal */
3336 LabelList *ll; /* Gate's label list */
3337 int whichTerm; /* Which terminal we are processing. The gate
3338 * is indicated by LL_GATEATTR.
3339 */
3340 int len; /* Length of perimeter along terminal */
3341 FILE *outFile; /* Output file */
3342 {
3343 char *cp;
3344 int n;
3345 char fmt;
3346
3347
3348 fprintf(outFile, " \"%s\" %d", extNodeName(lreg), len);
3349 for (fmt = ' '; ll; ll = ll->ll_next)
3350 if (ll->ll_attr == whichTerm)
3351 {
3352 fprintf(outFile, "%c\"", fmt);
3353 cp = ll->ll_label->lab_text;
3354 n = strlen(cp) - 1;
3355 while (n-- > 0)
3356 putc(*cp++, outFile);
3357 ll->ll_attr = LL_NOATTR;
3358 fprintf(outFile, "\"");
3359 fmt = ',';
3360 }
3361
3362 if (fmt == ' ')
3363 fprintf(outFile, " 0");
3364 }
3365
3366 /*
3367 * ----------------------------------------------------------------------------
3368 *
3369 * extTransBad --
3370 *
3371 * For a transistor where an error was encountered, give feedback
3372 * as to the location of the error.
3373 *
3374 * Results:
3375 * None.
3376 *
3377 * Side effects:
3378 * Complains to the user.
3379 *
3380 * ----------------------------------------------------------------------------
3381 */
3382
3383 void
extTransBad(def,tp,mesg)3384 extTransBad(def, tp, mesg)
3385 CellDef *def;
3386 Tile *tp;
3387 char *mesg;
3388 {
3389 Rect r;
3390
3391 if (!DebugIsSet(extDebugID, extDebNoFeedback))
3392 {
3393 TiToRect(tp, &r);
3394 DBWFeedbackAdd(&r, mesg, def, 1, STYLE_PALEHIGHLIGHTS);
3395 }
3396 extNumWarnings++;
3397 }
3398
3399 /*
3400 * ----------------------------------------------------------------------------
3401 *
3402 * extLabType --
3403 *
3404 * Check to see whether the text passed as an argument satisfies
3405 * any of the label types in 'typeMask'.
3406 *
3407 * Results:
3408 * TRUE if the text is of one of the label types in 'typeMask',
3409 * FALSE if not.
3410 *
3411 * Side effects:
3412 * None.
3413 *
3414 * ----------------------------------------------------------------------------
3415 */
3416
3417 bool
extLabType(text,typeMask)3418 extLabType(text, typeMask)
3419 char *text;
3420 int typeMask;
3421 {
3422 if (*text == '\0')
3423 return (FALSE);
3424
3425 while (*text) text++;
3426 switch (*--text)
3427 {
3428 case '@': /* Node attribute */
3429 return ((bool)(typeMask & LABTYPE_NODEATTR));
3430 case '$': /* Terminal (source/drain) attribute */
3431 return ((bool)(typeMask & LABTYPE_TERMATTR));
3432 case '^': /* Gate attribute */
3433 return ((bool)(typeMask & LABTYPE_GATEATTR));
3434 default:
3435 return ((bool)(typeMask & LABTYPE_NAME));
3436 }
3437 /*NOTREACHED*/
3438 }
3439
3440
3441 /*
3442 * ----------------------------------------------------------------------------
3443 * extNodeToTile --
3444 *
3445 * Sets tp to be the tile containing the lower-leftmost point of the
3446 * NodeRegion *np, but in the tile planes of the ExtTree *et instead
3447 * of the tile planes originally containing *np. This routine used
3448 * to be defined as the macro NODETOTILE().
3449 *
3450 * Results:
3451 * Returns a pointer to the tile
3452 *
3453 * Side effects:
3454 * None.
3455 * ----------------------------------------------------------------------------
3456 */
3457
extNodeToTile(np,et)3458 Tile *extNodeToTile(np, et)
3459 NodeRegion *np;
3460 ExtTree *et;
3461 {
3462 Tile *tp;
3463 Plane *myplane;
3464
3465 myplane = et->et_use->cu_def->cd_planes[np->nreg_pnum];
3466
3467 tp = myplane->pl_hint;
3468 GOTOPOINT(tp, &np->nreg_ll);
3469 myplane->pl_hint = tp;
3470
3471 if (IsSplit(tp))
3472 {
3473 TileType tpt = TiGetTypeExact(tp);
3474 if ((tpt & TT_LEFTMASK) == (np->nreg_type & TT_LEFTMASK))
3475 TiSetBody(tp, tpt & ~TT_SIDE);
3476 else
3477 TiSetBody(tp, tpt | TT_SIDE);
3478 }
3479
3480 return tp;
3481 }
3482
3483 /*
3484 * ----------------------------------------------------------------------------
3485 *
3486 * extSetNodeNum --
3487 *
3488 * Update reg->lreg_ll and reg->lreg_pnum so that they are always the
3489 * lowest leftmost coordinate in a cell, on the plane with the lowest
3490 * number (formerly a macro in extractInt.h).
3491 *
3492 * (10/1/05: Changed from a macro to a subroutine and modified for
3493 * handling non-Manhattan geometry)
3494 *
3495 * Results:
3496 * None.
3497 *
3498 * Side effects:
3499 * None.
3500 *
3501 * ----------------------------------------------------------------------------
3502 */
3503
3504 void
extSetNodeNum(reg,plane,tile)3505 extSetNodeNum(reg, plane, tile)
3506 LabRegion *reg;
3507 int plane;
3508 Tile *tile;
3509 {
3510 TileType type;
3511
3512 if (IsSplit(tile))
3513 {
3514 /* Only consider split tiles if the lower-left-hand corner */
3515 /* is only the type under consideration. */
3516
3517 if (!SplitSide(tile) && SplitDirection(tile))
3518 type = SplitSide(tile) ? SplitRightType(tile) : SplitLeftType(tile);
3519 else if (reg->lreg_pnum == DBNumPlanes)
3520 type = TiGetTypeExact(tile);
3521 else
3522 return;
3523 }
3524 else
3525 type = TiGetType(tile);
3526
3527 if ((plane < reg->lreg_pnum) || (reg->lreg_type & TT_DIAGONAL))
3528 {
3529 reg->lreg_type = type;
3530 reg->lreg_pnum = plane;
3531 reg->lreg_ll = tile->ti_ll;
3532 }
3533 else if (plane == reg->lreg_pnum)
3534 {
3535 if (LEFT(tile) < reg->lreg_ll.p_x)
3536 {
3537 reg->lreg_ll = tile->ti_ll;
3538 reg->lreg_type = type;
3539 }
3540 else if (LEFT(tile) == reg->lreg_ll.p_x
3541 && BOTTOM(tile) < reg->lreg_ll.p_y)
3542 {
3543 reg->lreg_ll.p_y = BOTTOM(tile);
3544 reg->lreg_type = type;
3545 }
3546 }
3547 }
3548
3549 /*
3550 * ----------------------------------------------------------------------------
3551 *
3552 * extTransFirst --
3553 * extTransEach --
3554 *
3555 * Filter functions passed to ExtFindRegions when tracing out transistor
3556 * regions as part of flat circuit extraction.
3557 *
3558 * Results:
3559 * extTransFirst returns a pointer to a new TransRegion.
3560 * extTransEach returns NULL.
3561 *
3562 * Side effects:
3563 * Memory is allocated by extTransFirst.
3564 * We cons the newly allocated region onto the front of the existing
3565 * region list.
3566 *
3567 * The area of each transistor is updated by extTransEach.
3568 *
3569 * ----------------------------------------------------------------------------
3570 */
3571
3572 Region *
extTransFirst(tile,arg)3573 extTransFirst(tile, arg)
3574 Tile *tile;
3575 FindRegion *arg;
3576 {
3577 TransRegion *reg;
3578
3579 reg = (TransRegion *) mallocMagic((unsigned) (sizeof (TransRegion)));
3580 reg->treg_next = (TransRegion *) NULL;
3581 reg->treg_labels = (LabelList *) NULL;
3582 reg->treg_area = 0;
3583 reg->treg_tile = tile;
3584 reg->treg_pnum = DBNumPlanes;
3585
3586 if (IsSplit(tile))
3587 reg->treg_type = SplitSide(tile) ? SplitRightType(tile) : SplitLeftType(tile);
3588 else
3589 reg->treg_type = TiGetTypeExact(tile);
3590
3591 /* Prepend it to the region list */
3592 reg->treg_next = (TransRegion *) arg->fra_region;
3593 arg->fra_region = (Region *) reg;
3594 return ((Region *) reg);
3595 }
3596
3597 /*ARGSUSED*/
3598 int
extTransEach(tile,pNum,arg)3599 extTransEach(tile, pNum, arg)
3600 Tile *tile;
3601 int pNum;
3602 FindRegion *arg;
3603 {
3604 TransRegion *reg = (TransRegion *) arg->fra_region;
3605 int area = TILEAREA(tile);
3606
3607 if (IsSplit(tile)) area /= 2; /* Split tiles are 1/2 area! */
3608 else if (IsSplit(reg->treg_tile))
3609 {
3610 /* Avoid setting the region's tile pointer to a split tile */
3611 reg->treg_tile = tile;
3612 reg->treg_type = TiGetTypeExact(tile);
3613 }
3614
3615 /* The following is non-ideal. It assumes that the lowest plane of */
3616 /* types connected to a device is the plane of the device itself. */
3617 /* Otherwise, the area of the device will be miscalculated. */
3618
3619 if (pNum < reg->treg_pnum) reg->treg_area = 0;
3620
3621 extSetNodeNum((LabRegion *) reg, pNum, tile);
3622
3623 if (pNum == reg->treg_pnum) reg->treg_area += area;
3624
3625 return (0);
3626 }
3627
3628 /*
3629 * ----------------------------------------------------------------------------
3630 *
3631 * extFindNodes --
3632 *
3633 * Build up, in the manner of ExtFindRegions, a list of all the
3634 * node regions in the CellDef 'def'. This procedure is heavily
3635 * optimized for speed.
3636 *
3637 * Results:
3638 * Returns a pointer to a NULL-terminated list of NodeRegions
3639 * that correspond to the nodes in the circuit. The label lists
3640 * for each node region have not yet been filled in.
3641 *
3642 * Side effects:
3643 * Memory is allocated.
3644 *
3645 * ----------------------------------------------------------------------------
3646 */
3647
3648 Stack *extNodeStack = NULL;
3649 Rect *extNodeClipArea = NULL;
3650
3651 NodeRegion *
extFindNodes(def,clipArea,subonly)3652 extFindNodes(def, clipArea, subonly)
3653 CellDef *def; /* Def whose nodes are being found */
3654 Rect *clipArea; /* If non-NULL, ignore perimeter and area that extend
3655 * outside this rectangle.
3656 */
3657 bool subonly; /* If true, only find the substrate node, and return */
3658 {
3659 int extNodeAreaFunc();
3660 int extSubsFunc();
3661 int extSubsFunc2();
3662 FindRegion arg;
3663 int pNum, n;
3664 TileTypeBitMask subsTypesNonSpace;
3665 bool space_is_substrate;
3666
3667 /* Reset perimeter and area prior to node extraction */
3668 for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
3669 extResistArea[n] = extResistPerim[n] = 0;
3670
3671 extNodeClipArea = clipArea;
3672 if (extNodeStack == (Stack *) NULL)
3673 extNodeStack = StackNew(64);
3674
3675 arg.fra_def = def;
3676 arg.fra_region = (Region *) NULL;
3677
3678 SigDisableInterrupts();
3679
3680 /* First pass: Find substrate. Collect all tiles belonging */
3681 /* to the substrate and push them onto the stack. Then */
3682 /* call extNodeAreaFunc() on the first of these to generate */
3683 /* a single substrate node. */
3684
3685 /* Refinement: Split search into two parts, one on the */
3686 /* globSubstratePlane and one on all other planes. ONLY */
3687 /* search other planes if TT_SPACE is in the list of */
3688 /* substrate types, and then only consider those types to */
3689 /* be part of the substrate node if they have only space */
3690 /* below them on the globSubstratePlane. This method lets */
3691 /* a single type like "psd" operate on, for example, both */
3692 /* the substrate and an isolated pwell, without implicitly */
3693 /* connecting the isolated pwell to the substrate. */
3694
3695 temp_subsnode = (NodeRegion *)NULL; // Reset for new search
3696
3697 if (TTMaskHasType(&ExtCurStyle->exts_globSubstrateTypes, TT_SPACE))
3698 space_is_substrate = True;
3699 else
3700 space_is_substrate = False;
3701
3702 TTMaskZero(&subsTypesNonSpace);
3703 TTMaskSetMask(&subsTypesNonSpace, &ExtCurStyle->exts_globSubstrateTypes);
3704 TTMaskClearType(&subsTypesNonSpace, TT_SPACE);
3705
3706 pNum = ExtCurStyle->exts_globSubstratePlane;
3707 /* Does the type set of this plane intersect the substrate types? */
3708 if (TTMaskIntersect(&DBPlaneTypes[pNum], &subsTypesNonSpace))
3709 {
3710 arg.fra_pNum = pNum;
3711 DBSrPaintClient((Tile *) NULL, def->cd_planes[pNum],
3712 &TiPlaneRect, &subsTypesNonSpace, extUnInit,
3713 extSubsFunc, (ClientData) &arg);
3714 }
3715
3716 for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
3717 {
3718 if (pNum == ExtCurStyle->exts_globSubstratePlane) continue;
3719
3720 /* Does the type set of this plane intersect the substrate types? */
3721
3722 if (TTMaskIntersect(&DBPlaneTypes[pNum], &subsTypesNonSpace))
3723 {
3724 arg.fra_pNum = pNum;
3725 if (space_is_substrate)
3726 DBSrPaintClient((Tile *) NULL, def->cd_planes[pNum],
3727 &TiPlaneRect, &subsTypesNonSpace, extUnInit,
3728 extSubsFunc2, (ClientData) &arg);
3729 else
3730 DBSrPaintClient((Tile *) NULL, def->cd_planes[pNum],
3731 &TiPlaneRect, &subsTypesNonSpace, extUnInit,
3732 extSubsFunc, (ClientData) &arg);
3733 }
3734 }
3735
3736 /* If there was a substrate connection, process it and everything */
3737 /* that was connected to it. If not, then create a new node */
3738 /* to represent the substrate. */
3739
3740 if (!StackEmpty(extNodeStack))
3741 {
3742 Tile *tile;
3743 int tilePlaneNum;
3744
3745 POPTILE(tile, tilePlaneNum);
3746 arg.fra_pNum = tilePlaneNum;
3747 extNodeAreaFunc(tile, &arg);
3748 temp_subsnode = (NodeRegion *)arg.fra_region;
3749 }
3750 else if (ExtCurStyle->exts_globSubstratePlane != -1)
3751 {
3752 NodeRegion *loc_subsnode;
3753
3754 extNodeAreaFunc((Tile *)NULL, (FindRegion *)&arg);
3755 loc_subsnode = (NodeRegion *)arg.fra_region;
3756 loc_subsnode->nreg_pnum = ExtCurStyle->exts_globSubstratePlane;
3757 loc_subsnode->nreg_type = TT_SPACE;
3758 loc_subsnode->nreg_ll.p_x = MINFINITY + 3;
3759 loc_subsnode->nreg_ll.p_y = MINFINITY + 3;
3760 loc_subsnode->nreg_labels = NULL;
3761 temp_subsnode = loc_subsnode;
3762 }
3763 if (subonly == TRUE) return ((NodeRegion *) arg.fra_region);
3764
3765 /* Second pass: Find all other nodes */
3766
3767 for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
3768 {
3769 arg.fra_pNum = pNum;
3770 (void) DBSrPaintClient((Tile *) NULL, def->cd_planes[pNum],
3771 &TiPlaneRect, &ExtCurStyle->exts_activeTypes,
3772 extUnInit, extNodeAreaFunc, (ClientData) &arg);
3773 }
3774 SigEnableInterrupts();
3775
3776 /* Compute resistance for last node */
3777 if (arg.fra_region && (ExtOptions & EXT_DORESISTANCE))
3778 extSetResist((NodeRegion *) arg.fra_region);
3779
3780 return ((NodeRegion *) arg.fra_region);
3781 }
3782
3783 int
extSubsFunc(tile,arg)3784 extSubsFunc(tile, arg)
3785 Tile *tile;
3786 FindRegion *arg;
3787 {
3788 int pNum;
3789 Rect tileArea;
3790 TileType type;
3791 TileTypeBitMask *smask;
3792 int extSubsFunc3();
3793
3794 if (IsSplit(tile))
3795 {
3796 type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
3797 if (type == TT_SPACE) return 0; /* Should not happen */
3798 }
3799
3800 /* Run second search in the area of the tile on the substrate plane */
3801 /* to make sure that no shield types are covering this tile. */
3802
3803 TiToRect(tile, &tileArea);
3804 smask = &ExtCurStyle->exts_globSubstrateShieldTypes;
3805 for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
3806 if (TTMaskIntersect(&DBPlaneTypes[pNum], smask))
3807 if (DBSrPaintArea((Tile *) NULL, arg->fra_def->cd_planes[pNum],
3808 &tileArea, smask, extSubsFunc3, (ClientData)NULL) != 0)
3809 return (0);
3810
3811 /* Mark this tile as pending and push it */
3812 PUSHTILE(tile, arg->fra_pNum);
3813
3814 /* That's all we do */
3815 return (0);
3816 }
3817
3818 int
extSubsFunc2(tile,arg)3819 extSubsFunc2(tile, arg)
3820 Tile *tile;
3821 FindRegion *arg;
3822 {
3823 int pNum;
3824 Rect tileArea;
3825 TileTypeBitMask *smask;
3826 int extSubsFunc3();
3827
3828 TiToRect(tile, &tileArea);
3829
3830 /* Run second search in the area of the tile on the substrate plane */
3831 /* to make sure that no shield types are covering this tile. */
3832
3833 smask = &ExtCurStyle->exts_globSubstrateShieldTypes;
3834 for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
3835 if (TTMaskIntersect(&DBPlaneTypes[pNum], smask))
3836 if (DBSrPaintArea((Tile *) NULL, arg->fra_def->cd_planes[pNum],
3837 &tileArea, smask, extSubsFunc3, (ClientData)NULL) != 0)
3838 /* Keep the search going, as there may be other tiles to check */
3839 return (0);
3840
3841 /* Run third search in the area of the tile on the substrate plane */
3842 /* to make sure that nothing but space is under these tiles. */
3843
3844 pNum = ExtCurStyle->exts_globSubstratePlane;
3845
3846 if (DBSrPaintArea((Tile *) NULL, arg->fra_def->cd_planes[pNum],
3847 &tileArea, &DBAllButSpaceBits,
3848 extSubsFunc3, (ClientData)NULL) == 0)
3849 {
3850 /* Mark this tile as pending and push it */
3851 PUSHTILE(tile, arg->fra_pNum);
3852 }
3853 return (0);
3854 }
3855
3856 int
extSubsFunc3(tile)3857 extSubsFunc3(tile)
3858 Tile *tile;
3859 {
3860 /* Stops the search because something that was not space was found */
3861 return 1;
3862 }
3863
3864 int
extNodeAreaFunc(tile,arg)3865 extNodeAreaFunc(tile, arg)
3866 Tile *tile;
3867 FindRegion *arg;
3868 {
3869 int tilePlaneNum, pNum, len, resistClass, n, nclasses;
3870 dlong area;
3871 PlaneMask pMask;
3872 CapValue capval;
3873 TileTypeBitMask *mask, *resMask;
3874 NodeRegion *reg;
3875 Tile *tp;
3876 TileType type, t, residue, tres;
3877 NodeRegion *old;
3878 Rect r;
3879 PlaneAndArea pla;
3880
3881 if (tile && IsSplit(tile))
3882 {
3883 type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
3884 if (type == TT_SPACE) return 0; /* Should not happen */
3885 }
3886
3887 /* Compute the resistance for the previous region */
3888 if (old = (NodeRegion *) arg->fra_region)
3889 if (ExtOptions & EXT_DORESISTANCE)
3890 extSetResist(old);
3891
3892 /* Allocate a new node */
3893 nclasses = ExtCurStyle->exts_numResistClasses;
3894 n = sizeof (NodeRegion) + (sizeof (PerimArea) * (nclasses - 1));
3895 reg = (NodeRegion *) mallocMagic((unsigned) n);
3896 reg->nreg_labels = (LabelList *) NULL;
3897 reg->nreg_cap = (CapValue) 0;
3898 reg->nreg_resist = 0;
3899 reg->nreg_pnum = DBNumPlanes;
3900 reg->nreg_next = (NodeRegion *) NULL;
3901 for (n = 0; n < nclasses; n++)
3902 reg->nreg_pa[n].pa_perim = reg->nreg_pa[n].pa_area = 0;
3903
3904 /* Prepend the new node to the region list */
3905 reg->nreg_next = (NodeRegion *) arg->fra_region;
3906 arg->fra_region = (Region *) reg;
3907
3908 /* Used by substrate generating routine */
3909 if (tile == NULL) return 1;
3910
3911 /* Mark this tile as pending and push it */
3912 PUSHTILE(tile, arg->fra_pNum);
3913
3914 /* Continue processing tiles until there are none left */
3915 while (!StackEmpty(extNodeStack))
3916 {
3917 POPTILE(tile, tilePlaneNum);
3918
3919 /*
3920 * Since tile was pushed on the stack, we know that it
3921 * belongs to this region. Check to see that it hasn't
3922 * been visited in the meantime. If it's still unvisited,
3923 * visit it and process its neighbors.
3924 */
3925 if (tile->ti_client == (ClientData) reg)
3926 continue;
3927 tile->ti_client = (ClientData) reg;
3928 if (DebugIsSet(extDebugID, extDebNeighbor))
3929 extShowTile(tile, "neighbor", 1);
3930
3931 if (IsSplit(tile))
3932 {
3933 type = (SplitSide(tile)) ? SplitRightType(tile):
3934 SplitLeftType(tile);
3935 }
3936 else
3937 type = TiGetTypeExact(tile);
3938
3939 /* Contacts are replaced by their residues when calculating */
3940 /* area/perimeter capacitance and resistance. */
3941
3942 residue = (DBIsContact(type)) ?
3943 DBPlaneToResidue(type, tilePlaneNum) : type;
3944
3945 mask = &ExtCurStyle->exts_nodeConn[type];
3946 resMask = &ExtCurStyle->exts_typesResistChanged[residue];
3947 resistClass = ExtCurStyle->exts_typeToResistClass[residue];
3948
3949 /*
3950 * Make sure the lower-leftmost point in the node is
3951 * kept up to date, so we can generate an internal
3952 * node name that does not depend on any other nodes
3953 * in this cell.
3954 */
3955 extSetNodeNum((LabRegion *) reg, tilePlaneNum, tile);
3956
3957 /*
3958 * Keep track of the total area of this node, and the
3959 * contribution to parasitic ground capacitance resulting
3960 * from area.
3961 */
3962 if (extNodeClipArea)
3963 {
3964 TITORECT(tile, &r);
3965 GEOCLIP(&r, extNodeClipArea);
3966 area = (dlong)(r.r_xtop - r.r_xbot) * (dlong)(r.r_ytop - r.r_ybot);
3967 }
3968 else area = (dlong)(TOP(tile) - BOTTOM(tile)) * (dlong)(RIGHT(tile) - LEFT(tile));
3969
3970 if (IsSplit(tile)) area /= 2; /* Split tiles are 1/2 area! */
3971
3972 if (resistClass != -1)
3973 extResistArea[resistClass] += area;
3974 reg->nreg_cap += area * ExtCurStyle->exts_areaCap[residue];
3975
3976 /* Compute perimeter of nonManhattan edges */
3977 if (IsSplit(tile))
3978 {
3979 len = ((RIGHT(tile) - LEFT(tile)) * (RIGHT(tile) - LEFT(tile))) +
3980 ((TOP(tile) - BOTTOM(tile)) * (TOP(tile) - BOTTOM(tile)));
3981 len = (int)sqrt((double)len);
3982
3983 if (extNodeClipArea)
3984 {
3985 /* To-do: Find perimeter length of clipped edge */
3986 }
3987
3988 /* Find the type on the other side of the tile */
3989 t = (SplitSide(tile)) ? SplitLeftType(tile):
3990 SplitRightType(tile);
3991 tres = (DBIsContact(t)) ? DBPlaneToResidue(t, tilePlaneNum) : t;
3992 if ((capval = ExtCurStyle->exts_perimCap[residue][tres]) != (CapValue) 0)
3993 reg->nreg_cap += capval * len;
3994 if (TTMaskHasType(resMask, tres) && resistClass != -1)
3995 extResistPerim[resistClass] += len;
3996 }
3997
3998 /*
3999 * Walk along all four sides of tile.
4000 * Sum perimeter capacitance as we go.
4001 * Keep track of the contribution to the total perimeter
4002 * of this node, for computing resistance.
4003 */
4004
4005 /* Top */
4006 topside:
4007
4008 if (IsSplit(tile) && (SplitSide(tile) ^ SplitDirection(tile))) goto leftside;
4009
4010 for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
4011 {
4012 if (extNodeClipArea)
4013 {
4014 r.r_ybot = r.r_ytop = TOP(tile);
4015 r.r_xtop = MIN(RIGHT(tile), RIGHT(tp));
4016 r.r_xbot = MAX(LEFT(tile), LEFT(tp));
4017 GEOCLIP(&r, extNodeClipArea);
4018 len = EDGENULL(&r) ? 0 : r.r_xtop - r.r_xbot;
4019 }
4020 else len = MIN(RIGHT(tile), RIGHT(tp)) - MAX(LEFT(tile), LEFT(tp));
4021 if (IsSplit(tp))
4022 {
4023 t = SplitBottomType(tp);
4024 if (tp->ti_client == extUnInit && TTMaskHasType(mask, t))
4025 {
4026 PUSHTILEBOTTOM(tp, tilePlaneNum);
4027 }
4028 else if (tp->ti_client != (ClientData)reg && TTMaskHasType(mask, t))
4029 {
4030 /* Count split tile twice, once for each node it belongs to. */
4031 tp->ti_client = extUnInit;
4032 PUSHTILEBOTTOM(tp, tilePlaneNum);
4033 }
4034 }
4035 else
4036 {
4037 t = TiGetTypeExact(tp);
4038 if (tp->ti_client == extUnInit && TTMaskHasType(mask, t))
4039 {
4040 PUSHTILE(tp, tilePlaneNum);
4041 }
4042 }
4043 tres = (DBIsContact(t)) ? DBPlaneToResidue(t, tilePlaneNum) : t;
4044 if ((capval = ExtCurStyle->exts_perimCap[residue][tres]) != (CapValue) 0)
4045 reg->nreg_cap += capval * len;
4046 if (TTMaskHasType(resMask, tres) && resistClass != -1)
4047 extResistPerim[resistClass] += len;
4048 }
4049
4050 /* Left */
4051 leftside:
4052
4053 if (IsSplit(tile) && SplitSide(tile)) goto bottomside;
4054
4055 for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
4056 {
4057 if (extNodeClipArea)
4058 {
4059 r.r_xbot = r.r_xtop = LEFT(tile);
4060 r.r_ytop = MIN(TOP(tile), TOP(tp));
4061 r.r_ybot = MAX(BOTTOM(tile), BOTTOM(tp));
4062 GEOCLIP(&r, extNodeClipArea);
4063 len = EDGENULL(&r) ? 0 : r.r_ytop - r.r_ybot;
4064 }
4065 else len = MIN(TOP(tile), TOP(tp)) - MAX(BOTTOM(tile), BOTTOM(tp));
4066 if (IsSplit(tp))
4067 {
4068 t = SplitRightType(tp);
4069 if (tp->ti_client == extUnInit && TTMaskHasType(mask, t))
4070 {
4071 PUSHTILERIGHT(tp, tilePlaneNum);
4072 }
4073 else if (tp->ti_client != (ClientData)reg && TTMaskHasType(mask, t))
4074 {
4075 /* Count split tile twice, once for each node it belongs to. */
4076 tp->ti_client = extUnInit;
4077 PUSHTILERIGHT(tp, tilePlaneNum);
4078 }
4079 }
4080 else
4081 {
4082 t = TiGetTypeExact(tp);
4083 if (tp->ti_client == extUnInit && TTMaskHasType(mask, t))
4084 {
4085 PUSHTILE(tp, tilePlaneNum);
4086 }
4087 }
4088 tres = (DBIsContact(t)) ? DBPlaneToResidue(t, tilePlaneNum) : t;
4089 if ((capval = ExtCurStyle->exts_perimCap[residue][tres]) != (CapValue) 0)
4090 reg->nreg_cap += capval * len;
4091 if (TTMaskHasType(resMask, tres) && resistClass != -1)
4092 extResistPerim[resistClass] += len;
4093 }
4094
4095 /* Bottom */
4096 bottomside:
4097
4098 if (IsSplit(tile) && (!(SplitSide(tile) ^ SplitDirection(tile))))
4099 goto rightside;
4100
4101 for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
4102 {
4103 if (extNodeClipArea)
4104 {
4105 r.r_ybot = r.r_ytop = BOTTOM(tile);
4106 r.r_xtop = MIN(RIGHT(tile), RIGHT(tp));
4107 r.r_xbot = MAX(LEFT(tile), LEFT(tp));
4108 GEOCLIP(&r, extNodeClipArea);
4109 len = EDGENULL(&r) ? 0 : r.r_xtop - r.r_xbot;
4110 }
4111 else len = MIN(RIGHT(tile), RIGHT(tp)) - MAX(LEFT(tile), LEFT(tp));
4112 if (IsSplit(tp))
4113 {
4114 t = SplitTopType(tp);
4115 if (tp->ti_client == extUnInit && TTMaskHasType(mask, t))
4116 {
4117 PUSHTILETOP(tp, tilePlaneNum);
4118 }
4119 else if (tp->ti_client != (ClientData)reg && TTMaskHasType(mask, t))
4120 {
4121 /* Count split tile twice, once for each node it belongs to. */
4122 tp->ti_client = extUnInit;
4123 PUSHTILETOP(tp, tilePlaneNum);
4124 }
4125 }
4126 else
4127 {
4128 t = TiGetTypeExact(tp);
4129 if (tp->ti_client == extUnInit && TTMaskHasType(mask, t))
4130 {
4131 PUSHTILE(tp, tilePlaneNum);
4132 }
4133 }
4134 tres = (DBIsContact(t)) ? DBPlaneToResidue(t, tilePlaneNum) : t;
4135 if ((capval = ExtCurStyle->exts_perimCap[residue][tres]) != (CapValue) 0)
4136 reg->nreg_cap += capval * len;
4137 if (TTMaskHasType(resMask, tres) && resistClass != -1)
4138 extResistPerim[resistClass] += len;
4139 }
4140
4141 /* Right */
4142 rightside:
4143
4144 if (IsSplit(tile) && !SplitSide(tile)) goto donesides;
4145
4146 for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
4147 {
4148 if (extNodeClipArea)
4149 {
4150 r.r_xbot = r.r_xtop = RIGHT(tile);
4151 r.r_ytop = MIN(TOP(tile), TOP(tp));
4152 r.r_ybot = MAX(BOTTOM(tile), BOTTOM(tp));
4153 GEOCLIP(&r, extNodeClipArea);
4154 len = EDGENULL(&r) ? 0 : r.r_ytop - r.r_ybot;
4155 }
4156 else len = MIN(TOP(tile), TOP(tp)) - MAX(BOTTOM(tile), BOTTOM(tp));
4157 if (IsSplit(tp))
4158 {
4159 t = SplitLeftType(tp);
4160 if (tp->ti_client == extUnInit && TTMaskHasType(mask, t))
4161 {
4162 PUSHTILELEFT(tp, tilePlaneNum);
4163 }
4164 else if (tp->ti_client != (ClientData)reg && TTMaskHasType(mask, t))
4165 {
4166 /* Count split tile twice, once for each node it belongs to */
4167 tp->ti_client = extUnInit;
4168 PUSHTILELEFT(tp, tilePlaneNum);
4169 }
4170 }
4171 else
4172 {
4173 t = TiGetTypeExact(tp);
4174 if (tp->ti_client == extUnInit && TTMaskHasType(mask, t))
4175 {
4176 PUSHTILE(tp, tilePlaneNum);
4177 }
4178 }
4179 tres = (DBIsContact(t)) ? DBPlaneToResidue(t, tilePlaneNum) : t;
4180 if ((capval = ExtCurStyle->exts_perimCap[residue][tres]) != (CapValue) 0)
4181 reg->nreg_cap += capval * len;
4182 if (TTMaskHasType(resMask, tres) && resistClass != -1)
4183 extResistPerim[resistClass] += len;
4184 }
4185
4186 donesides:
4187 /* No capacitance */
4188 if ((ExtOptions & EXT_DOCAPACITANCE) == 0)
4189 reg->nreg_cap = (CapValue) 0;
4190
4191 /* If this is a contact, visit all the other planes */
4192 if (DBIsContact(type))
4193 {
4194 pMask = DBConnPlanes[type];
4195 pMask &= ~(PlaneNumToMaskBit(tilePlaneNum));
4196 for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
4197 if (PlaneMaskHasPlane(pMask, pNum))
4198 {
4199 Plane *plane = arg->fra_def->cd_planes[pNum];
4200
4201 tp = plane->pl_hint;
4202 GOTOPOINT(tp, &tile->ti_ll);
4203 plane->pl_hint = tp;
4204
4205 if (tp->ti_client != extUnInit) continue;
4206
4207 /* tp and tile should have the same geometry for a contact */
4208 if (IsSplit(tile) && IsSplit(tp))
4209 {
4210 if (SplitSide(tile))
4211 {
4212 t = SplitRightType(tp);
4213 if (TTMaskHasType(mask, t))
4214 {
4215 PUSHTILERIGHT(tp, pNum);
4216 }
4217 }
4218 else
4219 {
4220 t = SplitLeftType(tp);
4221 if (TTMaskHasType(mask, t))
4222 {
4223 PUSHTILELEFT(tp, pNum);
4224 }
4225 }
4226 }
4227 else if (IsSplit(tp))
4228 {
4229 /* Need to test both sides of the tile */
4230 t = SplitRightType(tp);
4231 if (TTMaskHasType(mask, t))
4232 {
4233 PUSHTILERIGHT(tp, pNum);
4234 }
4235 t = SplitLeftType(tp);
4236 if (TTMaskHasType(mask, t))
4237 {
4238 PUSHTILELEFT(tp, pNum);
4239 }
4240 }
4241 else
4242 {
4243 t = TiGetTypeExact(tp);
4244 if (TTMaskHasType(mask, t))
4245 {
4246 PUSHTILE(tp, pNum);
4247 }
4248 }
4249 }
4250 }
4251
4252 /*
4253 * The hairiest case is when this type connects to stuff on
4254 * other planes, but isn't itself connected as a contact.
4255 * For example, a CMOS pwell connects to diffusion of the
4256 * same doping (p substrate diff). In a case like this,
4257 * we need to search the entire AREA of the tile plus a
4258 * 1-lambda halo to find everything it overlaps or touches
4259 * on the other plane.
4260 */
4261 if (pMask = DBAllConnPlanes[type])
4262 {
4263 Rect biggerArea;
4264 bool is_split = IsSplit(tile);
4265
4266 extNbrUn = extUnInit;
4267 TITORECT(tile, &pla.area);
4268 GEO_EXPAND(&pla.area, 1, &biggerArea);
4269 for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
4270 if ((pNum != tilePlaneNum) && PlaneMaskHasPlane(pMask, pNum))
4271 {
4272 pla.plane = pNum;
4273 if (is_split)
4274 DBSrPaintNMArea((Tile *) NULL,
4275 arg->fra_def->cd_planes[pNum],
4276 TiGetTypeExact(tile) &
4277 (TT_DIAGONAL | TT_SIDE | TT_DIRECTION),
4278 &biggerArea, mask, extNbrPushFunc,
4279 (ClientData) &pla);
4280 else
4281 DBSrPaintArea((Tile *) NULL,
4282 arg->fra_def->cd_planes[pNum], &biggerArea,
4283 mask, extNbrPushFunc, (ClientData) &pla);
4284 }
4285 }
4286 }
4287
4288 return (0);
4289 }
4290
4291 /*
4292 * ----------------------------------------------------------------------------
4293 *
4294 * extGetCapValue --
4295 * extSetCapValue --
4296 *
4297 * Procedures to get/set a value from our capacitance tables.
4298 *
4299 * ----------------------------------------------------------------------------
4300 */
4301
4302 void
extSetCapValue(he,value)4303 extSetCapValue(he, value)
4304 HashEntry *he;
4305 CapValue value;
4306 {
4307 if (HashGetValue(he) == NULL)
4308 HashSetValue(he, (CapValue *) mallocMagic(sizeof(CapValue)));
4309 *( (CapValue *) HashGetValue(he)) = value;
4310 }
4311
4312 CapValue
extGetCapValue(he)4313 extGetCapValue(he)
4314 HashEntry *he;
4315 {
4316 if (HashGetValue(he) == NULL)
4317 extSetCapValue(he, (CapValue) 0);
4318 return *( (CapValue *) HashGetValue(he));
4319 }
4320
4321 /*
4322 * ----------------------------------------------------------------------------
4323 *
4324 * extCapHashKill --
4325 *
4326 * Kill off a coupling capacitance hash table.
4327 *
4328 * Results:
4329 * None.
4330 *
4331 * Side effects:
4332 * Frees up storage in the table.
4333 * ----------------------------------------------------------------------------
4334 */
4335
4336 void
extCapHashKill(ht)4337 extCapHashKill(ht)
4338 HashTable *ht;
4339 {
4340 HashSearch hs;
4341 HashEntry *he;
4342
4343 HashStartSearch(&hs);
4344 while (he = HashNext(ht, &hs))
4345 {
4346 if (HashGetValue(he) != NULL)
4347 {
4348 freeMagic(HashGetValue(he)); /* Free a malloc'ed CapValue */
4349 HashSetValue(he, (ClientData) NULL);
4350 }
4351 }
4352 HashKill(ht);
4353 }
4354