1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: dbtechi.c
6  * Database technology internal helper routines
7  * Written by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 #include "global.h"
33 #include "database.h"
34 #include "egraphics.h"
35 #include "tech.h"
36 #include "tecgen.h"
37 #include "tecmocmos.h"
38 #include "efunction.h"
39 #include "usr.h"
40 
41 /*
42  * when arcs are curved (with "arc curve" or "arc center") the number of
43  * line segments will be between this value, and half of this value.
44  */
45 #define MAXARCPIECES   16		/* maximum segments in curved arc */
46 
47 static GRAPHICS tech_arrow = {LAYERO, CELLOUT, SOLIDC, SOLIDC,
48 	{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
49 	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
50 static GRAPHICS tech_vartxt = {LAYERO, CELLTXT, SOLIDC, SOLIDC,
51 	{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
52 	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
53 
54 /* prototypes for local routines */
55 static void      db_adjusttree(NODEPROTO*);
56 static void      tech_shortenmostrans(NODEINST*, POLYGON*, TECH_POLYGON*, INTBIG, INTBIG, TECH_PORTS*);
57 static INTBIG    tech_displayableanyvars(WINDOWPART *win, NODEPROTO *np, POLYLOOP *pl);
58 static VARIABLE *tech_filldisplayableanyvar(POLYGON *poly, INTBIG lx, INTBIG hx,
59 					INTBIG ly, INTBIG hy, INTBIG addr, INTBIG type, TECHNOLOGY *tech,
60 					WINDOWPART *win, NODEPROTO *cell, VARIABLE **varnoeval, POLYLOOP *pl);
61 
62 /******************** GENERAL ********************/
63 
tech_doinitprocess(TECHNOLOGY * tech)64 BOOLEAN tech_doinitprocess(TECHNOLOGY *tech)
65 {
66 	REGISTER TECH_NODES *nty;
67 	REGISTER TECH_ARCS *at;
68 	REGISTER INTBIG i;
69 	REGISTER INTBIG lam;
70 
71 	/* calculate the true number of layers, arcprotos, and nodeprotos */
72 	for(tech->layercount=0; tech->layers[tech->layercount] != NOGRAPHICS;
73 		tech->layercount++) ;
74 	for(tech->arcprotocount=0; tech->arcprotos[tech->arcprotocount] != ((TECH_ARCS *)-1);
75 		tech->arcprotocount++) ;
76 	for(tech->nodeprotocount=0; tech->nodeprotos[tech->nodeprotocount] != ((TECH_NODES *)-1);
77 		tech->nodeprotocount++) ;
78 
79 	/* initialize the nodeprotos */
80 	lam = tech->deflambda;
81 	for(i=0; i<tech->nodeprotocount; i++)
82 	{
83 		nty = tech->nodeprotos[i];
84 		nty->creation = db_newprimnodeproto(nty->nodename, nty->xsize*lam/WHOLE,
85 			nty->ysize*lam/WHOLE, nty->nodeindex, tech);
86 		if (nty->creation == NONODEPROTO)
87 		{
88 			ttyputerr(_("Cannot create nodeprotos"));
89 			return(TRUE);
90 		}
91 		nty->creation->userbits = nty->initialbits;
92 	}
93 
94 	/* initialize the arcs */
95 	for(i=0; i<tech->arcprotocount; i++)
96 	{
97 		at = tech->arcprotos[i];
98 		at->creation = db_newarcproto(tech, at->arcname, at->arcwidth*lam/WHOLE, at->arcindex);
99 		if (at->creation == NOARCPROTO)
100 		{
101 			ttyputerr(_("Cannot create arcproto %s in technology %s"),
102 				at->arcname, tech->techname);
103 			return(TRUE);
104 		}
105 		at->creation->userbits = at->initialbits;
106 	}
107 	return(FALSE);
108 }
109 
tech_doaddportsandvars(TECHNOLOGY * tech)110 BOOLEAN tech_doaddportsandvars(TECHNOLOGY *tech)
111 {
112 	REGISTER TECH_NODES *nty;
113 	REGISTER NODEPROTO *np;
114 	REGISTER INTBIG i, j, k;
115 	REGISTER INTBIG pindex, *centerlist;
116 	REGISTER TECH_PORTS *portinst;
117 	REGISTER ARCPROTO *ap;
118 	REGISTER TECHNOLOGY *te;
119 
120 	/* reset pointers to ports */
121 	for(i=0; i<tech->nodeprotocount; i++)
122 	{
123 		nty = tech->nodeprotos[i];
124 		portinst = nty->portlist;
125 		for(j=0; j<nty->portcount; j++)
126 			portinst[j].addr = NOPORTPROTO;
127 	}
128 
129 	/* first add ports */
130 	for(i=0; i<tech->nodeprotocount; i++)
131 	{
132 		nty = tech->nodeprotos[i];
133 		portinst = nty->portlist;
134 		for(j=0; j<nty->portcount; j++)
135 		{
136 			/* create the list of arcprotos */
137 			if (portinst[j].portarcs[0] == -1)
138 			{
139 				/* convert the arc prototypes in the list */
140 				for(k=1; portinst[j].portarcs[k] != -1; k++)
141 				{
142 					pindex = portinst[j].portarcs[k];
143 					if ((pindex >> 16) == 0) te = tech; else
144 					{
145 						for(te = el_technologies; te != NOTECHNOLOGY; te = te->nexttechnology)
146 							if (te->techindex == (pindex>>16)-1) break;
147 						if (te == NOTECHNOLOGY) te = tech;
148 						pindex &= 0xFFFF;
149 					}
150 					for(ap = te->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
151 						if (ap->arcindex == pindex)
152 					{
153 						portinst[j].portarcs[k] = (INTBIG)ap;
154 						break;
155 					}
156 				}
157 				portinst[j].portarcs[0] = 0;
158 			}
159 
160 			/* create the portproto */
161 			if (portinst[j].addr != NOPORTPROTO)
162 			{
163 				ttyputerr(_("Warning: node %s of technology %s shares port descriptions"),
164 					nty->creation->protoname, tech->techname);
165 			}
166 			portinst[j].addr = db_newprimportproto(nty->creation,
167 				(ARCPROTO **)&portinst[j].portarcs[1], portinst[j].protoname);
168 			if (portinst[j].addr == NOPORTPROTO)
169 			{
170 				ttyputerr(_("Error creating ports"));
171 				return(TRUE);
172 			}
173 			portinst[j].addr->userbits = portinst[j].initialbits;
174 		}
175 	}
176 
177 	/* now add variables */
178 	for(i=0; tech->variables[i].name != 0; i++)
179 	{
180 		/* handle "prototype_center" variable specially */
181 		if (namesame(tech->variables[i].name, x_("prototype_center")) == 0)
182 		{
183 			centerlist = (INTBIG *)tech->variables[i].value;
184 			for(j=0; j<tech->variables[i].type; j++)
185 			{
186 				np = tech->nodeprotos[centerlist[j*3]-1]->creation;
187 				(void)setvalkey((INTBIG)np, VNODEPROTO, el_prototype_center_key,
188 					(INTBIG)&centerlist[j*3+1], VINTEGER|VISARRAY|(2<<VLENGTHSH));
189 			}
190 			continue;
191 		}
192 
193 		/* floating point variables have data in a different place */
194 		if ((tech->variables[i].type&VTYPE) == VFLOAT && (tech->variables[i].type&VISARRAY) == 0)
195 		{
196 			nextchangequiet();
197 			if (setvalkey((INTBIG)tech, VTECHNOLOGY, makekey(tech->variables[i].name),
198 				castint(tech->variables[i].fvalue), tech->variables[i].type) == NOVARIABLE)
199 					return(TRUE);
200 			continue;
201 		}
202 
203 		/* normal variable setting */
204 		nextchangequiet();
205 		if (setvalkey((INTBIG)tech, VTECHNOLOGY, makekey(tech->variables[i].name),
206 			(INTBIG)tech->variables[i].value, tech->variables[i].type) == NOVARIABLE)
207 				return(TRUE);
208 	}
209 
210 	return(FALSE);
211 }
212 
213 /*
214  * routine to convert old format mocmos (MOSIS CMOS) library "lib" to the current
215  * design style
216  */
tech_convertmocmoslib(LIBRARY * lib)217 void tech_convertmocmoslib(LIBRARY *lib)
218 {
219 	REGISTER INTBIG prims;
220 	REGISTER INTBIG lambda;
221 	REGISTER NODEPROTO *np;
222 	REGISTER ARCINST *ai;
223 	REGISTER NODEINST *ni;
224 	REGISTER TECHNOLOGY *mocmostech;
225 
226 	for(mocmostech = el_technologies; mocmostech != NOTECHNOLOGY; mocmostech = mocmostech->nexttechnology)
227 		if (namesame(mocmostech->techname, x_("mocmos")) == 0) break;
228 	if (mocmostech == NOTECHNOLOGY)
229 	{
230 		ttyputmsg(M_("Cannot find 'mocmos' technology"));
231 		return;
232 	}
233 
234 	lambda = lib->lambda[mocmostech->techindex];
235 	prims = 0;
236 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
237 	{
238 		for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
239 		{
240 			if (ai->proto->tech != mocmostech) continue;
241 			if (namesame(ai->proto->protoname, x_("S-Active")) != 0) continue;
242 			undogeom(ai->geom, np);
243 			ai->width += 4 * lambda;
244 			linkgeom(ai->geom, np);
245 			prims++;
246 		}
247 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
248 		{
249 			if (ni->proto->primindex == 0) continue;
250 			if (ni->proto->tech != mocmostech) continue;
251 			if (namesame(ni->proto->protoname, x_("S-Active-Pin")) == 0 ||
252 				namesame(ni->proto->protoname, x_("S-Transistor")) == 0 ||
253 				namesame(ni->proto->protoname, x_("Metal-1-S-Active-Con")) == 0)
254 			{
255 				undogeom(ni->geom, np);
256 				ni->lowx -= 2 * lambda;
257 				ni->highx += 2 * lambda;
258 				ni->lowy -= 2 * lambda;
259 				ni->highy += 2 * lambda;
260 				linkgeom(ni->geom, np);
261 				prims++;
262 				continue;
263 			}
264 			if (ni->proto == mocmos_metal1pwellprim)
265 			{
266 				undogeom(ni->geom, np);
267 				ni->lowx -= 4 * lambda;
268 				ni->highx += 4 * lambda;
269 				ni->lowy -= 4 * lambda;
270 				ni->highy += 4 * lambda;
271 				linkgeom(ni->geom, np);
272 				prims++;
273 				continue;
274 			}
275 		}
276 	}
277 
278 	/* if nothing was changed, quit now */
279 	if (prims == 0)
280 	{
281 		ttyputmsg(M_("No MOSIS CMOS objects found to alter"));
282 		return;
283 	}
284 
285 	/* adjust cell sizes */
286 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
287 		np->temp1 = 0;
288 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
289 		if (np->firstinst == NONODEINST) db_adjusttree(np);
290 
291 	ttyputmsg(M_("%ld S-active arcs, S-Active pins, Metal-1-S-Active"), prims);
292 	ttyputmsg(M_("  contacts, S-Transistors, and Metal-1-Substrate"));
293 	ttyputmsg(M_("  contacts from the MOSIS CMOS technology in this"));
294 	ttyputmsg(M_("  library have been adjusted."));
295 	ttyputmsg(M_("NOW DO A -debug check-database TO ADJUST CELL SIZES"));
296 }
297 
db_adjusttree(NODEPROTO * np)298 void db_adjusttree(NODEPROTO *np)
299 {
300 	REGISTER NODEINST *ni;
301 	REGISTER INTBIG dlx, dhx, dly, dhy, nlx, nhx, nly, nhy;
302 	INTBIG lx, hx, ly, hy, offx, offy;
303 	XARRAY trans;
304 
305 	/* descend the hierarchy to get the bottom cells first */
306 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
307 	{
308 		if (ni->proto->primindex != 0) continue;
309 		if (ni->proto->temp1 != 0) continue;
310 		db_adjusttree(ni->proto);
311 	}
312 
313 	/* now adjust the cell size */
314 	np->temp1++;
315 	db_boundcell(np, &lx, &hx, &ly, &hy);
316 	if (lx == np->lowx && hx == np->highx && ly == np->lowy && hy == np->highy) return;
317 
318 	/* adjust all instances of the cell */
319 	for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
320 	{
321 		undogeom(ni->geom, ni->parent);
322 		makeangle(ni->rotation, ni->transpose, trans);
323 		dlx = lx - np->lowx;   dhx = hx - np->highx;
324 		dly = ly - np->lowy;   dhy = hy - np->highy;
325 		xform(dhx+dlx, dhy+dly, &offx, &offy, trans);
326 		nlx = (dlx-dhx+offx) / 2;   nhx = offx - nlx;
327 		nly = (dly-dhy+offy) / 2;   nhy = offy - nly;
328 		ni->lowx += nlx;   ni->highx += nhx;
329 		ni->lowy += nly;   ni->highy += nhy;
330 		linkgeom(ni->geom, ni->parent);
331 	}
332 	np->lowx = lx;   np->highx = hx;
333 	np->lowy = ly;   np->highy = hy;
334 }
335 
336 /******************** NODEINST DESCRIPTION ********************/
337 
338 /*
339  * routine to fill polygon "poly" with a description of box "box" of MOS
340  * transistor node "ni".  The assumption is that this box is shortened
341  * because of a nonmanhattan arc attaching to the transistor.  The graphical
342  * layer information is in "lay", the value of lambda is in "lambda", and
343  * the port information is in "portstruct".  The assumption of this port
344  * structure and the transistor in general is that ports 0 and 2 are the
345  * polysilicon and ports 1 and 3 are the diffusion.  Also, box 0 is the
346  * diffusion and box 1 is the polysilicon.
347  */
tech_shortenmostrans(NODEINST * ni,POLYGON * poly,TECH_POLYGON * lay,INTBIG lambda,INTBIG box,TECH_PORTS * portstruct)348 void tech_shortenmostrans(NODEINST *ni, POLYGON *poly, TECH_POLYGON *lay, INTBIG lambda,
349 	INTBIG box, TECH_PORTS *portstruct)
350 {
351 	INTBIG lx, hx, ly, hy;
352 	REGISTER INTBIG wid, swid, len, x1, y1, x2, y2, shrink1, shrink2, ang, end1, end2, dist,
353 		halflength;
354 	REGISTER ARCINST *ai;
355 	REGISTER PORTARCINST *pi, *pi1, *pi2;
356 
357 	/* compute the box geometry */
358 	subrange(ni->lowx, ni->highx, lay->points[0], lay->points[1], lay->points[4], lay->points[5],
359 		&lx, &hx, lambda);
360 	subrange(ni->lowy, ni->highy, lay->points[2], lay->points[3], lay->points[6], lay->points[7],
361 		&ly, &hy, lambda);
362 	if (box == 0)
363 	{
364 		/* find the arcs on this, the vertical diffusion box */
365 		pi1 = pi2 = NOPORTARCINST;
366 		for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
367 		{
368 			if (pi->proto == portstruct[1].addr) pi1 = pi;
369 			if (pi->proto == portstruct[3].addr) pi2 = pi;
370 		}
371 
372 		/* specify the box */
373 		x1 = x2 = (hx+lx) / 2;
374 		swid = wid = hx-lx;
375 		halflength = abs(hy-ly) / 2;
376 		if (pi1 != NOPORTARCINST)
377 		{
378 			if (pi1->conarcinst->width < wid) pi1 = NOPORTARCINST; else
379 				swid = mini(swid, pi1->conarcinst->width);
380 		}
381 		if (pi2 != NOPORTARCINST)
382 		{
383 			if (pi2->conarcinst->width < wid) pi2 = NOPORTARCINST; else
384 				swid = mini(swid, pi2->conarcinst->width);
385 		}
386 		y1 = hy - swid / 2;   y2 = ly + swid / 2;
387 		len = y1-y2;
388 	} else
389 	{
390 		/* find the arcs on this, the horizontal polysilicon box */
391 		pi1 = pi2 = NOPORTARCINST;
392 		for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
393 		{
394 			if (pi->proto == portstruct[0].addr) pi1 = pi;
395 			if (pi->proto == portstruct[2].addr) pi2 = pi;
396 		}
397 
398 		/* specify the box */
399 		y1 = y2 = (hy+ly) / 2;
400 		swid = wid = hy-ly;
401 		halflength = abs(hx-lx) / 2;
402 		if (pi1 != NOPORTARCINST)
403 		{
404 			if (pi1->conarcinst->width < wid) pi1 = NOPORTARCINST; else
405 				swid = mini(swid, pi1->conarcinst->width);
406 		}
407 		if (pi2 != NOPORTARCINST)
408 		{
409 			if (pi2->conarcinst->width < wid) pi2 = NOPORTARCINST; else
410 				swid = mini(swid, pi2->conarcinst->width);
411 		}
412 		x1 = lx + swid / 2;   x2 = hx - swid / 2;
413 		len = x2-x1;
414 	}
415 	shrink1 = shrink2 = 0;
416 	if (pi1 != NOPORTARCINST)
417 	{
418 		ai = pi1->conarcinst;
419 		if (ai->end[0].nodeinst == ni && ai->end[0].portarcinst->proto == pi1->proto)
420 		{
421 			end1 = 0;
422 			shrink1 = ai->endshrink & 0xFFFF;
423 		} else
424 		{
425 			end1 = 1;
426 			shrink1 = (ai->endshrink >> 16) & 0xFFFF;
427 		}
428 	}
429 	if (pi2 != NOPORTARCINST)
430 	{
431 		ai = pi2->conarcinst;
432 		if (ai->end[0].nodeinst == ni && ai->end[0].portarcinst->proto == pi2->proto)
433 		{
434 			end2 = 0;
435 			shrink2 = ai->endshrink & 0xFFFF;
436 		} else
437 		{
438 			end2 = 1;
439 			shrink2 = (ai->endshrink >> 16) & 0xFFFF;
440 		}
441 	}
442 	if (shrink1 == 0 && shrink2 == 0)
443 	{
444 		if (poly->limit < 4) (void)extendpolygon(poly, 4);
445 		poly->xv[1] = poly->xv[0] = lx;   poly->xv[3] = poly->xv[2] = hx;
446 		poly->yv[3] = poly->yv[0] = ly;   poly->yv[2] = poly->yv[1] = hy;
447 		poly->count = 4;
448 	} else
449 	{
450 		if (shrink1 == 0) shrink1 = wid / 2; else
451 		{
452 			dist = computedistance(ai->end[end1].xpos, ai->end[end1].ypos,
453 				(ni->geom->lowx+ni->geom->highx)/2, (ni->geom->lowy+ni->geom->highy)/2);
454 			shrink1 = wid / 2 + tech_getextendfactor(wid, shrink1);
455 			shrink1 -= halflength - dist;
456 		}
457 		if (shrink2 == 0) shrink2 = wid / 2; else
458 		{
459 			dist = computedistance(ai->end[end2].xpos, ai->end[end2].ypos,
460 				(ni->geom->lowx+ni->geom->highx)/2, (ni->geom->lowy+ni->geom->highy)/2);
461 			shrink2 = wid / 2 + tech_getextendfactor(wid, shrink2);
462 			shrink2 -= halflength - dist;
463 		}
464 		ang = figureangle(x1, y1, x2, y2);
465 		tech_makeendpointpoly(len, wid, ang, x1,y1, shrink1, x2,y2, shrink2, poly);
466 	}
467 	poly->layer = lay->layernum;
468 	poly->style = lay->style;
469 	if (poly->style == FILLEDRECT) poly->style = FILLED; else
470 		if (poly->style == CLOSEDRECT) poly->style = CLOSED;
471 }
472 
473 /*
474  * routine to convert extension factors into distances.  For an arc of
475  * width "wid", the routine returns the proper extension distance for a
476  * factor of "extend".
477  *
478  * Arcs are typically drawn with an extension of half their width.  When arcs
479  * are nonmanhattan, their ends are extended by a variable amount so that
480  * little tabs don't appear at the places where they overlap.  The
481  * "endshrink" factor on an arcinst determines the angle at which the ends
482  * meet other arcinsts and therefore, the amount of extension that must be
483  * applied.  Since angles greater than 90 are reflective cases of the angles
484  * less than 90, the extension factor is a number from 0 to 90 where a small
485  * value indicates that the ends should not extend much and an extension of
486  * 90 indicates full extension.  The exception is the value 0 which also
487  * indicates full extension.  The formula is that the end of the arcinst
488  * extends beyond the actual terminus by:
489  *    (half arcinst width) / tan(extension/2)
490  * This works out correctly for a extension of 90 because the tangent of 45
491  * is 1 and a manhattan connection should extend beyond its terminus by half
492  * its width.  The "extendfactor" table has the values of:
493  *     100 * tan(extension/2)
494  * for the values of extension from 0 to 90.
495  */
tech_getextendfactor(INTBIG wid,INTBIG extend)496 INTBIG tech_getextendfactor(INTBIG wid, INTBIG extend)
497 {
498 	static INTBIG extendfactor[] = {0,
499 		11459, 5729, 3819, 2864, 2290, 1908, 1635, 1430, 1271, 1143,
500 		 1039,  951,  878,  814,  760,  712,  669,  631,  598,  567,
501 		  540,  514,  492,  470,  451,  433,  417,  401,  387,  373,
502 		  361,  349,  338,  327,  317,  308,  299,  290,  282,  275,
503 		  267,  261,  254,  248,  241,  236,  230,  225,  219,  214,
504 		  210,  205,  201,  196,  192,  188,  184,  180,  177,  173,
505 		  170,  166,  163,  160,  157,  154,  151,  148,  146,  143,
506 		  140,  138,  135,  133,  130,  128,  126,  123,  121,  119,
507 		  117,  115,  113,  111,  109,  107,  105,  104,  102,  100};
508 
509 	/* compute the amount of extension (from 0 to wid/2) */
510 	if (extend <= 0) return(wid/2);
511 
512 	/* values should be from 0 to 90, but check anyway */
513 	if (extend > 90) return(wid/2);
514 
515 	/* return correct extension */
516 	return(wid * 50 / extendfactor[extend]);
517 }
518 
519 /*
520  * routine to determine whether pin display should be supressed by counting
521  * the number of arcs and seeing if there are one or two and also by seeing if
522  * the node has exports (then draw it if there are three or more).
523  * Returns true if the pin should be supressed.  If "win" is NOWINDOWPART, then
524  * see if this node is visible in that window and include arcs connected at
525  * higher levels of hierarchy.
526  */
tech_pinusecount(NODEINST * ni,WINDOWPART * win)527 BOOLEAN tech_pinusecount(NODEINST *ni, WINDOWPART *win)
528 {
529 	REGISTER INTBIG i;
530 	INTBIG depth;
531 	REGISTER NODEINST *upni;
532 	NODEINST **nilist;
533 	REGISTER PORTARCINST *pi;
534 	REGISTER PORTEXPINST *pe;
535 
536 	/* count the number of arcs on this node */
537 	i = 0;
538 	for (pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
539 		i++;
540 
541 	/* if the next level up the hierarchy is visible, consider arcs connected there */
542 	if (win != NOWINDOWPART && ni->firstportexpinst != NOPORTEXPINST)
543 	{
544 		db_gettraversalpath(ni->parent, win, &nilist, &depth);
545 		if (depth == 1)
546 		{
547 			upni = nilist[0];
548 			if (upni->proto == ni->parent && upni->parent == win->curnodeproto)
549 			{
550 				/* make sure there is at least one connection for the icon */
551 				if (i == 0) i++;
552 				for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
553 				{
554 					for (pi = upni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
555 						if (pi->proto == pe->exportproto) i++;
556 				}
557 			}
558 		}
559 	}
560 
561 	/* now decide whether or not to supress the pin */
562 	if (i > 2) return(FALSE);
563 	if (ni->firstportexpinst != NOPORTEXPINST) return(TRUE);
564 	if (i == 0) return(FALSE);
565 	return(TRUE);
566 }
567 
568 /*
569  * routine to return the number of contact cuts needed for node "ni" and to
570  * setup the globals for the subsequent calls to "tech_moscutpoly".  The size
571  * of a single cut is "cutsizex" by "cutsizey", the indentation from the edge
572  * of the node is in "cutindent", and the separation between cuts is "cutsep",
573  * all given in WHOLE fractions of lambda.  "reasonable" is loaded with a
574  * smaller number of polygons to use when too many become prohibitive.
575  */
tech_moscutcount(NODEINST * ni,INTBIG cutsizex,INTBIG cutsizey,INTBIG cutindent,INTBIG cutsep,INTBIG * reasonable,POLYLOOP * pl)576 INTBIG tech_moscutcount(NODEINST *ni, INTBIG cutsizex, INTBIG cutsizey, INTBIG cutindent,
577 	INTBIG cutsep, INTBIG *reasonable, POLYLOOP *pl)
578 {
579 	REGISTER INTBIG lambda, lx, hx, ly, hy;
580 
581 	/* get the lambda value */
582 	lambda = lambdaofnode(ni);
583 	pl->moscutsizex = cutsizex;
584 	pl->moscutsizey = cutsizey;
585 	pl->moscutsep = cutsep;
586 	cutsizex = cutsizex * lambda / WHOLE;
587 	cutsizey = cutsizey * lambda / WHOLE;
588 	cutindent = cutindent * lambda / WHOLE;
589 	cutsep = cutsep * lambda / WHOLE;
590 
591 	/* determine the actual node size */
592 	nodesizeoffset(ni, &pl->moscutlx, &pl->moscutly, &pl->moscuthx, &pl->moscuthy);
593 	lx = ni->lowx + pl->moscutlx;   hx = ni->highx - pl->moscuthx;
594 	ly = ni->lowy + pl->moscutly;   hy = ni->highy - pl->moscuthy;
595 
596 	/* number of cuts depends on the size */
597 	pl->moscutsx = (hx-lx-cutindent*2+cutsep) / (cutsizex+cutsep);
598 	pl->moscutsy = (hy-ly-cutindent*2+cutsep) / (cutsizey+cutsep);
599 	if (pl->moscutsx <= 0) pl->moscutsx = 1;
600 	if (pl->moscutsy <= 0) pl->moscutsy = 1;
601 	pl->moscuttotal = pl->moscutsx * pl->moscutsy;
602 	*reasonable = pl->moscuttotal;
603 	if (pl->moscuttotal != 1)
604 	{
605 		/* prepare for the multiple contact cut locations */
606 		pl->moscutbasex = (hx-lx-cutindent*2 - cutsizex*pl->moscutsx -
607 			cutsep*(pl->moscutsx-1)) * WHOLE / lambda / 2 +
608 				(pl->moscutlx + cutindent) * WHOLE / lambda;
609 		pl->moscutbasey = (hy-ly-cutindent*2 - cutsizey*pl->moscutsy -
610 			cutsep*(pl->moscutsy-1)) * WHOLE / lambda / 2 +
611 				(pl->moscutly + cutindent) * WHOLE / lambda;
612 		if (pl->moscutsx > 2 && pl->moscutsy > 2)
613 		{
614 			*reasonable = pl->moscutsx * 2 + (pl->moscutsy-2) * 2;
615 			pl->moscuttopedge = pl->moscutsx*2;
616 			pl->moscutleftedge = pl->moscutsx*2 + pl->moscutsy-2;
617 			pl->moscutrightedge = pl->moscutsx*2 + (pl->moscutsy-2)*2;
618 		}
619 	}
620 	return(pl->moscuttotal);
621 }
622 
623 /*
624  * routine to fill in the contact cuts of a MOS contact when there are
625  * multiple cuts.  Node is in "ni" and the contact cut number (0 based) is
626  * in "cut".  The array describing the cut is filled into "descrip" which is:
627  *     INTBIG descrip[8] = {-H0, K1,-H0, K1, -H0, K3,-H0, K3};
628  * This routine presumes that "tech_moscutcount" has already been called
629  * so that the globals "tech_moscutlx", "tech_moscuthx", "tech_moscutly",
630  * "tech_moscuthy", "tech_moscutbasex", "tech_moscutbasey", "tech_moscuttotal",
631  * "tech_moscutsizex", "tech_moscutsizey", "tech_moscuttopedge",
632  * "tech_moscutleftedge", and "tech_moscutrightedge" are set.
633  */
tech_moscutpoly(NODEINST * ni,INTBIG cut,INTBIG descrip[],POLYLOOP * pl)634 void tech_moscutpoly(NODEINST *ni, INTBIG cut, INTBIG descrip[], POLYLOOP *pl)
635 {
636 	REGISTER INTBIG lambda, cutx, cuty;
637 
638 	lambda = lambdaofnode(ni);
639 
640 	if (pl->moscutsx > 2 && pl->moscutsy > 2)
641 	{
642 		/* rearrange cuts so that the initial ones go around the outside */
643 		if (cut < pl->moscutsx)
644 		{
645 			/* bottom edge: it's ok as is */
646 			/* EMPTY */
647 		} else if (cut < pl->moscuttopedge)
648 		{
649 			/* top edge: shift up */
650 			cut += pl->moscutsx * (pl->moscutsy-2);
651 		} else if (cut < pl->moscutleftedge)
652 		{
653 			/* left edge: rearrange */
654 			cut = (cut - pl->moscuttopedge) * pl->moscutsx + pl->moscutsx;
655 		} else if (cut < pl->moscutrightedge)
656 		{
657 			/* right edge: rearrange */
658 			cut = (cut - pl->moscutleftedge) * pl->moscutsx + pl->moscutsx*2-1;
659 		} else
660 		{
661 			/* center: rearrange and scale down */
662 			cut = cut - pl->moscutrightedge;
663 			cutx = cut % (pl->moscutsx-2);
664 			cuty = cut / (pl->moscutsx-2);
665 			cut = cuty * pl->moscutsx + cutx+pl->moscutsx+1;
666 		}
667 	}
668 
669 	if (pl->moscutsx == 1)
670 	{
671 		descrip[1] = (ni->highx-ni->lowx)/2 * WHOLE/lambda - pl->moscutsizex/2;
672 		descrip[5] = (ni->highx-ni->lowx)/2 * WHOLE/lambda + pl->moscutsizex/2;
673 	} else
674 	{
675 		descrip[1] = pl->moscutbasex + (cut % pl->moscutsx) * (pl->moscutsizex + pl->moscutsep);
676 		descrip[5] = descrip[1] + pl->moscutsizex;
677 	}
678 
679 	if (pl->moscutsy == 1)
680 	{
681 		descrip[3] = (ni->highy-ni->lowy)/2 * WHOLE/lambda - pl->moscutsizey/2;
682 		descrip[7] = (ni->highy-ni->lowy)/2 * WHOLE/lambda + pl->moscutsizey/2;
683 	} else
684 	{
685 		descrip[3] = pl->moscutbasey + (cut / pl->moscutsx) * (pl->moscutsizey + pl->moscutsep);
686 		descrip[7] = descrip[3] + pl->moscutsizey;
687 	}
688 }
689 
690 /*
691  * helper routine to fill polygon "poly" from the "tech_polygon" structure
692  * in "lay" which is on node "ni".  The value of lambda is "lambda" and the
693  * style of the polygon (if trace information is used) is "sty"
694  */
tech_fillpoly(POLYGON * poly,TECH_POLYGON * lay,NODEINST * ni,INTBIG lambda,INTBIG sty)695 void tech_fillpoly(POLYGON *poly, TECH_POLYGON *lay, NODEINST *ni, INTBIG lambda,
696 	INTBIG sty)
697 {
698 	REGISTER INTBIG i, lastpoint, count;
699 	REGISTER INTBIG x, y, *pt, xm, xs, ym, ys;
700 	INTBIG minlx, minhx, minly, minhy;
701 	REGISTER VARIABLE *var;
702 
703 	/* one thing is constant */
704 	poly->layer = lay->layernum;
705 
706 	/* see if trace information is present */
707 	if ((ni->proto->userbits&HOLDSTRACE) != 0)
708 	{
709 		var = gettrace(ni);
710 		if (var != NOVARIABLE)
711 		{
712 			count = getlength(var) / 2;
713 			x = (ni->highx + ni->lowx) / 2;   y = (ni->highy + ni->lowy) / 2;
714 			if (poly->limit < count) (void)extendpolygon(poly, count);
715 			for(i=0; i<count; i++)
716 			{
717 				poly->xv[i] = ((INTBIG *)var->addr)[i*2] + x;
718 				poly->yv[i] = ((INTBIG *)var->addr)[i*2+1] + y;
719 			}
720 			poly->count = count;
721 			poly->style = sty;
722 			return;
723 		}
724 	}
725 
726 	/* normal description from the technology tables */
727 	switch (lay->representation)
728 	{
729 		case BOX:
730 		case MINBOX:
731 			lastpoint = 8;
732 			if (lay->style == FILLEDRECT || lay->style == CLOSEDRECT)
733 			{
734 				if (poly->limit < 2) (void)extendpolygon(poly, 2);
735 				subrange(ni->lowx, ni->highx, lay->points[0], lay->points[1],
736 					lay->points[4], lay->points[5], &poly->xv[0], &poly->xv[1], lambda);
737 				subrange(ni->lowy, ni->highy, lay->points[2], lay->points[3],
738 					lay->points[6], lay->points[7], &poly->yv[0], &poly->yv[1], lambda);
739 				if (lay->representation == MINBOX)
740 				{
741 					/* make sure the box is large enough */
742 					lastpoint = 16;
743 					subrange(ni->lowx, ni->highx, lay->points[8], lay->points[9],
744 						lay->points[12], lay->points[13], &minlx, &minhx, lambda);
745 					subrange(ni->lowy, ni->highy, lay->points[10], lay->points[11],
746 						lay->points[14], lay->points[15], &minly, &minhy, lambda);
747 					if (poly->xv[0] > minlx) poly->xv[0] = minlx;
748 					if (poly->xv[1] < minhx) poly->xv[1] = minhx;
749 					if (poly->yv[0] > minly) poly->yv[0] = minly;
750 					if (poly->yv[1] < minhy) poly->yv[1] = minhy;
751 				}
752 			} else
753 			{
754 				if (poly->limit < 4) (void)extendpolygon(poly, 4);
755 				subrange(ni->lowx, ni->highx, lay->points[0], lay->points[1],
756 					lay->points[4], lay->points[5], &poly->xv[0], &poly->xv[2], lambda);
757 				subrange(ni->lowy, ni->highy, lay->points[2], lay->points[3],
758 					lay->points[6], lay->points[7], &poly->yv[0], &poly->yv[1], lambda);
759 				if (lay->representation == MINBOX)
760 				{
761 					/* make sure the box is large enough */
762 					lastpoint = 16;
763 					subrange(ni->lowx, ni->highx, lay->points[8], lay->points[9],
764 						lay->points[10], lay->points[13], &minlx, &minhx, lambda);
765 					subrange(ni->lowy, ni->highy, lay->points[10], lay->points[11],
766 						lay->points[14], lay->points[15], &minly, &minhy, lambda);
767 					if (poly->xv[0] > minlx) poly->xv[0] = minlx;
768 					if (poly->xv[2] < minhx) poly->xv[2] = minhx;
769 					if (poly->yv[0] > minly) poly->yv[0] = minly;
770 					if (poly->yv[1] < minhy) poly->yv[1] = minhy;
771 				}
772 				poly->xv[1] = poly->xv[0];   poly->xv[3] = poly->xv[2];
773 				poly->yv[3] = poly->yv[0];   poly->yv[2] = poly->yv[1];
774 			}
775 			break;
776 
777 		case POINTS:
778 			pt = &lay->points[0];
779 			if (poly->limit < lay->count) (void)extendpolygon(poly, lay->count);
780 			for(i=0; i<lay->count; i++)
781 			{
782 				xm = *pt++;   xs = *pt++;   ym = *pt++;   ys = *pt++;
783 				poly->xv[i] = getrange(ni->lowx,ni->highx, xm,xs, lambda);
784 				poly->yv[i] = getrange(ni->lowy,ni->highy, ym,ys, lambda);
785 			}
786 			lastpoint = lay->count*4;
787 			break;
788 
789 		case ABSPOINTS:
790 			pt = &lay->points[0];
791 			if (poly->limit < lay->count) (void)extendpolygon(poly, lay->count);
792 			for(i=0; i<lay->count; i++)
793 			{
794 				xs = *pt++;   ys = *pt++;
795 				poly->xv[i] = getrange(ni->lowx,ni->highx, 0,xs, lambda);
796 				poly->yv[i] = getrange(ni->lowy,ni->highy, 0,ys, lambda);
797 			}
798 			lastpoint = lay->count*2;
799 			break;
800 	}
801 	poly->count = lay->count;
802 	poly->style = lay->style;
803 	if (lay->style >= TEXTCENT && lay->style <= TEXTBOX)
804 		poly->string = (CHAR *)lay->points[lastpoint];
805 }
806 
807 /*
808  * routine to determine the number of polygons that will compose transistor
809  * "ni".  If the transistor is not serpentine, the value supplied in "count"
810  * is returned.  Otherwise, one polygon will be drawn for every segment of
811  * the serpent times every one of the "count" layers.
812  */
tech_inittrans(INTBIG count,NODEINST * ni,POLYLOOP * pl)813 INTBIG tech_inittrans(INTBIG count, NODEINST *ni, POLYLOOP *pl)
814 {
815 	REGISTER INTBIG total;
816 
817 	/* see if the transistor has serpentine information */
818 	pl->serpentvar = gettrace(ni);
819 	if (pl->serpentvar == NOVARIABLE) return(count);
820 
821 	/* trace data is there: make sure there are enough points */
822 	total = getlength(pl->serpentvar);
823 	if (total < 4)
824 	{
825 		pl->serpentvar = NOVARIABLE;
826 		return(count);
827 	}
828 
829 	/* return the number of polygons */
830 	return(count * (total/2 - 1));
831 }
832 
833 /*
834  * Version Jan.11/88 of tech_filltrans() and tech_filltransport() that
835  * draws the diffusions and ports as they are described in the technology
836  * file.
837  */
838 
839 #define LEFTANGLE   900
840 #define RIGHTANGLE 2700
841 /*
842  * routine to describe box "box" of transistor "ni" that may be part of a
843  * serpentine path.  If the variable "trace" exists on the node, get that
844  * x/y/x/y information as the centerline of the serpentine path.  The "laylist"
845  * structure describes the transistor: "lwidth" and "rwidth" are the extension
846  * of the active layer to the left and right; "extendt/extendb" are the extension
847  * of the poly layer on the top and bottom ends.  The outline is
848  * placed in the polygon "poly".  Layer information for this polygon is in
849  * "lay", port information is in "portstruct", and the value of lambda is in
850  * "lambda".  In all manhattan cases, nonoverlapping polygons are
851  * constructed for consecutive segments; the current segment extends to
852  * the furthest boundary of the next, and the next is truncated where it
853  * overlaps the previous polygon.
854  * NOTE: For each trace segment, the left hand side of the trace
855  * will contain the polygons that appear ABOVE the gate in the node
856  * definition. That is, the "top" port and diffusion will be above a
857  * gate segment that extends from left to right, and on the left of a
858  * segment that goes from bottom to top.
859  */
tech_filltrans(POLYGON * poly,TECH_POLYGON ** lay,TECH_SERPENT * laylist,NODEINST * ni,INTBIG lambda,INTBIG box,TECH_PORTS * portstruct,POLYLOOP * pl)860 void tech_filltrans(POLYGON *poly, TECH_POLYGON **lay, TECH_SERPENT *laylist,
861 	NODEINST *ni, INTBIG lambda, INTBIG box, TECH_PORTS *portstruct, POLYLOOP *pl)
862 {
863 	REGISTER INTBIG angle, ang;
864 	REGISTER INTBIG thissg, next, total, segment, element, otherang;
865 	REGISTER INTBIG sin, cos, xoff, yoff, thisxl, thisyl, thisxr, thisyr, lwid,
866 		rwid, extendt, extendb, scale, thisx, thisy, nextx, nexty, *list,
867 		nextxl, nextyl, nextxr, nextyr, otherx, othery;
868 	INTBIG x, y, ly, hy, xl, xr, yl, yr;
869 	REGISTER VARIABLE *varw;
870 
871 	/* nonserpentine transtors fill in the normal way */
872 	if (pl->serpentvar == NOVARIABLE)
873 	{
874 		*lay = &laylist[box].basics;
875 		if (portstruct == 0) tech_fillpoly(poly, *lay, ni, lambda, -1); else
876 			tech_shortenmostrans(ni, poly, *lay, lambda, box, portstruct);
877 		return;
878 	}
879 
880 	/* compute the segment (along the serpent) and element (of transistor) */
881 	total = getlength(pl->serpentvar) / 2 - 1;
882 	segment = box % total;
883 	element = box / total;
884 
885 	/* see if nonstandard width is specified */
886 	lwid = lambda * laylist[element].lwidth / WHOLE;
887 	rwid = lambda * laylist[element].rwidth / WHOLE;
888 	extendt = lambda * laylist[element].extendt / WHOLE;
889 	extendb = lambda * laylist[element].extendb / WHOLE;
890 	varw = getvalkey((INTBIG)ni, VNODEINST, VFRACT, el_transistor_width_key);
891 	if (varw != NOVARIABLE)
892 	{
893 		nodesizeoffset(ni, &x, &ly, &x, &hy);
894 		scale = varw->addr * lambda / WHOLE - ni->proto->highy+ni->proto->lowy+hy+ly;
895 		lwid += scale / 2;
896 		rwid += scale / 2;
897 	}
898 
899 	/* prepare to fill the serpentine transistor */
900 	list = (INTBIG *)pl->serpentvar->addr;
901 	xoff = (ni->highx+ni->lowx)/2;
902 	yoff = (ni->highy+ni->lowy)/2;
903 	thissg = segment;   next = segment+1;
904 	thisx = list[thissg*2];   thisy = list[thissg*2+1];
905 	nextx = list[next*2];   nexty = list[next*2+1];
906 	angle = figureangle(thisx, thisy, nextx, nexty);
907 
908 	/* push the points at the ends of the transistor */
909 	if (thissg == 0)
910 	{
911 		/* extend "thissg" 180 degrees back */
912 		ang = (angle+1800) % 3600;
913 		thisx += mult(cosine(ang), extendt);
914 		thisy += mult(sine(ang), extendt);
915 	}
916 	if (next == total)
917 	{
918 		/* extend "next" 0 degrees forward */
919 		nextx += mult(cosine(angle), extendb);
920 		nexty += mult(sine(angle), extendb);
921 	}
922 
923 	/* compute endpoints of line parallel to and left of center line */
924 	ang = (angle+LEFTANGLE) % 3600;
925 	sin = mult(sine(ang), lwid);   cos = mult(cosine(ang), lwid);
926 	thisxl = thisx + cos;   thisyl = thisy + sin;
927 	nextxl = nextx + cos;   nextyl = nexty + sin;
928 
929 	/* compute endpoints of line parallel to and right of center line */
930 	ang = (angle+RIGHTANGLE) % 3600;
931 	sin = mult(sine(ang), rwid);   cos = mult(cosine(ang), rwid);
932 	thisxr = thisx + cos;   thisyr = thisy + sin;
933 	nextxr = nextx + cos;   nextyr = nexty + sin;
934 
935 	/* determine proper intersection of this and the previous segment */
936 	if (thissg != 0)
937 	{
938 		otherx = list[thissg*2-2];   othery = list[thissg*2-1];
939 		otherang = figureangle(otherx,othery, thisx,thisy);
940 		if (otherang != angle)
941 		{
942 			/* special case for completely orthogonal wires */
943 			if (angle%900 == 0 && otherang%900 == 0)
944 			{
945 				/* Do nonoverlapping extensions */
946 				ang = (otherang+LEFTANGLE) % 3600;
947 				xl = otherx + mult(cosine(ang), lwid);
948 				yl = othery + mult(sine(ang), lwid);
949 				ang = (otherang+RIGHTANGLE) % 3600;
950 				xr = otherx + mult(cosine(ang), rwid);
951 				yr = othery + mult(sine(ang), rwid);
952 				switch (angle)
953 				{
954 					case 0:    thisxr = thisxl = mini(xl,xr);   break;
955 					case 1800: thisxr = thisxl = maxi(xl,xr);   break;
956 					case 900:  thisyr = thisyl = mini(yl,yr);   break;
957 					case 2700: thisyr = thisyl = maxi(yl,yr);   break;
958 				}
959 			} else	      /* NonManhattan */
960 			{
961 				ang = (otherang+LEFTANGLE) % 3600;
962 				(void)intersect(thisx+mult(cosine(ang),lwid), thisy+mult(sine(ang),lwid),
963 					otherang, thisxl,thisyl,angle, &x, &y);
964 				thisxl = x;   thisyl = y;
965 				ang = (otherang+RIGHTANGLE) % 3600;
966 				(void)intersect(thisx+mult(cosine(ang),rwid), thisy+mult(sine(ang),rwid),
967 					otherang, thisxr,thisyr,angle, &x, &y);
968 				thisxr = x;   thisyr = y;
969 			}
970 		}
971 	}
972 
973 	/* determine proper intersection of this and the next segment */
974 	if (next != total)
975 	{
976 		otherx = list[next*2+2];   othery = list[next*2+3];
977 		otherang = figureangle(nextx, nexty, otherx,othery);
978 		if (otherang != angle)
979 		{
980 			/* special case for completely orthogonal wires */
981 			if (angle%900 == 0 && otherang%900 == 0)
982 			{
983 				/* Do nonoverlapping extensions */
984 				ang = (otherang+LEFTANGLE) % 3600;
985 				xl = nextx + mult(cosine(ang), lwid);
986 				yl = nexty + mult(sine(ang), lwid);
987 				ang = (otherang+RIGHTANGLE) % 3600;
988 				xr = nextx + mult(cosine(ang), rwid);
989 				yr = nexty + mult(sine(ang), rwid);
990 				switch (angle)
991 				{
992 					case 0:    nextxr = nextxl = maxi(xl,xr);   break;
993 					case 1800: nextxr = nextxl = mini(xl,xr);   break;
994 					case 900:  nextyr = nextyl = maxi(yl,yr);   break;
995 					case 2700: nextyr = nextyl = mini(yl,yr);   break;
996 				}
997 			} else
998 			{
999 				ang = (otherang+LEFTANGLE) % 3600;
1000 				(void)intersect(nextx+mult(cosine(ang),lwid), nexty+mult(sine(ang),lwid),
1001 					otherang, nextxl,nextyl,angle, &x, &y);
1002 				nextxl = x;   nextyl = y;
1003 				ang = (otherang+RIGHTANGLE) % 3600;
1004 				(void)intersect(nextx+mult(cosine(ang),rwid), nexty+mult(sine(ang),rwid),
1005 					otherang, nextxr,nextyr,angle, &x, &y);
1006 				nextxr = x;   nextyr = y;
1007 			}
1008 		}
1009 	}
1010 
1011 	/* fill the polygon */
1012 	if (poly->limit < 4) (void)extendpolygon(poly, 4);
1013 	poly->xv[0] = thisxl+xoff;   poly->yv[0] = thisyl+yoff;
1014 	poly->xv[1] = thisxr+xoff;   poly->yv[1] = thisyr+yoff;
1015 	poly->xv[2] = nextxr+xoff;   poly->yv[2] = nextyr+yoff;
1016 	poly->xv[3] = nextxl+xoff;   poly->yv[3] = nextyl+yoff;
1017 	poly->count = 4;
1018 
1019 	/* see if the sides of the polygon intersect */
1020 	ang = figureangle(poly->xv[0], poly->yv[0], poly->xv[1], poly->yv[1]);
1021 	angle = figureangle(poly->xv[2], poly->yv[2], poly->xv[3], poly->yv[3]);
1022 	if (intersect(poly->xv[0], poly->yv[0], ang, poly->xv[2], poly->yv[2], angle, &x, &y) >= 0)
1023 	{
1024 		/* lines intersect, see if the point is on one of the lines */
1025 		if (x >= mini(poly->xv[0], poly->xv[1]) && x <= maxi(poly->xv[0], poly->xv[1]) &&
1026 			y >= mini(poly->yv[0], poly->yv[1]) && y <= maxi(poly->yv[0], poly->yv[1]))
1027 		{
1028 			if (abs(x-poly->xv[0])+abs(y-poly->yv[0]) > abs(x-poly->xv[1])+abs(y-poly->yv[1]))
1029 			{
1030 				poly->xv[1] = x;   poly->yv[1] = y;
1031 				poly->xv[2] = poly->xv[3];   poly->yv[2] = poly->yv[3];
1032 			} else
1033 			{
1034 				poly->xv[0] = x;   poly->yv[0] = y;
1035 			}
1036 			poly->count = 3;
1037 		}
1038 	}
1039 
1040 	*lay = &laylist[element].basics;
1041 	poly->style = (*lay)->style;
1042 	if (poly->style == FILLEDRECT) poly->style = FILLED; else
1043 		if (poly->style == CLOSEDRECT) poly->style = CLOSED;
1044 	poly->layer = (*lay)->layernum;
1045 }
1046 
1047 /*
1048  * routine to describe a port in a transistor that may be part of a serpentine
1049  * path.  If the variable "trace" exists on the node, get that x/y/x/y
1050  * information as the centerline of the serpentine path.  The port path
1051  * is shrunk by "diffinset" in the length and is pushed "diffextend" from the centerline.
1052  * The default width of the transistor is "defwid".  The outline is placed
1053  * in the polygon "poly".
1054  * The assumptions about directions are:
1055  * Segments have port 1 to the left, and port 3 to the right of the gate
1056  * trace. Port 0, the "left-hand" end of the gate, appears at the starting
1057  * end of the first trace segment; port 2, the "right-hand" end of the gate,
1058  * appears at the end of the last trace segment.  Port 3 is drawn as a
1059  * reflection of port 1 around the trace.
1060  * The values "diffinset", "diffextend", "defwid", "polyinset", and "polyextend"
1061  * are used to determine the offsets of the ports:
1062  * The poly ports are extended "polyextend" beyond the appropriate end of the trace
1063  * and are inset by "polyinset" from the polysilicon edge.
1064  * The diffusion ports are extended "diffextend" from the polysilicon edge
1065  * and set in "diffinset" from the ends of the trace segment.
1066  */
tech_filltransport(NODEINST * ni,PORTPROTO * pp,POLYGON * poly,XARRAY trans,TECH_NODES * nodedata,INTBIG diffinset,INTBIG diffextend,INTBIG defwid,INTBIG polyinset,INTBIG polyextend)1067 void tech_filltransport(NODEINST *ni, PORTPROTO *pp, POLYGON *poly, XARRAY trans,
1068 	TECH_NODES *nodedata, INTBIG diffinset, INTBIG diffextend, INTBIG defwid,
1069 	INTBIG polyinset, INTBIG polyextend)
1070 {
1071 	REGISTER INTBIG thissg, next, angle, pangle, ang;
1072 	REGISTER INTBIG sin, cos, thisx, thisy, nextx, nexty, pthisx, pthisy;
1073 	INTBIG *list, xoff, yoff, lambda, x, y;
1074 	INTBIG total, which;
1075 	REGISTER VARIABLE *var, *varw;
1076 	REGISTER PORTPROTO *lpp;
1077 
1078 	/* see if the transistor has serpentine information */
1079 	var = gettrace(ni);
1080 	if (var != NOVARIABLE)
1081 	{
1082 		/* trace data is there: make sure there are enough points */
1083 		total = getlength(var);
1084 		if (total <= 2) var = NOVARIABLE;
1085 	}
1086 
1087 	/* nonserpentine transtors fill in the normal way */
1088 	lambda = lambdaofnode(ni);
1089 	if (var == NOVARIABLE)
1090 	{
1091 		tech_fillportpoly(ni, pp, poly, trans, nodedata, -1, lambda);
1092 		return;
1093 	}
1094 
1095 	/* prepare to fill the serpentine transistor port */
1096 	list = (INTBIG *)var->addr;
1097 	poly->style = OPENED;
1098 	xoff = (ni->highx+ni->lowx)/2;
1099 	yoff = (ni->highy+ni->lowy)/2;
1100 	total /= 2;
1101 
1102 	/* see if nonstandard width is specified */
1103 	defwid = lambda * defwid / WHOLE;
1104 	diffinset = lambda * diffinset / WHOLE;   diffextend = lambda * diffextend / WHOLE;
1105 	polyinset = lambda * polyinset / WHOLE;   polyextend = lambda * polyextend / WHOLE;
1106 	varw = getvalkey((INTBIG)ni, VNODEINST, VFRACT, el_transistor_width_key);
1107 	if (varw != NOVARIABLE) defwid = lambda * varw->addr / WHOLE;
1108 
1109 	/* determine which port is being described */
1110 	for(lpp = ni->proto->firstportproto, which=0; lpp != NOPORTPROTO;
1111 		lpp = lpp->nextportproto, which++) if (lpp == pp) break;
1112 
1113 	/* ports 0 and 2 are poly (simple) */
1114 	if (which == 0)
1115 	{
1116 		if (poly->limit < 2) (void)extendpolygon(poly, 2);
1117 		thisx = list[0];   thisy = list[1];
1118 		nextx = list[2];   nexty = list[3];
1119 		angle = figureangle(thisx, thisy, nextx, nexty);
1120 		ang = (angle+1800) % 3600;
1121 		thisx += mult(cosine(ang), polyextend) + xoff;
1122 		thisy += mult(sine(ang), polyextend) + yoff;
1123 		ang = (angle+LEFTANGLE) % 3600;
1124 		nextx = thisx + mult(cosine(ang), defwid/2-polyinset);
1125 		nexty = thisy + mult(sine(ang), defwid/2-polyinset);
1126 		xform(nextx, nexty, &poly->xv[0], &poly->yv[0], trans);
1127 		ang = (angle+RIGHTANGLE) % 3600;
1128 		nextx = thisx + mult(cosine(ang), defwid/2-polyinset);
1129 		nexty = thisy + mult(sine(ang), defwid/2-polyinset);
1130 		xform(nextx, nexty, &poly->xv[1], &poly->yv[1], trans);
1131 		poly->count = 2;
1132 		return;
1133 	}
1134 	if (which == 2)
1135 	{
1136 		if (poly->limit < 2) (void)extendpolygon(poly, 2);
1137 		thisx = list[(total-1)*2];   thisy = list[(total-1)*2+1];
1138 		nextx = list[(total-2)*2];   nexty = list[(total-2)*2+1];
1139 		angle = figureangle(thisx, thisy, nextx, nexty);
1140 		ang = (angle+1800) % 3600;
1141 		thisx += mult(cosine(ang), polyextend) + xoff;
1142 		thisy += mult(sine(ang), polyextend) + yoff;
1143 		ang = (angle+LEFTANGLE) % 3600;
1144 		nextx = thisx + mult(cosine(ang), defwid/2-polyinset);
1145 		nexty = thisy + mult(sine(ang), defwid/2-polyinset);
1146 		xform(nextx, nexty, &poly->xv[0], &poly->yv[0], trans);
1147 		ang = (angle+RIGHTANGLE) % 3600;
1148 		nextx = thisx + mult(cosine(ang), defwid/2-polyinset);
1149 		nexty = thisy + mult(sine(ang), defwid/2-polyinset);
1150 		xform(nextx, nexty, &poly->xv[1], &poly->yv[1], trans);
1151 		poly->count = 2;
1152 		return;
1153 	}
1154 
1155 	/* THE ORIGINAL CODE TREATED PORT 1 AS THE NEGATED PORT ... SRP */
1156 	/* port 3 is the negated path side of port 1 */
1157 	if (which == 3)
1158 	{
1159 		diffextend = -diffextend;
1160 		defwid = -defwid;
1161 	}
1162 
1163 	/* extra port on some n-transistors */
1164 	if (which == 4) diffextend = defwid = 0;
1165 
1166 	/* polygon will need total points */
1167 	if (poly->limit < total) (void)extendpolygon(poly, total);
1168 
1169 	for(next=1; next<total; next++)
1170 	{
1171 		thissg = next-1;
1172 		thisx = list[thissg*2];   thisy = list[thissg*2+1];
1173 		nextx = list[next*2];   nexty = list[next*2+1];
1174 		angle = figureangle(thisx, thisy, nextx, nexty);
1175 
1176 		/* determine the points */
1177 		if (thissg == 0)
1178 		{
1179 			/* extend "thissg" 0 degrees forward */
1180 			thisx += mult(cosine(angle), diffinset);
1181 			thisy += mult(sine(angle), diffinset);
1182 		}
1183 		if (next == total-1)
1184 		{
1185 			/* extend "next" 180 degrees back */
1186 			ang = (angle+1800) % 3600;
1187 			nextx += mult(cosine(ang), diffinset);
1188 			nexty += mult(sine(ang), diffinset);
1189 		}
1190 
1191 		/* compute endpoints of line parallel to center line */
1192 		ang = (angle+LEFTANGLE) % 3600;   sin = sine(ang);   cos = cosine(ang);
1193 		thisx += mult(cos, defwid/2+diffextend);   thisy += mult(sin, defwid/2+diffextend);
1194 		nextx += mult(cos, defwid/2+diffextend);   nexty += mult(sin, defwid/2+diffextend);
1195 
1196 		if (thissg != 0)
1197 		{
1198 			/* compute intersection of this and previous line */
1199 
1200 			/* LINTED "pthisx", "pthisy", and "pangle" used in proper order */
1201 			(void)intersect(pthisx, pthisy, pangle, thisx, thisy, angle, &x, &y);
1202 			thisx = x;   thisy = y;
1203 			xform(thisx+xoff, thisy+yoff, &poly->xv[thissg], &poly->yv[thissg], trans);
1204 		} else
1205 			xform(thisx+xoff, thisy+yoff, &poly->xv[0], &poly->yv[0], trans);
1206 		pthisx = thisx;   pthisy = thisy;
1207 		pangle = angle;
1208 	}
1209 
1210 	xform(nextx+xoff, nexty+yoff, &poly->xv[total-1], &poly->yv[total-1], trans);
1211 	poly->count = total;
1212 }
1213 
1214 /*
1215  * routine to compute the number of displayable polygons on nodeinst "ni"
1216  */
tech_displayablenvars(NODEINST * ni,WINDOWPART * win,POLYLOOP * pl)1217 INTBIG tech_displayablenvars(NODEINST *ni, WINDOWPART *win, POLYLOOP *pl)
1218 {
1219 	pl->numvar = ni->numvar;
1220 	pl->firstvar = ni->firstvar;
1221 	if (ni->proto == gen_invispinprim)
1222 	{
1223 		if ((us_useroptions&HIDETXTNONLAY) != 0) return(0);
1224 	} else
1225 	{
1226 		if ((us_useroptions&HIDETXTNODE) != 0) return(0);
1227 	}
1228 	return(tech_displayableanyvars(win, ni->parent, pl));
1229 }
1230 
1231 /*
1232  * routine to fill polygon "poly" with the next displayable variable
1233  * on nodeinst "ni".  Returns the address of the variable just filled.
1234  */
tech_filldisplayablenvar(NODEINST * ni,POLYGON * poly,WINDOWPART * win,VARIABLE ** varnoeval,POLYLOOP * pl)1235 VARIABLE *tech_filldisplayablenvar(NODEINST *ni, POLYGON *poly, WINDOWPART *win,
1236 	VARIABLE **varnoeval, POLYLOOP *pl)
1237 {
1238 	REGISTER NODEPROTO *cell;
1239 	REGISTER VARIABLE *var;
1240 	REGISTER INTBIG lx, hx, ly, hy;
1241 	INTBIG olx, ohx, oly, ohy;
1242 	REGISTER BOOLEAN oldonobjectstate;
1243 
1244 	/* track which object we are on */
1245 	oldonobjectstate = db_onanobject;
1246 	if (!db_onanobject)
1247 	{
1248 		db_onanobject = TRUE;
1249 		db_onobjectaddr = (INTBIG)ni;
1250 		db_onobjecttype = VNODEINST;
1251 	}
1252 	db_lastonobjectaddr = (INTBIG)ni;
1253 	db_lastonobjecttype = VNODEINST;
1254 
1255 	cell = ni->parent;
1256 	pl->numvar = ni->numvar;
1257 	pl->firstvar = ni->firstvar;
1258 	if (cell->tech == NOTECHNOLOGY)
1259 		cell->tech = whattech(cell);
1260 	lx = ni->lowx;   hx = ni->highx;
1261 	ly = ni->lowy;   hy = ni->highy;
1262 	nodesizeoffset(ni, &olx, &oly, &ohx, &ohy);
1263 	lx += olx;   hx -= ohx;
1264 	ly += oly;   hy -= ohy;
1265 	var = tech_filldisplayableanyvar(poly, lx, hx, ly, hy, (INTBIG)ni, VNODEINST,
1266 		cell->tech, win, cell, varnoeval, pl);
1267 	db_onanobject = oldonobjectstate;
1268 	return(var);
1269 }
1270 
1271 /*
1272  * routine to compute the number of displayable polygons on nodeproto "np"
1273  */
tech_displayablecellvars(NODEPROTO * np,WINDOWPART * win,POLYLOOP * pl)1274 INTBIG tech_displayablecellvars(NODEPROTO *np, WINDOWPART *win, POLYLOOP *pl)
1275 {
1276 	pl->numvar = np->numvar;
1277 	pl->firstvar = np->firstvar;
1278 	if ((us_useroptions&HIDETXTCELL) != 0) return(0);
1279 	return(tech_displayableanyvars(win, np, pl));
1280 }
1281 
1282 /*
1283  * routine to fill polygon "poly" with the next displayable variable
1284  * on nodeproto "np".  Returns the address of the variable just filled.
1285  */
tech_filldisplayablecellvar(NODEPROTO * np,POLYGON * poly,WINDOWPART * win,VARIABLE ** varnoeval,POLYLOOP * pl)1286 VARIABLE *tech_filldisplayablecellvar(NODEPROTO *np, POLYGON *poly, WINDOWPART *win,
1287 	VARIABLE **varnoeval, POLYLOOP *pl)
1288 {
1289 	pl->numvar = np->numvar;
1290 	pl->firstvar = np->firstvar;
1291 	if (np->tech == NOTECHNOLOGY) np->tech = whattech(np);
1292 
1293 	/* cell variables are offset from (0,0) */
1294 	return(tech_filldisplayableanyvar(poly, 0, 0, 0, 0, (INTBIG)np,
1295 		VNODEPROTO, np->tech, win, np, varnoeval, pl));
1296 }
1297 
1298 /******************** PORTINST DESCRIPTION ********************/
1299 
1300 /*
1301  * routine to fill polygon "poly" with the bounding box of port "pp" on
1302  * nodeinst "ni".  The port description should be transformed by "trans"
1303  * and the node is further described by the internal data in "nodedata".
1304  * If "sty" is not -1, the outline is described in trace data on the node.
1305  */
tech_fillportpoly(NODEINST * ni,PORTPROTO * pp,POLYGON * poly,XARRAY trans,TECH_NODES * nodedata,INTBIG sty,INTBIG lambda)1306 void tech_fillportpoly(NODEINST *ni, PORTPROTO *pp, POLYGON *poly, XARRAY trans,
1307 	TECH_NODES *nodedata, INTBIG sty, INTBIG lambda)
1308 {
1309 	REGISTER INTBIG i, count;
1310 	REGISTER INTBIG x, y;
1311 	INTBIG lx, ly, hx, hy;
1312 	REGISTER TECH_PORTS *portdata;
1313 	REGISTER VARIABLE *var;
1314 
1315 	/* if the node has trace data, use it */
1316 	if ((ni->proto->userbits&HOLDSTRACE) != 0)
1317 	{
1318 		var = gettrace(ni);
1319 		if (var != NOVARIABLE)
1320 		{
1321 			count = getlength(var) / 2;
1322 			if (poly->limit < count) (void)extendpolygon(poly, count);
1323 			x = (ni->highx + ni->lowx) / 2;   y = (ni->highy + ni->lowy) / 2;
1324 			for(i=0; i<count; i++)
1325 				xform(((INTBIG *)var->addr)[i*2]+x, ((INTBIG *)var->addr)[i*2+1]+y,
1326 					&poly->xv[i], &poly->yv[i], trans);
1327 			poly->count = count;
1328 			poly->style = sty;
1329 			return;
1330 		}
1331 	}
1332 
1333 	/* find the port to get its boundary information */
1334 	for(i=0; i<nodedata->portcount; i++)
1335 	{
1336 		portdata = &nodedata->portlist[i];
1337 		if (portdata->addr == pp) break;
1338 	}
1339 
1340 	/* get the high/low X/Y of the port area */
1341 	subrange(ni->lowx, ni->highx, portdata->lowxmul, portdata->lowxsum,
1342 		portdata->highxmul, portdata->highxsum, &lx, &hx, lambda);
1343 	subrange(ni->lowy, ni->highy, portdata->lowymul, portdata->lowysum,
1344 		portdata->highymul, portdata->highysum, &ly, &hy, lambda);
1345 
1346 	/* clip to the size of the node */
1347 	if (hx < lx) lx = hx = (lx + hx) / 2;
1348 	if (hy < ly) ly = hy = (ly + hy) / 2;
1349 
1350 	/* transform this into the port polygon description */
1351 	if (poly->limit < 4) (void)extendpolygon(poly, 4);
1352 	xform(lx, ly, &poly->xv[0], &poly->yv[0], trans);
1353 	xform(lx, hy, &poly->xv[1], &poly->yv[1], trans);
1354 	xform(hx, hy, &poly->xv[2], &poly->yv[2], trans);
1355 	xform(hx, ly, &poly->xv[3], &poly->yv[3], trans);
1356 	poly->count = 4;
1357 	poly->style = FILLED;
1358 }
1359 
1360 /*
1361  * routine to tell whether end "e" of arcinst "ai" would be properly connected
1362  * to its nodeinst if it were located at (x, y), but considering the width of
1363  * the arc as a limiting factor.
1364  */
db_stillinport(ARCINST * ai,INTBIG e,INTBIG x,INTBIG y)1365 BOOLEAN db_stillinport(ARCINST *ai, INTBIG e, INTBIG x, INTBIG y)
1366 {
1367 	REGISTER INTBIG wid;
1368 	REGISTER BOOLEAN isin;
1369 	REGISTER POLYGON *poly;
1370 
1371 	/* make sure there is a polygon */
1372 	poly = allocpolygon(4, db_cluster);
1373 
1374 	/* determine the area of the nodeinst */
1375 	shapeportpoly(ai->end[e].nodeinst, ai->end[e].portarcinst->proto, poly, FALSE);
1376 	wid = ai->width - arcwidthoffset(ai);
1377 	reduceportpoly(poly, ai->end[e].nodeinst, ai->end[e].portarcinst->proto, wid,
1378 		(ai->userbits&AANGLE)>>AANGLESH);
1379 	isin = isinside(x, y, poly);
1380 	freepolygon(poly);
1381 	if (isin) return(TRUE);
1382 
1383 	/* no good */
1384 	return(FALSE);
1385 }
1386 
1387 /*
1388  * routine to compute the number of displayable polygons on portproto "pp"
1389  */
tech_displayableportvars(PORTPROTO * pp,WINDOWPART * win,POLYLOOP * pl)1390 INTBIG tech_displayableportvars(PORTPROTO *pp, WINDOWPART *win, POLYLOOP *pl)
1391 {
1392 	pl->numvar = pp->numvar;
1393 	pl->firstvar = pp->firstvar;
1394 	if ((us_useroptions&HIDETXTEXPORT) != 0) return(0);
1395 	return(tech_displayableanyvars(win, pp->parent, pl));
1396 }
1397 
1398 /*
1399  * routine to fill polygon "poly" with the next displayable variable
1400  * on nodeproto "np".  Returns the address of the variable just filled.
1401  */
tech_filldisplayableportvar(PORTPROTO * pp,POLYGON * poly,WINDOWPART * win,VARIABLE ** varnoeval,POLYLOOP * pl)1402 VARIABLE *tech_filldisplayableportvar(PORTPROTO *pp, POLYGON *poly, WINDOWPART *win,
1403 	VARIABLE **varnoeval, POLYLOOP *pl)
1404 {
1405 	INTBIG x, y;
1406 	REGISTER INTSML saverot, savetrn;
1407 	REGISTER NODEINST *ni;
1408 	REGISTER NODEPROTO *cell;
1409 
1410 	cell = pp->parent;
1411 	ni = pp->subnodeinst;
1412 	saverot = ni->rotation;   savetrn = ni->transpose;
1413 	ni->rotation = ni->transpose = 0;
1414 	portposition(ni, pp->subportproto, &x, &y);
1415 	ni->rotation = saverot;   ni->transpose = savetrn;
1416 	pl->numvar = pp->numvar;
1417 	pl->firstvar = pp->firstvar;
1418 	if (cell->tech == NOTECHNOLOGY)
1419 		cell->tech = whattech(cell);
1420 	return(tech_filldisplayableanyvar(poly, x, x, y, y,
1421 		(INTBIG)pp, VPORTPROTO, cell->tech, win, cell, varnoeval, pl));
1422 }
1423 
1424 /******************** ARCINST DESCRIPTION ********************/
1425 
1426 /*
1427  * routine to handle initialization of arcs that are curved.  Decomposition
1428  * into segments is necessary when arcs have a nonzero width.  The routine
1429  * returns the number of polygons that make up arc "ai".  For straight
1430  * cases, there are "total" polygons and for curved cases, the true value is
1431  * computed.
1432  */
tech_initcurvedarc(ARCINST * ai,INTBIG total,POLYLOOP * pl)1433 INTBIG tech_initcurvedarc(ARCINST *ai, INTBIG total, POLYLOOP *pl)
1434 {
1435 	REGISTER INTBIG i;
1436 	INTBIG x1, y1, x2, y2;
1437 	REGISTER VARIABLE *var;
1438 
1439 	/* by default, set flag for straight arc */
1440 	pl->arcpieces = 0;
1441 
1442 	/* see if there is radius information on the arc */
1443 	var = getvalkey((INTBIG)ai, VARCINST, VINTEGER, el_arc_radius_key);
1444 	if (var == NOVARIABLE) return(total);
1445 
1446 	/* get the radius of the circle, check for validity */
1447 	pl->radius = var->addr;
1448 	if (abs(pl->radius)*2 < ai->length) return(total);
1449 
1450 	/* determine the center of the circle */
1451 	if (findcenters(abs(pl->radius), ai->end[0].xpos, ai->end[0].ypos,
1452 		ai->end[1].xpos, ai->end[1].ypos, ai->length, &x1,&y1, &x2,&y2))
1453 			return(total);
1454 
1455 	if (pl->radius < 0)
1456 	{
1457 		pl->radius = -pl->radius;
1458 		pl->centerx = x1;   pl->centery = y1;
1459 	} else
1460 	{
1461 		pl->centerx = x2;   pl->centery = y2;
1462 	}
1463 
1464 	/* special case for zero-width arcs */
1465 	if (ai->width == 0)
1466 	{
1467 		pl->arcpieces = -1;
1468 		return(total);
1469 	}
1470 
1471 	/* determine the base and range of angles */
1472 	pl->anglebase = figureangle(pl->centerx, pl->centery, ai->end[0].xpos, ai->end[0].ypos);
1473 	pl->anglerange = figureangle(pl->centerx, pl->centery, ai->end[1].xpos, ai->end[1].ypos);
1474 	if ((ai->userbits&REVERSEEND) != 0)
1475 	{
1476 		i = pl->anglebase;
1477 		pl->anglebase = pl->anglerange;
1478 		pl->anglerange = i;
1479 	}
1480 	pl->anglerange -= pl->anglebase;
1481 	if (pl->anglerange < 0) pl->anglerange += 3600;
1482 
1483 	/* determine the number of intervals to use for the arc */
1484 	pl->arcpieces = pl->anglerange;
1485 	while (pl->arcpieces > MAXARCPIECES) pl->arcpieces /= 2;
1486 	return(pl->arcpieces*total);
1487 }
1488 
1489 /*
1490  * routine to generate piece "box" of curved arc "ai" and put it in "poly".
1491  * The arc prototype structure is in "arcprotos".  The routine returns false
1492  * if successful, true if the arc is not curved.
1493  */
tech_curvedarcpiece(ARCINST * ai,INTBIG box,POLYGON * poly,TECH_ARCS ** arcprotos,POLYLOOP * pl)1494 BOOLEAN tech_curvedarcpiece(ARCINST *ai, INTBIG box, POLYGON *poly, TECH_ARCS **arcprotos,
1495 	POLYLOOP *pl)
1496 {
1497 	REGISTER INTBIG a;
1498 	REGISTER INTBIG aindex, sin, cos, innerradius, outerradius, wid;
1499 	REGISTER TECH_ARCLAY *thista;
1500 
1501 	if (pl->arcpieces == 0) return(TRUE);
1502 
1503 	aindex = ai->proto->arcindex;
1504 
1505 	/* handle zero-width arcs as a true arc polygon */
1506 	if (pl->arcpieces < 0)
1507 	{
1508 		/* initialize the polygon */
1509 		if (poly->limit < 3) (void)extendpolygon(poly, 3);
1510 		poly->count = 3;
1511 		poly->style = CIRCLEARC;
1512 		thista = &arcprotos[aindex]->list[box];
1513 		poly->layer = thista->lay;
1514 		poly->xv[0] = pl->centerx;
1515 		poly->yv[0] = pl->centery;
1516 		if ((ai->userbits&REVERSEEND) == 0)
1517 		{
1518 			poly->xv[1] = ai->end[1].xpos;
1519 			poly->yv[1] = ai->end[1].ypos;
1520 			poly->xv[2] = ai->end[0].xpos;
1521 			poly->yv[2] = ai->end[0].ypos;
1522 		} else
1523 		{
1524 			poly->xv[1] = ai->end[0].xpos;
1525 			poly->yv[1] = ai->end[0].ypos;
1526 			poly->xv[2] = ai->end[1].xpos;
1527 			poly->yv[2] = ai->end[1].ypos;
1528 		}
1529 		return(FALSE);
1530 	}
1531 
1532 	/* nonzero width arcs are described in segments */
1533 	thista = &arcprotos[aindex]->list[box/pl->arcpieces];
1534 	box = box % pl->arcpieces;
1535 
1536 	/* initialize the polygon */
1537 	if (poly->limit < 4) (void)extendpolygon(poly, 4);
1538 	poly->count = 4;
1539 	poly->style = thista->style;
1540 	poly->layer = thista->lay;
1541 
1542 	/* get the inner and outer radii of the arc */
1543 	wid = ai->width - thista->off * lambdaofarc(ai) / WHOLE;
1544 	outerradius = pl->radius + wid / 2;
1545 	innerradius = outerradius - wid;
1546 
1547 	/* fill the polygon */
1548 	a = (pl->anglebase + box * pl->anglerange / pl->arcpieces) % 3600;
1549 	sin = sine(a);   cos = cosine(a);
1550 	poly->xv[0] = mult(cos, innerradius) + pl->centerx;
1551 	poly->yv[0] = mult(sin, innerradius) + pl->centery;
1552 	poly->xv[1] = mult(cos, outerradius) + pl->centerx;
1553 	poly->yv[1] = mult(sin, outerradius) + pl->centery;
1554 	a = (pl->anglebase + (box+1) * pl->anglerange / pl->arcpieces) % 3600;
1555 	sin = sine(a);   cos = cosine(a);
1556 	poly->xv[2] = mult(cos, outerradius) + pl->centerx;
1557 	poly->yv[2] = mult(sin, outerradius) + pl->centery;
1558 	poly->xv[3] = mult(cos, innerradius) + pl->centerx;
1559 	poly->yv[3] = mult(sin, innerradius) + pl->centery;
1560 	return(FALSE);
1561 }
1562 
1563 /*
1564  * routine to draw a directional arrow in "poly" for arc "ai"
1565  */
tech_makearrow(ARCINST * ai,POLYGON * poly)1566 void tech_makearrow(ARCINST *ai, POLYGON *poly)
1567 {
1568 	REGISTER INTBIG x1, y1, x2, y2, swap;
1569 	REGISTER INTBIG angle;
1570 
1571 	x1 = ai->end[0].xpos;   y1 = ai->end[0].ypos;
1572 	x2 = ai->end[1].xpos;   y2 = ai->end[1].ypos;
1573 	angle = ((ai->userbits&AANGLE) >> AANGLESH) * 10;
1574 	if ((ai->userbits&REVERSEEND) != 0)
1575 	{
1576 		swap = x1;   x1 = x2;   x2 = swap;
1577 		swap = y1;   y1 = y2;   y2 = swap;
1578 		angle = (angle+1800) % 3600;
1579 	}
1580 	if (poly->limit < 2) (void)extendpolygon(poly, 2);
1581 	poly->style = VECTORS;
1582 	poly->layer = -1;
1583 	poly->desc = &tech_arrow;
1584 	tech_arrow.col = el_colcell;
1585 	poly->count = 2;
1586 	poly->xv[0] = x1;   poly->yv[0] = y1;
1587 	poly->xv[1] = x2;   poly->yv[1] = y2;
1588 	if ((ai->userbits&NOTEND1) == 0) tech_addheadarrow(poly, angle, x2, y2,
1589 		lambdaofarc(ai));
1590 }
1591 
1592 /*
1593  * helper routine to add an arrow head to the arc in "poly", given that
1594  * the arc runs from (x,y) and is at an angle of "angle" tenth-degrees
1595  */
tech_addheadarrow(POLYGON * poly,INTBIG angle,INTBIG x,INTBIG y,INTBIG lambda)1596 void tech_addheadarrow(POLYGON *poly, INTBIG angle, INTBIG x, INTBIG y, INTBIG lambda)
1597 {
1598 	REGISTER INTBIG c;
1599 	REGISTER INTBIG dist;
1600 
1601 	c = poly->count;
1602 	if (poly->limit < c+4) (void)extendpolygon(poly, c+4);
1603 	dist = K1 * lambda / WHOLE;
1604 	poly->xv[c] = x;    poly->yv[c] = y;   c++;
1605 	poly->xv[c] = x + mult(cosine((angle+1500) % 3600), dist);
1606 	poly->yv[c] = y + mult(sine((angle+1500) % 3600), dist);   c++;
1607 	poly->xv[c] = x;    poly->yv[c] = y;   c++;
1608 	poly->xv[c] = x + mult(cosine((angle+2100) % 3600), dist);
1609 	poly->yv[c] = y + mult(sine((angle+2100) % 3600), dist);   c++;
1610 	poly->count = c;
1611 }
1612 
1613 /*
1614  * helper routine to add an arrow head to the arc in "poly", given that
1615  * the arc runs from (x,y), is "width" wide, and is at an angle of "angle"
1616  * tenth-degrees.  The body of the arc is a double-line so the end must be shortened
1617  * too.
1618  */
tech_adddoubleheadarrow(POLYGON * poly,INTBIG angle,INTBIG * x,INTBIG * y,INTBIG width)1619 void tech_adddoubleheadarrow(POLYGON *poly, INTBIG angle, INTBIG *x,INTBIG *y, INTBIG width)
1620 {
1621 	REGISTER INTBIG c, a;
1622 
1623 	c = poly->count;
1624 	if (poly->limit < c+4) (void)extendpolygon(poly, c+4);
1625 	poly->xv[c] = *x;   poly->yv[c] = *y;   c++;
1626 	a = (angle + 1350) % 3600;
1627 	poly->xv[c] = *x + mult(cosine(a), width*2);
1628 	poly->yv[c] = *y + mult(sine(a), width*2);   c++;
1629 
1630 	poly->xv[c] = *x;   poly->yv[c] = *y;   c++;
1631 	a = (angle + 2250) % 3600;
1632 	poly->xv[c] = *x + mult(cosine(a), width*2);
1633 	poly->yv[c] = *y + mult(sine(a), width*2);   c++;
1634 
1635 	a = (angle + 1800) % 3600;
1636 	*x += mult(cosine(a), width);
1637 	*y += mult(sine(a), width);
1638 	poly->count = c;
1639 }
1640 
1641 /*
1642  * helper routine to add a double-line body to the arc in "poly", given that
1643  * the arc runs from (x1,y1) to (x2,y2), is "width" wide, and is at an angle
1644  * of "angle" tenth-degrees.
1645  */
tech_add2linebody(POLYGON * poly,INTBIG angle,INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2,INTBIG width)1646 void tech_add2linebody(POLYGON *poly, INTBIG angle, INTBIG x1, INTBIG y1, INTBIG x2,
1647 	INTBIG y2, INTBIG width)
1648 {
1649 	REGISTER INTBIG c;
1650 	REGISTER INTBIG sin, cos;
1651 
1652 	c = poly->count;
1653 	if (poly->limit < c+4) (void)extendpolygon(poly, c+4);
1654 	cos = cosine((angle+900) % 3600);
1655 	sin = sine((angle+900) % 3600);
1656 	poly->xv[c] = x1 + mult(cos, width);
1657 	poly->yv[c] = y1 + mult(sin, width);   c++;
1658 	poly->xv[c] = x2 + mult(cos, width);
1659 	poly->yv[c] = y2 + mult(sin, width);   c++;
1660 	cos = cosine((angle+2700) % 3600);
1661 	sin = sine((angle+2700) % 3600);
1662 	poly->xv[c] = x1 + mult(cos, width);
1663 	poly->yv[c] = y1 + mult(sin, width);   c++;
1664 	poly->xv[c] = x2 + mult(cos, width);
1665 	poly->yv[c] = y2 + mult(sin, width);   c++;
1666 	poly->count = c;
1667 }
1668 
1669 /*
1670  * routine to build a polygon "poly" that describes an arc.  The arc is "len"
1671  * long and "wid" wide and runs at "angle" tenths of a degree.  The two points
1672  * (x1,y1) and (x2,y2) are at the ends of this arc.  There is an extension of
1673  * "e1" on end 1 and "e2" on end 2 (a value typically ranging from 0 to half of
1674  * the width).
1675  */
tech_makeendpointpoly(INTBIG len,INTBIG wid,INTBIG angle,INTBIG x1,INTBIG y1,INTBIG e1,INTBIG x2,INTBIG y2,INTBIG e2,POLYGON * poly)1676 void tech_makeendpointpoly(INTBIG len, INTBIG wid, INTBIG angle, INTBIG x1, INTBIG y1, INTBIG e1,
1677 	INTBIG x2, INTBIG y2, INTBIG e2, POLYGON *poly)
1678 {
1679 	REGISTER INTBIG temp, xextra, yextra, xe1, ye1, xe2, ye2, w2, sa, ca;
1680 
1681 	if (poly->limit < 4) (void)extendpolygon(poly, 4);
1682 	poly->count = 4;
1683 	w2 = wid / 2;
1684 
1685 	/* somewhat simpler if rectangle is manhattan */
1686 	if (angle == 900 || angle == 2700)
1687 	{
1688 		if (y1 > y2)
1689 		{
1690 			temp = y1;   y1 = y2;   y2 = temp;
1691 			temp = e1;   e1 = e2;   e2 = temp;
1692 		}
1693 		poly->xv[0] = x1 - w2;   poly->yv[0] = y1 - e1;
1694 		poly->xv[1] = x1 + w2;   poly->yv[1] = y1 - e1;
1695 		poly->xv[2] = x2 + w2;   poly->yv[2] = y2 + e2;
1696 		poly->xv[3] = x2 - w2;   poly->yv[3] = y2 + e2;
1697 		return;
1698 	}
1699 	if (angle == 0 || angle == 1800)
1700 	{
1701 		if (x1 > x2)
1702 		{
1703 			temp = x1;   x1 = x2;   x2 = temp;
1704 			temp = e1;   e1 = e2;   e2 = temp;
1705 		}
1706 		poly->xv[0] = x1 - e1;   poly->yv[0] = y1 - w2;
1707 		poly->xv[1] = x1 - e1;   poly->yv[1] = y1 + w2;
1708 		poly->xv[2] = x2 + e2;   poly->yv[2] = y2 + w2;
1709 		poly->xv[3] = x2 + e2;   poly->yv[3] = y2 - w2;
1710 		return;
1711 	}
1712 
1713 	/* nonmanhattan arcs cannot have zero length so re-compute it */
1714 	if (len == 0) len = computedistance(x1,y1, x2,y2);
1715 	if (len == 0)
1716 	{
1717 		sa = sine(angle);
1718 		ca = cosine(angle);
1719 		xe1 = x1 - mult(ca, e1);
1720 		ye1 = y1 - mult(sa, e1);
1721 		xe2 = x2 + mult(ca, e2);
1722 		ye2 = y2 + mult(sa, e2);
1723 		xextra = mult(ca, w2);
1724 		yextra = mult(sa, w2);
1725 	} else
1726 	{
1727 		/* work out all the math for nonmanhattan arcs */
1728 		xe1 = x1 - muldiv(e1, (x2-x1), len);
1729 		ye1 = y1 - muldiv(e1, (y2-y1), len);
1730 		xe2 = x2 + muldiv(e2, (x2-x1), len);
1731 		ye2 = y2 + muldiv(e2, (y2-y1), len);
1732 
1733 		/* now compute the corners */
1734 		xextra = muldiv(w2, (x2-x1), len);
1735 		yextra = muldiv(w2, (y2-y1), len);
1736 	}
1737 
1738 	poly->xv[0] = yextra + xe1;   poly->yv[0] = ye1 - xextra;
1739 	poly->xv[1] = xe1 - yextra;   poly->yv[1] = xextra + ye1;
1740 	poly->xv[2] = xe2 - yextra;   poly->yv[2] = xextra + ye2;
1741 	poly->xv[3] = yextra + xe2;   poly->yv[3] = ye2 - xextra;
1742 }
1743 
1744 /*
1745  * routine to reset the ISNEGATED bit on arc "ai" because it is in a
1746  * layout technology and shouldn't ought to be set
1747  */
tech_resetnegated(ARCINST * ai)1748 void tech_resetnegated(ARCINST *ai)
1749 {
1750 	ttyputmsg(_("Warning: arc %s cannot be negated: state reset"), describearcinst(ai));
1751 	ai->userbits &= ~ISNEGATED;
1752 }
1753 
1754 /*
1755  * routine to compute the number of displayable polygons on arcinst "ai"
1756  */
tech_displayableavars(ARCINST * ai,WINDOWPART * win,POLYLOOP * pl)1757 INTBIG tech_displayableavars(ARCINST *ai, WINDOWPART *win, POLYLOOP *pl)
1758 {
1759 	pl->numvar = ai->numvar;
1760 	pl->firstvar = ai->firstvar;
1761 	if ((us_useroptions&HIDETXTARC) != 0) return(0);
1762 	return(tech_displayableanyvars(win, ai->parent, pl));
1763 }
1764 
1765 /*
1766  * routine to fill polygon "poly" with the next displayable variable
1767  * on arcinst "ai".  Returns the address of the variable just filled.
1768  */
tech_filldisplayableavar(ARCINST * ai,POLYGON * poly,WINDOWPART * win,VARIABLE ** varnoeval,POLYLOOP * pl)1769 VARIABLE *tech_filldisplayableavar(ARCINST *ai, POLYGON *poly, WINDOWPART *win,
1770 	VARIABLE **varnoeval, POLYLOOP *pl)
1771 {
1772 	REGISTER NODEPROTO *cell;
1773 	REGISTER VARIABLE *var;
1774 	REGISTER BOOLEAN oldonobjectstate;
1775 
1776 	/* track which object we are on */
1777 	oldonobjectstate = db_onanobject;
1778 	if (!db_onanobject)
1779 	{
1780 		db_onanobject = TRUE;
1781 		db_onobjectaddr = (INTBIG)ai;
1782 		db_onobjecttype = VARCINST;
1783 	}
1784 	db_lastonobjectaddr = (INTBIG)ai;
1785 	db_lastonobjecttype = VARCINST;
1786 
1787 	cell = ai->parent;
1788 	pl->numvar = ai->numvar;
1789 	pl->firstvar = ai->firstvar;
1790 	if (cell->tech == NOTECHNOLOGY)
1791 		cell->tech = whattech(cell);
1792 	var = tech_filldisplayableanyvar(poly, ai->geom->lowx, ai->geom->highx,
1793 		ai->geom->lowy, ai->geom->highy, (INTBIG)ai, VARCINST, cell->tech,
1794 			win, cell, varnoeval, pl);
1795 	db_onanobject = oldonobjectstate;
1796 	return(var);
1797 }
1798 
1799 /******************** SUPPORT ********************/
1800 
1801 /*
1802  * routine to compute the number of displayable polygons in the pair "tech_numvar/
1803  * tech_firstvar"
1804  */
tech_displayableanyvars(WINDOWPART * win,NODEPROTO * cell,POLYLOOP * pl)1805 INTBIG tech_displayableanyvars(WINDOWPART *win, NODEPROTO *cell, POLYLOOP *pl)
1806 {
1807 	REGISTER INTBIG i, total;
1808 	REGISTER VARIABLE *var;
1809 
1810 	pl->ndisplayindex = pl->ndisplaysubindex = total = 0;
1811 	if (win == NOWINDOWPART) win = el_curwindowpart;
1812 	for(i = 0; i < pl->numvar; i++)
1813 	{
1814 		var = &pl->firstvar[i];
1815 		if ((var->type&VDISPLAY) == 0) continue;
1816 		if (TDGETINTERIOR(var->textdescript) != 0 ||
1817 			TDGETINHERIT(var->textdescript) != 0)
1818 		{
1819 			if (win != NOWINDOWPART && cell != win->curnodeproto) continue;
1820 		}
1821 		if ((var->type&VISARRAY) == 0) total++; else
1822 			total += getlength(var);
1823 	}
1824 	return(total);
1825 }
1826 
1827 /*
1828  * routine to fill polygon "poly" with the next displayable variable
1829  * on nodeinst "ni".  Returns the address of the variable just filled.
1830  */
tech_filldisplayableanyvar(POLYGON * poly,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy,INTBIG addr,INTBIG type,TECHNOLOGY * tech,WINDOWPART * win,NODEPROTO * cell,VARIABLE ** varnoeval,POLYLOOP * pl)1831 VARIABLE *tech_filldisplayableanyvar(POLYGON *poly, INTBIG lx, INTBIG hx,
1832 	INTBIG ly, INTBIG hy, INTBIG addr, INTBIG type, TECHNOLOGY *tech,
1833 		WINDOWPART *win, NODEPROTO *cell, VARIABLE **varnoeval, POLYLOOP *pl)
1834 {
1835 	REGISTER INTBIG len, language, whichindex;
1836 	UINTBIG descript[TEXTDESCRIPTSIZE];
1837 	REGISTER CHAR *query;
1838 	REGISTER VARIABLE *var, *retvar;
1839 	REGISTER NODEINST *ni;
1840 	REGISTER WINDOWPART *oldwin;
1841 
1842 	/* get next displayable variable */
1843 	if (varnoeval != 0)
1844 		(*varnoeval) = NOVARIABLE;
1845 	if (win == NOWINDOWPART) win = el_curwindowpart;
1846 	oldwin = setvariablewindow(win);
1847 	poly->count = 1;
1848 	poly->xv[0] = (lx+hx)/2;
1849 	poly->yv[0] = (ly+hy)/2;
1850 	poly->style = CROSS;
1851 	for(;;)
1852 	{
1853 		if (pl->ndisplayindex >= pl->numvar)
1854 		{
1855 			TDCLEAR(descript);
1856 			poly->string = x_("ERROR");
1857 			var = NOVARIABLE;
1858 			break;
1859 		}
1860 		var = &pl->firstvar[pl->ndisplayindex];
1861 		if (varnoeval != 0)
1862 			(*varnoeval) = var;
1863 		if ((var->type&VDISPLAY) != 0 &&
1864 			((TDGETINTERIOR(var->textdescript) == 0 && TDGETINHERIT(var->textdescript) == 0) ||
1865 				win == NOWINDOWPART ||
1866 					cell == win->curnodeproto))
1867 		{
1868 			TDCOPY(descript, var->textdescript);
1869 			language = var->type & (VCODE1|VCODE2);
1870 			if (language != 0)
1871 			{
1872 				if ((var->type&VISARRAY) == 0) query = (CHAR *)var->addr; else
1873 					query = ((CHAR **)var->addr)[0];
1874 				retvar = doquerry(query, language, var->type & ~(VCODE1|VCODE2|VISARRAY|VLENGTH));
1875 				if (retvar != NOVARIABLE)
1876 				{
1877 					TDCOPY(retvar->textdescript, descript);
1878 					retvar->key = var->key;
1879 					var = retvar;
1880 				}
1881 			}
1882 			if ((var->type&VISARRAY) == 0)
1883 			{
1884 				pl->ndisplayindex++;
1885 				pl->ndisplaysubindex = 0;
1886 				if (TDGETPOS(descript) == VTPOSBOXED)
1887 				{
1888 					makerectpoly(lx, hx, ly, hy, poly);
1889 					poly->style = CLOSED;
1890 				}
1891 				poly->string = describedisplayedvariable(var, -1, -1);
1892 				break;
1893 			}
1894 			len = getlength(var);
1895 			if (pl->ndisplaysubindex < len)
1896 			{
1897 				whichindex = pl->ndisplaysubindex++;
1898 				poly->string = describedisplayedvariable(var, whichindex, -1);
1899 				if (TDGETPOS(descript) == VTPOSBOXED)
1900 				{
1901 					makerectpoly(lx, hx, ly, hy, poly);
1902 					poly->style = CLOSED;
1903 				} else
1904 				{
1905 					if (type == VNODEINST)
1906 					{
1907 						/* multiline variables only work on nodes! */
1908 						ni = (NODEINST *)addr;
1909 						if (win == NOWINDOWPART) win = el_curwindowpart;
1910 						getdisparrayvarlinepos((INTBIG)ni, VNODEINST, tech, win, var,
1911 							whichindex, &poly->xv[0], &poly->yv[0], FALSE);
1912 					}
1913 				}
1914 				break;
1915 			}
1916 		}
1917 		pl->ndisplayindex++;
1918 		pl->ndisplaysubindex = 0;
1919 	}
1920 
1921 	adjustdisoffset(addr, type, tech, poly, descript);
1922 	poly->desc = &tech_vartxt;
1923 	tech_vartxt.col = el_colcelltxt;
1924 	poly->layer = -1;
1925 	(void)setvariablewindow(oldwin);
1926 	return(var);
1927 }
1928