1 
2 #ifndef lint
3 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResBasic.c,v 1.3 2010/06/24 12:37:56 tim Exp $";
4 #endif  /* not lint */
5 
6 #include <stdio.h>
7 #include <string.h>
8 #include <ctype.h>
9 #include <math.h>
10 
11 #include "utils/magic.h"
12 #include "utils/geometry.h"
13 #include "utils/geofast.h"
14 #include "tiles/tile.h"
15 #include "utils/hash.h"
16 #include "database/database.h"
17 #include "utils/malloc.h"
18 #include "textio/textio.h"
19 #include "extract/extract.h"
20 #include "extract/extractInt.h"
21 #include "windows/windows.h"
22 #include "dbwind/dbwind.h"
23 #include "utils/tech.h"
24 #include "textio/txcommands.h"
25 #include "resis/resis.h"
26 
27 int resSubDevFunc();
28 
29 /*
30  *--------------------------------------------------------------------------
31  *
32  * resNodeIsPort --
33  *
34  *	If the given position is inside any port declared on the tile,
35  *	change the node name to the port name.  Remove the port
36  *	declaration if it was used.
37  *
38  *--------------------------------------------------------------------------
39  */
40 
41 void
resNodeIsPort(node,x,y,tile)42 resNodeIsPort(node, x, y, tile)
43     resNode *node;
44     int	    x;
45     int	    y;
46     Tile    *tile;
47 {
48     Rect 	*rect;
49     Point 	p;
50     resPort 	*pl, *lp;
51     tileJunk	*junk = (tileJunk *)(tile->ti_client);
52 
53     p.p_x = x;
54     p.p_y = y;
55 
56     for (pl = junk->portList; pl; pl = pl->rp_nextPort)
57     {
58 	rect = &(pl->rp_bbox);
59 	if (GEO_ENCLOSE(&p, rect))
60 	{
61 	    node->rn_name = pl->rp_nodename;
62 	    if (junk->portList == pl)
63 		junk->portList = pl->rp_nextPort;
64 	    else
65 	    {
66 	        for (lp = junk->portList; lp && (lp->rp_nextPort != pl);
67 			lp = lp->rp_nextPort);
68 		lp->rp_nextPort = pl->rp_nextPort;
69 	    }
70 	    freeMagic(pl);
71 	    break;
72 	}
73     }
74 }
75 
76 /*
77  *--------------------------------------------------------------------------
78  *
79  * resAllPortNodes --
80  *
81  *	Generate new nodes and breakpoints for every unused port declared
82  *	on a tile.
83  *
84  *--------------------------------------------------------------------------
85  */
86 
87 void
resAllPortNodes(tile,list)88 resAllPortNodes(tile, list)
89     Tile 	*tile;
90     resNode	**list;
91 {
92     int		x, y;
93     resNode	*resptr;
94     resPort 	*pl;
95     tileJunk	*junk = (tileJunk *)(tile->ti_client);
96 
97     for (pl = junk->portList; pl; pl = pl->rp_nextPort)
98     {
99 	x = pl->rp_loc.p_x;
100 	y = pl->rp_loc.p_y;
101 	resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
102 	InitializeNode(resptr, x, y, RES_NODE_ORIGIN);
103 	resptr->rn_status = TRUE;
104 	resptr->rn_noderes = 0;
105 	resptr->rn_name = pl->rp_nodename;
106 	ResAddToQueue(resptr, list);
107 	NEWBREAK(resptr, tile, x, y, NULL);
108 	freeMagic(pl);
109     }
110 }
111 
112 /*
113  *--------------------------------------------------------------------------
114  *
115  * ResMultiPlaneFunc---
116  *
117  *  If device is found overlapping one of its source/drain types, then
118  *  generate a new device at the center of the tile and add to ResNodeQueue.
119  *
120  * Results:
121  *	Always 0 to keep the search going.
122  *
123  * Side effects:
124  *	Adds to ResNodeQueue
125  *
126  *--------------------------------------------------------------------------
127  */
128 
129 int
ResMultiPlaneFunc(tile,tpptr)130 ResMultiPlaneFunc(tile, tpptr)
131     Tile *tile, **tpptr;
132 {
133     Tile *tp = *tpptr;
134     int	 xj, yj;
135 
136     xj = (LEFT(tile) + RIGHT(tile)) / 2;
137     yj = (TOP(tile) + BOTTOM(tile)) / 2;
138     ResNewSDDevice(tp, tile, xj, yj, OTHERPLANE, &ResNodeQueue);
139 
140     return 0;
141 }
142 
143 /*
144  *--------------------------------------------------------------------------
145  *
146  * ResSubstrateFunc---
147  *
148  *  If device is found overlapping its substrate type, then generate a new
149  *  device at the center of the tile and add to ResNodeQueue.
150  *
151  * Results:
152  *	Always 0 to keep the search going.
153  *
154  * Side effects:
155  *	Adds to ResNodeQueue
156  *
157  *--------------------------------------------------------------------------
158  */
159 
160 int
ResSubstrateFunc(tile,tpptr)161 ResSubstrateFunc(tile, tpptr)
162     Tile *tile, **tpptr;
163 {
164     Tile *tp = *tpptr;
165     int	 xj, yj;
166 
167     xj = (LEFT(tile) + RIGHT(tile)) / 2;
168     yj = (TOP(tile) + BOTTOM(tile)) / 2;
169     ResNewSubDevice(tp, tile, xj, yj, OTHERPLANE, &ResNodeQueue);
170 
171     return 0;
172 }
173 
174 /*
175  *--------------------------------------------------------------------------
176  *
177  * ResEachTile--for each tile, make a list of all possible current sources/
178  *   sinks including contacts, devices, and junctions.  Once this
179  *   list is made, calculate the resistor network for the tile.
180  *
181  *  Results: returns TRUE or FALSE depending on whether a node was
182  *           involved in a merge.
183  *
184  *  Side Effects: creates Nodes, devices, junctions, and breakpoints.
185  *
186  *
187  *--------------------------------------------------------------------------
188  */
189 
190 bool
ResEachTile(tile,startpoint)191 ResEachTile(tile, startpoint)
192     Tile 	*tile;
193     Point 		*startpoint;
194 
195 {
196     Tile 	*tp;
197     resNode	*resptr;
198     cElement	*ce;
199     TileType	t1, t2;
200     int		xj, yj, i;
201     bool	merged;
202     tElement	*tcell;
203     tileJunk	*tstructs= (tileJunk *)(tile->ti_client);
204     ExtDevice   *devptr;
205 
206     ResTileCount++;
207 
208     /* Process startpoint, if any. */
209 
210     if (IsSplit(tile))
211     {
212 	t1 = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
213     }
214     else
215 	t1 = TiGetTypeExact(tile);
216 
217     if (startpoint != (Point *) NULL)
218     {
219 	int x = startpoint->p_x;
220 	int y = startpoint->p_y;
221 	resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
222 	InitializeNode(resptr, x, y, RES_NODE_ORIGIN);
223 	resptr->rn_status = TRUE;
224 	resptr->rn_noderes = 0;
225 	ResAddToQueue(resptr, &ResNodeQueue);
226 	NEWBREAK(resptr, tile, x, y, NULL);
227 	resCurrentNode = resptr;
228 	resNodeIsPort(resptr, x, y, tile);
229     }
230 
231     if TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t1)
232     {
233 	/*
234 	 * The device is put in the center of the tile. This is fine
235 	 * for single tile device, but not as good for multiple ones.
236 	 */
237 
238 	if (tstructs->tj_status & RES_TILE_DEV)
239  	{
240 	    if (tstructs->deviceList->rd_fet_gate == NULL)
241 	    {
242 		int x = (LEFT(tile) + RIGHT(tile)) >> 1;
243 		int y = (TOP(tile) + BOTTOM(tile)) >> 1;
244 
245 		resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
246 		tstructs->deviceList->rd_fet_gate = resptr;
247 		tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
248 		tcell->te_thist = tstructs->deviceList;
249 		tcell->te_nextt = NULL;
250 
251 		InitializeNode(resptr, x, y, RES_NODE_JUNCTION);
252 		resptr->rn_te = tcell;
253 		ResAddToQueue(resptr, &ResNodeQueue);
254 		resNodeIsPort(resptr, x, y, tile);
255 
256 		NEWBREAK(resptr, tile, resptr->rn_loc.p_x,
257 		     			resptr->rn_loc.p_y, NULL);
258 	    }
259 	}
260     }
261 
262     /* Process all the contact points */
263     ce = tstructs->contactList;
264     while (ce != (cElement *) NULL)
265     {
266 	ResContactPoint	*cp = ce->ce_thisc;
267 	cElement	*oldce;
268 	if (cp->cp_cnode[0] == (resNode *) NULL)
269 	{
270 	    ResDoContacts(cp, &ResNodeQueue, &ResResList);
271 	}
272 	oldce = ce;
273 	ce = ce->ce_nextc;
274 	freeMagic((char *)oldce);
275     }
276     tstructs->contactList = NULL;
277 
278     /*
279      * Walk the four sides of the tile looking for adjoining connecting
280      * materials.
281      */
282 
283     /* left */
284     for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
285     {
286 	t2 = TiGetRightType(tp);
287 	devptr = ExtCurStyle->exts_device[t2];
288 	if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2) &&
289 	      TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), t1))
290         /* found device */
291 	{
292 	    xj = LEFT(tile);
293 	    yj = (TOP(tp) + BOTTOM(tp)) >> 1;
294 	    ResNewSDDevice(tile, tp, xj, yj, RIGHTEDGE, &ResNodeQueue);
295 	}
296 	if TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)
297 	/* tile is junction  */
298 	{
299 	    /*junction rn_loc */
300 	    xj = LEFT(tile);
301 	    yj = (MAX(BOTTOM(tile), BOTTOM(tp)) + MIN(TOP(tile), TOP(tp))) >> 1;
302 	    (void) ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
303 	}
304     }
305 
306     /* right */
307     for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp=LB(tp))
308     {
309       	t2 = TiGetLeftType(tp);
310 	devptr = ExtCurStyle->exts_device[t2];
311 	if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2) &&
312 	      TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), t1))
313         /* found device */
314 	{
315 	    xj = RIGHT(tile);
316 	    yj = (TOP(tp)+BOTTOM(tp))>>1;
317 	    ResNewSDDevice(tile, tp, xj, yj, LEFTEDGE, &ResNodeQueue);
318 	}
319 	if TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2)
320 	/* tile is junction  */
321 	{
322 	    /*junction rn_loc */
323 	    xj = RIGHT(tile);
324 	    yj = (MAX(BOTTOM(tile),BOTTOM(tp)) + MIN(TOP(tile), TOP(tp))) >> 1;
325 	    (void)ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
326 	}
327     }
328 
329     /* top */
330     for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp=BL(tp))
331     {
332       	t2 = TiGetBottomType(tp);
333 	devptr = ExtCurStyle->exts_device[t2];
334 	if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2) &&
335 	      TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), t1))
336         /* found device */
337 	{
338 	    yj = TOP(tile);
339 	    xj = (LEFT(tp)+RIGHT(tp))>>1;
340 	    ResNewSDDevice(tile, tp, xj, yj, BOTTOMEDGE, &ResNodeQueue);
341 	}
342 	if TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1],t2)
343 	/* tile is junction  */
344 	{
345 	    yj = TOP(tile);
346 	    xj = (MAX(LEFT(tile),LEFT(tp)) + MIN(RIGHT(tile),RIGHT(tp))) >> 1;
347 	    ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
348 	}
349     }
350 
351     /* bottom */
352     for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
353     {
354       	t2 = TiGetTopType(tp);
355 	devptr = ExtCurStyle->exts_device[t2];
356 	if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2) &&
357 	      TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), t1))
358         /* found device */
359 	{
360 	    yj = BOTTOM(tile);
361 	    xj = (LEFT(tp) + RIGHT(tp)) >> 1;
362 	    ResNewSDDevice(tile, tp, xj, yj, TOPEDGE, &ResNodeQueue);
363 	}
364 	if TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)
365 	/* tile is junction  */
366 	{
367 	    yj = BOTTOM(tile);
368 	    xj = (MAX(LEFT(tile),LEFT(tp)) + MIN(RIGHT(tile),RIGHT(tp))) >> 1;
369 	    ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
370 	}
371     }
372 
373     /* Check for source/drain on other planes (e.g., capacitors, bipolars, ...) */
374 
375     if (TTMaskHasType(&ResSDTypesBitMask, t1))
376     {
377 	Rect r;
378 	int pNum;
379 	TileTypeBitMask devMask;
380 
381 	TiToRect(tile, &r);
382 
383 	for (pNum = 0; pNum < DBNumPlanes; pNum++)
384 	{
385 	    if (DBTypeOnPlane(t1, pNum)) continue;
386 
387 	    /* NOTE:  This is ridiculously inefficient and should be done
388 	     * in a different way.
389 	     */
390 
391 	    TTMaskZero(&devMask);
392 	    for (t2 = TT_TECHDEPBASE; t2 < DBNumUserLayers; t2++)
393 		for (devptr = ExtCurStyle->exts_device[t2]; devptr;
394 			    devptr = devptr->exts_next)
395 		    for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++)
396 			if (TTMaskHasType(&devptr->exts_deviceSDTypes[i], t1))
397 			    TTMaskSetType(&devMask, t2);
398 
399 	    DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pNum],
400 			&r, &devMask, ResMultiPlaneFunc, (ClientData)&tile);
401 	}
402     }
403 
404     /* Check for substrate under device */
405 
406     if (TTMaskHasType(&ResSubTypesBitMask, t1))
407     {
408 	Rect r;
409 	int pNum;
410 	TileTypeBitMask devMask;
411 
412 	TiToRect(tile, &r);
413 
414 	for (pNum = 0; pNum < DBNumPlanes; pNum++)
415 	{
416 	    if (DBTypeOnPlane(t1, pNum)) continue;
417 
418 	    /* NOTE:  This is ridiculously inefficient and should be done
419 	     * in a different way.
420 	     */
421 
422 	    TTMaskZero(&devMask);
423 	    for (t2 = TT_TECHDEPBASE; t2 < DBNumUserLayers; t2++)
424 		for (devptr = ExtCurStyle->exts_device[t2]; devptr;
425 			    devptr = devptr->exts_next)
426 		    if (TTMaskHasType(&devptr->exts_deviceSubstrateTypes, t1))
427 			TTMaskSetType(&devMask, t2);
428 
429 	    DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pNum],
430 			&r, &devMask, ResSubstrateFunc, (ClientData)&tile);
431 	}
432     }
433 
434     tstructs->tj_status |= RES_TILE_DONE;
435 
436     resAllPortNodes(tile, &ResNodeQueue);
437 
438     merged = ResCalcTileResistance(tile, tstructs, &ResNodeQueue,
439 			&ResNodeList);
440 
441     return(merged);
442 }
443 
444 /*
445  *-------------------------------------------------------------------------
446  *
447  * resSubDevFunc -- called when DBSrPaintArea finds a device within
448  *	a substrate area.
449  *
450  * Results: always returns 0 to keep search going.
451  *
452  * Side Effects: allocates substrate node.
453  *
454  *-------------------------------------------------------------------------
455  */
456 
457 int
resSubDevFunc(tile,tp)458 resSubDevFunc(tile, tp)
459     Tile	*tile, *tp;
460 {
461     tileJunk	*junk = (tileJunk *)(tile->ti_client);
462     resNode	*resptr;
463     tElement	*tcell;
464     int		x, y;
465 
466     if (junk->deviceList->rd_fet_subs == NULL)
467     {
468         resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
469 	junk->deviceList->rd_fet_subs = resptr;
470 	junk->tj_status |= RES_TILE_DEV;
471         tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
472 	tcell->te_thist = junk->deviceList;
473 	tcell->te_nextt = NULL;
474 	x = (LEFT(tile) + RIGHT(tile)) >> 1;
475 	y = (TOP(tile) + BOTTOM(tile)) >> 1;
476 
477 	InitializeNode(resptr, x, y, RES_NODE_JUNCTION);
478 	resptr->rn_te = tcell;
479 	ResAddToQueue(resptr, &ResNodeQueue);
480 
481 	NEWBREAK(resptr, tp, x, y, NULL);
482     }
483     return 0;
484 }
485