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)¢erlist[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