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, &region, &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