1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: dblibrary.c
6 * Database library and lambda control module
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 "network.h"
35
36 /* prototypes for local routines */
37 static void db_scalecell(NODEPROTO*, INTBIG, TECHNOLOGY**, INTBIG*);
38 static void db_validatearcinst(ARCINST*);
39 static void db_setarcinst(ARCINST*, INTBIG, INTBIG, INTBIG, INTBIG);
40 static INTBIG db_scaleunits(INTBIG *value, INTBIG num, INTBIG den);
41 static void db_scalearcinst(ARCINST *ai, INTBIG num, INTBIG denom);
42 static void db_scalenodeinst(NODEINST *ni, INTBIG num, INTBIG denom);
43
44 /****************************** LIBRARIES ******************************/
45
46 /*
47 * routine to allocate a library, places it in its own cluster, and return its
48 * address. The routine returns NOLIBRARY if allocation fails.
49 */
alloclibrary(void)50 LIBRARY *alloclibrary(void)
51 {
52 REGISTER LIBRARY *lib;
53 REGISTER TECHNOLOGY *tech;
54 REGISTER CLUSTER *cluster;
55
56 cluster = alloccluster(x_(""));
57 if (cluster == NOCLUSTER) return((LIBRARY *)db_error(DBNOMEM|DBALLOCLIBRARY));
58 lib = (LIBRARY *)emalloc((sizeof (LIBRARY)), cluster);
59 if (lib == 0) return((LIBRARY *)db_error(DBNOMEM|DBALLOCLIBRARY));
60 lib->cluster = cluster;
61
62 /* allocate space for lambda array */
63 lib->lambda = emalloc(((el_maxtech+1) * SIZEOFINTBIG), cluster);
64 if (lib->lambda == 0) return((LIBRARY *)db_error(DBNOMEM|DBALLOCLIBRARY));
65 lib->lambda[el_maxtech] = -1;
66
67 lib->userbits = lib->temp1 = lib->temp2 = 0;
68 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
69 {
70 if (el_curlib == NOLIBRARY)
71 {
72 lib->lambda[tech->techindex] = tech->deflambda;
73 } else
74 {
75 lib->lambda[tech->techindex] = el_curlib->lambda[tech->techindex];
76 }
77 }
78 lib->numvar = 0;
79 lib->libname = NOSTRING;
80 lib->libfile = NOSTRING;
81 lib->firstvar = NOVARIABLE;
82 lib->firstnodeproto = NONODEPROTO;
83 lib->tailnodeproto = NONODEPROTO;
84 lib->curnodeproto = NONODEPROTO;
85 lib->nextlibrary = NOLIBRARY;
86 lib->numnodeprotos = 0;
87 lib->nodeprotohashtablesize = 0;
88 lib->freenetwork = NONETWORK;
89 return(lib);
90 }
91
92 /*
93 * routine to return library "lib" to the pool of free libraries
94 */
freelibrary(LIBRARY * lib)95 void freelibrary(LIBRARY *lib)
96 {
97 REGISTER CLUSTER *clus;
98 REGISTER NETWORK *net, *nextnet;
99
100 if (lib == NOLIBRARY) return;
101 if (lib->numvar != 0) db_freevars(&lib->firstvar, &lib->numvar);
102 efree((CHAR *)lib->lambda);
103 if (lib->nodeprotohashtablesize > 0)
104 {
105 efree((CHAR *)lib->nodeprotohashtable);
106 efree((CHAR *)lib->nodeprotoviewhashtable);
107 }
108 for(net = lib->freenetwork; net != NONETWORK; net = nextnet)
109 {
110 nextnet = net->nextnetwork;
111 if (net->arctotal != 0) efree((CHAR *)net->arcaddr);
112 efree((CHAR *)net);
113 }
114 clus = lib->cluster;
115 efree((CHAR *)lib);
116 freecluster(clus);
117 }
118
119 /*
120 * routine to create a new library and return its address. The library name
121 * is "name" and its disk file is "file". If there is any error, NOLIBRARY
122 * is returned.
123 */
newlibrary(CHAR * name,CHAR * file)124 LIBRARY *newlibrary(CHAR *name, CHAR *file)
125 {
126 REGISTER LIBRARY *lib;
127 REGISTER CHAR *ch, nc;
128 REGISTER BOOLEAN renamed;
129
130 /* error checks */
131 renamed = FALSE;
132 for(ch = name; *ch != 0; ch++)
133 {
134 nc = *ch;
135 if (nc == ' ') nc = '-';
136 if (nc == '\t' || nc == ':') nc = '-';
137 if (nc != *ch) renamed = TRUE;
138 *ch = nc;
139 }
140 if (renamed) ttyputerr(_("Warning: library renamed to '%s'"), name);
141 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
142 if (namesame(name, lib->libname) == 0)
143 return((LIBRARY *)db_error(DBBADLIB|DBNEWLIBRARY));
144
145 /* create the library */
146 lib = alloclibrary();
147 if (lib == NOLIBRARY) return((LIBRARY *)db_error(DBNOMEM|DBNEWLIBRARY));
148 (void)estrcpy(lib->cluster->clustername, x_("lib:"));
149 (void)estrncpy(&lib->cluster->clustername[4], name, 25);
150
151 /* set library name and file */
152 if (allocstring(&lib->libname, name, lib->cluster)) return(NOLIBRARY);
153 if (allocstring(&lib->libfile, file, lib->cluster)) return(NOLIBRARY);
154
155 /* set units */
156 lib->userbits |= (((el_units & INTERNALUNITS) >> INTERNALUNITSSH) << LIBUNITSSH);
157
158 /* link in the new library after the current library */
159 if (el_curlib == NOLIBRARY)
160 {
161 /* this is the first library: make it the current one */
162 lib->nextlibrary = NOLIBRARY;
163 el_curlib = lib;
164 } else
165 {
166 /* add this library to the list headed by "el_curlib" */
167 lib->nextlibrary = el_curlib->nextlibrary;
168 el_curlib->nextlibrary = lib;
169 }
170
171 /* tell constraint system about new library */
172 (*el_curconstraint->newlib)(lib);
173
174 /* mark a change to the database */
175 db_changetimestamp++;
176
177 /* report library address */
178 return(lib);
179 }
180
181 /*
182 * routine to set the current library (represented by the global "el_curlib")
183 * to "lib"
184 */
selectlibrary(LIBRARY * lib,BOOLEAN changelambda)185 void selectlibrary(LIBRARY *lib, BOOLEAN changelambda)
186 {
187 REGISTER LIBRARY *l, *lastlib;
188 REGISTER TECHNOLOGY *tech;
189
190 /* quit if already done */
191 if (lib == NOLIBRARY) return;
192 if (el_curlib == lib) return;
193
194 /* unlink library from its current position */
195 lastlib = NOLIBRARY;
196 for(l = el_curlib; l != NOLIBRARY; l = l->nextlibrary)
197 {
198 if (l == lib) break;
199 lastlib = l;
200 }
201 if (lastlib != NOLIBRARY) lastlib->nextlibrary = lib->nextlibrary;
202
203 /* link in at the head of the list */
204 lib->nextlibrary = el_curlib;
205 el_curlib = lib;
206
207 if (changelambda)
208 {
209 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
210 changetechnologylambda(tech, el_curlib->lambda[tech->techindex]);
211 }
212
213 /* mark a change to the database */
214 db_changetimestamp++;
215 }
216
killlibrary(LIBRARY * lib)217 void killlibrary(LIBRARY *lib)
218 {
219 REGISTER LIBRARY *l, *lastlib;
220
221 if (lib == el_curlib)
222 {
223 (void)db_error(DBBADLIB|DBKILLLIBRARY);
224 return;
225 }
226
227 /* tell constraint system about killed library */
228 (*el_curconstraint->killlib)(lib);
229
230 /* unlink current library */
231 lastlib = NOLIBRARY;
232 for(l = el_curlib; l != NOLIBRARY; l = l->nextlibrary)
233 {
234 if (l == lib) break;
235 lastlib = l;
236 }
237 if (lastlib != NOLIBRARY) lastlib->nextlibrary = lib->nextlibrary;
238
239 /* kill the requested library */
240 eraselibrary(lib);
241 efree(lib->libfile);
242 efree(lib->libname);
243 freelibrary(lib);
244 }
245
246 /*
247 * routine to erase the contents of a library of cells.
248 * The index of the library is in "libindex".
249 */
eraselibrary(LIBRARY * lib)250 void eraselibrary(LIBRARY *lib)
251 {
252 REGISTER NODEPROTO *np, *lnp;
253 REGISTER PORTPROTO *pp, *lpt;
254 REGISTER NODEINST *ni, *nni;
255 REGISTER ARCINST *ai, *nai;
256 REGISTER PORTARCINST *pi, *lpo;
257 REGISTER PORTEXPINST *pe, *lpe;
258 REGISTER NETWORK *net, *nnet;
259 REGISTER INTBIG i;
260
261 /* see if this library exists */
262 if (lib == NOLIBRARY) return;
263
264 /* flush all batched changes */
265 noundoallowed();
266
267 for(i=0; i<el_maxtools; i++)
268 if ((el_tools[i].toolstate & TOOLON) != 0 && el_tools[i].eraselibrary != 0)
269 (*el_tools[i].eraselibrary)(lib);
270
271 /* erase the nodes, ports, arcs, and geometry modules in each nodeproto */
272 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
273 {
274 /* erase all arcs and nodes in this cell */
275 for(ni = np->firstnodeinst; ni != NONODEINST; ni = nni)
276 {
277 nni = ni->nextnodeinst;
278
279 /* remove nodeinst link */
280 if (ni->nextinst != NONODEINST) ni->nextinst->previnst = ni->previnst;
281 if (ni->previnst != NONODEINST) ni->previnst->nextinst = ni->nextinst; else
282 ni->proto->firstinst = ni->nextinst;
283
284 /* erase the portarcs on this nodeinst */
285 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = lpo)
286 {
287 lpo = pi->nextportarcinst;
288 freeportarcinst(pi);
289 }
290
291 /* erase the portexps on this nodeinst */
292 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = lpe)
293 {
294 lpe = pe->nextportexpinst;
295 freeportexpinst(pe);
296 }
297
298 /* erase the nodeinst */
299 freegeom(ni->geom);
300 freenodeinst(ni);
301 }
302 for(ai = np->firstarcinst; ai != NOARCINST; ai = nai)
303 {
304 nai = ai->nextarcinst;
305 freegeom(ai->geom);
306 freearcinst(ai);
307 }
308 for(net = np->firstnetwork; net != NONETWORK; net = nnet)
309 {
310 nnet = net->nextnetwork;
311 net_freenetwork(net, np);
312 }
313 db_freertree(np->rtree);
314 }
315
316 /* now erase the portprotos and nodeprotos */
317 for(np = lib->firstnodeproto; np != NONODEPROTO; np = lnp)
318 {
319 lnp = np->nextnodeproto;
320
321 /* free the portproto entries */
322 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = lpt)
323 {
324 lpt = pp->nextportproto;
325 efree(pp->protoname);
326 freeportproto(pp);
327 }
328
329 /* free the nodeinst proto */
330 freenodeproto(np);
331 }
332 lib->firstnodeproto = NONODEPROTO;
333 lib->tailnodeproto = NONODEPROTO;
334 lib->curnodeproto = NONODEPROTO;
335
336 /* now erase the library information */
337 if (lib->numvar != 0) db_freevars(&lib->firstvar, &lib->numvar);
338
339 /* mark a change to the database */
340 db_changetimestamp++;
341 }
342
343 /*
344 * routine to determine the appropriate library associated with the
345 * variable whose address is "addr" and type is "type".
346 */
whichlibrary(INTBIG addr,INTBIG type)347 LIBRARY *whichlibrary(INTBIG addr, INTBIG type)
348 {
349 REGISTER GEOM *geom;
350 REGISTER NODEPROTO *np;
351
352 switch (type&VTYPE)
353 {
354 case VNODEINST: return(((NODEINST *)addr)->parent->lib);
355 case VNODEPROTO:
356 np = (NODEPROTO *)addr;
357 if (np->primindex == 0) return(np->lib);
358 return(NOLIBRARY);
359 case VPORTARCINST:
360 return(((PORTARCINST *)addr)->conarcinst->parent->lib);
361 case VPORTEXPINST:
362 return(((PORTEXPINST *)addr)->exportproto->parent->lib);
363 case VPORTPROTO:
364 np = ((PORTPROTO *)addr)->parent;
365 if (np->primindex == 0) return(np->lib);
366 return(NOLIBRARY);
367 case VARCINST: return(((ARCINST *)addr)->parent->lib);
368 case VGEOM: geom = (GEOM *)addr;
369 if (geom->entryisnode)
370 return(geom->entryaddr.ni->parent->lib);
371 return(geom->entryaddr.ai->parent->lib);
372 case VLIBRARY: return((LIBRARY *)addr);
373 case VNETWORK: return(((NETWORK *)addr)->parent->lib);
374 }
375 return(NOLIBRARY);
376 }
377
378 /****************************** LAMBDA ******************************/
379
380 /*
381 * routine to change value of lambda in "count" technologies. The
382 * technologies are in "techarray" and the new lambda values for them
383 * are in "newlam".
384 * If "how" is 0, only change the technology (no libraries)
385 * If "how" is 1, change technology and library "whichlib"
386 * If "how" is 2, change technology and all libraries, specifically "whichlib"
387 */
changelambda(INTBIG count,TECHNOLOGY ** techarray,INTBIG * newlam,LIBRARY * whichlib,INTBIG how)388 void changelambda(INTBIG count, TECHNOLOGY **techarray, INTBIG *newlam,
389 LIBRARY *whichlib, INTBIG how)
390 {
391 REGISTER INTBIG *oldlam, i;
392 REGISTER NODEPROTO *np;
393 REGISTER LIBRARY *lib;
394 REGISTER TECHNOLOGY *tech;
395
396 if (how == 0)
397 {
398 /* special case when only changing technology values */
399 for(i=0; i<count; i++)
400 changetechnologylambda(techarray[i], newlam[i]);
401 return;
402 }
403
404 /* make the technology agree with the current library */
405 for(i=0; i<count; i++)
406 changetechnologylambda(techarray[i], newlam[i]);
407
408 /* update lambda values in the libraries */
409 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
410 {
411 lib->temp2 = 0;
412 if (how == 1 && whichlib != lib) continue;
413
414 /* announce start of changes to this library */
415 startobjectchange((INTBIG)lib, VLIBRARY);
416
417 /* preserve lambda for this library */
418 oldlam = (INTBIG *)emalloc(count * SIZEOFINTBIG, el_tempcluster);
419 if (oldlam == 0) return;
420 for(i=0; i<count; i++)
421 {
422 tech = techarray[i];
423 oldlam[i] = lib->lambda[tech->techindex];
424 lib->lambda[tech->techindex] = newlam[i];
425 }
426
427 lib->temp2 = (INTBIG)oldlam;
428
429 }
430
431 /* mark all cells in the library for scaling */
432 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
433 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
434 np->temp1 = 0;
435
436 /* scale all the cells */
437 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
438 {
439 if (how == 1 && whichlib != lib) continue;
440 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
441 db_scalecell(np, count, techarray, newlam);
442 if (lib->firstnodeproto != NONODEPROTO)
443 lib->userbits |= LIBCHANGEDMAJOR;
444 }
445
446 /* free old lambda values */
447 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
448 {
449 if (how == 1 && whichlib != lib) continue;
450 efree((CHAR *)lib->temp2);
451
452 /* announce end of changes to this library */
453 endobjectchange((INTBIG)lib, VLIBRARY);
454 }
455
456 }
457
458 /*
459 * routine to recursively scale the contents of cell "np" by "newlam/oldlam"
460 */
db_scalecell(NODEPROTO * np,INTBIG count,TECHNOLOGY ** techarray,INTBIG * newlamarray)461 void db_scalecell(NODEPROTO *np, INTBIG count, TECHNOLOGY **techarray, INTBIG *newlamarray)
462 {
463 REGISTER NODEINST *ni;
464 REGISTER ARCINST *ai;
465 REGISTER VARIABLE *var;
466 REGISTER INTBIG i, *oldlamarray, *position, oldlam, newlam;
467
468 /* quit if the cell is already done */
469 if (np->temp1 != 0) return;
470
471 /* first look for sub-cells that are not yet scaled */
472 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
473 if (ni->proto->primindex == 0)
474 db_scalecell(ni->proto, count, techarray, newlamarray);
475
476 /* mark this cell "scaled" */
477 np->temp1++;
478
479 /* see if this cell gets scaled */
480 for(i=0; i<count; i++)
481 if (np->tech == techarray[i]) break;
482 if (i < count)
483 {
484 /* get the old lambda value */
485 oldlamarray = (INTBIG *)np->lib->temp2;
486 if (oldlamarray == 0) return;
487 oldlam = oldlamarray[i];
488 newlam = newlamarray[i];
489
490 /* scale nodes and arcs in the cell */
491 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
492 db_scalenodeinst(ni, newlam, oldlam);
493 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
494 db_scalearcinst(ai, newlam, oldlam);
495
496 /* scale the cell */
497 db_boundcell(np, &np->lowx, &np->highx, &np->lowy, &np->highy);
498
499 /* scale variables such as cell-center and characteristic spacing */
500 var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center_key);
501 if (var != NOVARIABLE)
502 {
503 position = (INTBIG *)var->addr;
504 position[0] = muldiv(position[0], newlam, oldlam);
505 position[1] = muldiv(position[1], newlam, oldlam);
506 }
507 var = getval((INTBIG)np, VNODEPROTO, VINTEGER|VISARRAY, x_("FACET_characteristic_spacing"));
508 if (var != NOVARIABLE)
509 {
510 position = (INTBIG *)var->addr;
511 position[0] = muldiv(position[0], newlam, oldlam);
512 position[1] = muldiv(position[1], newlam, oldlam);
513 }
514 }
515 }
516
db_scalenodeinst(NODEINST * ni,INTBIG newlam,INTBIG oldlam)517 void db_scalenodeinst(NODEINST *ni, INTBIG newlam, INTBIG oldlam)
518 {
519 REGISTER VARIABLE *var;
520 REGISTER INTBIG sizex, sizey, dx, dy, len, i, newlx, newhx, newly, newhy;
521
522 newlx = muldiv(ni->lowx, newlam, oldlam);
523 newhx = muldiv(ni->highx, newlam, oldlam);
524 newly = muldiv(ni->lowy, newlam, oldlam);
525 newhy = muldiv(ni->highy, newlam, oldlam);
526
527 if (ni->proto->primindex == 0)
528 {
529 sizex = ni->proto->highx - ni->proto->lowx;
530 sizey = ni->proto->highy - ni->proto->lowy;
531 dx = ni->highx - ni->lowx - sizex;
532 dy = ni->highy - ni->lowy - sizey;
533 ni->lowx = newlx; ni->highx = newhx;
534 ni->lowy = newly; ni->highy = newhy;
535 if (dx != 0 || dy != 0)
536 {
537 dx = ni->highx - ni->lowx - sizex;
538 dy = ni->highy - ni->lowy - sizey;
539 if (dx != 0 || dy != 0)
540 {
541 ttyputmsg(_("Cell %s, node %s size and position adjusted"),
542 describenodeproto(ni->parent), describenodeinst(ni));
543 ni->lowx += dx/2; ni->highx = ni->lowx + sizex;
544 ni->lowy += dy/2; ni->highy = ni->lowy + sizey;
545 }
546 }
547 } else
548 {
549 /* look for trace data on primitives */
550 ni->lowx = newlx; ni->highx = newhx;
551 ni->lowy = newly; ni->highy = newhy;
552 var = gettrace(ni);
553 if (var != NOVARIABLE)
554 {
555 len = getlength(var);
556 for(i=0; i<len; i++)
557 ((INTBIG *)var->addr)[i] = muldiv(((INTBIG *)var->addr)[i], newlam, oldlam);
558 }
559 }
560 updategeom(ni->geom, ni->parent);
561 }
562
db_scalearcinst(ARCINST * ai,INTBIG newlam,INTBIG oldlam)563 void db_scalearcinst(ARCINST *ai, INTBIG newlam, INTBIG oldlam)
564 {
565 REGISTER VARIABLE *var;
566
567 ai->width = muldiv(ai->width, newlam, oldlam);
568 ai->end[0].xpos = muldiv(ai->end[0].xpos, newlam, oldlam);
569 ai->end[0].ypos = muldiv(ai->end[0].ypos, newlam, oldlam);
570 ai->end[1].xpos = muldiv(ai->end[1].xpos, newlam, oldlam);
571 ai->end[1].ypos = muldiv(ai->end[1].ypos, newlam, oldlam);
572 ai->length = computedistance(ai->end[0].xpos, ai->end[0].ypos,
573 ai->end[1].xpos, ai->end[1].ypos);
574 db_validatearcinst(ai);
575 updategeom(ai->geom, ai->parent);
576
577 /* look for curvature data on primitives */
578 var = getvalkey((INTBIG)ai, VARCINST, VINTEGER, el_arc_radius_key);
579 if (var != NOVARIABLE) var->addr = muldiv(var->addr, newlam, oldlam);
580 }
581
582 /*
583 * routine to validate arcinst "ai" after being scaled.
584 */
db_validatearcinst(ARCINST * ai)585 void db_validatearcinst(ARCINST *ai)
586 {
587 REGISTER BOOLEAN inside0, inside1;
588 INTBIG lx0, lx1, hx0, hx1, ly0, ly1, hy0, hy1, fx, fy, tx, ty;
589 REGISTER POLYGON *poly0, *poly1;
590
591 /* make sure there is a polygon */
592 poly0 = allocpolygon(4, db_cluster);
593 poly1 = allocpolygon(4, db_cluster);
594
595 /* if nothing is outside port, quit */
596 fx = ai->end[0].xpos;
597 fy = ai->end[0].ypos;
598 tx = ai->end[1].xpos;
599 ty = ai->end[1].ypos;
600 shapeportpoly(ai->end[0].nodeinst, ai->end[0].portarcinst->proto, poly0, FALSE);
601 inside0 = isinside(fx, fy, poly0);
602 shapeportpoly(ai->end[1].nodeinst, ai->end[1].portarcinst->proto, poly1, FALSE);
603 inside1 = isinside(tx, ty, poly1);
604 if (!inside0 || !inside1)
605 {
606 /* if arcinst is not fixed-angle, run it directly to the port centers */
607 if ((ai->userbits&FIXANG) == 0)
608 {
609 if (!inside0) closestpoint(poly0, &fx, &fy);
610 if (!inside1) closestpoint(poly1, &tx, &ty);
611 db_setarcinst(ai, fx, fy, tx, ty);
612 } else
613 {
614 /* get bounding boxes of polygons */
615 getbbox(poly0, &lx0, &hx0, &ly0, &hy0);
616 getbbox(poly1, &lx1, &hx1, &ly1, &hy1);
617
618 /* if fixed-angle path runs between the ports, adjust the arcinst */
619 if (arcconnects(((ai->userbits&AANGLE) >> AANGLESH) * 10, lx0,hx0, ly0,hy0, lx1,hx1,
620 ly1,hy1, &fx,&fy, &tx,&ty))
621 {
622 closestpoint(poly0, &fx, &fy);
623 closestpoint(poly1, &tx, &ty);
624 db_setarcinst(ai, fx, fy, tx, ty);
625 } else
626 {
627 /* give up and remove the constraint */
628 fx = ai->end[0].xpos;
629 fy = ai->end[0].ypos;
630 tx = ai->end[1].xpos;
631 ty = ai->end[1].ypos;
632 if (!inside0) closestpoint(poly0, &fx, &fy);
633 if (!inside1) closestpoint(poly1, &tx, &ty);
634 ai->userbits &= ~FIXANG;
635 db_setarcinst(ai, fx, fy, tx, ty);
636 ttyputmsg(_("Cell %s, arc %s no longer fixed-angle"),
637 describenodeproto(ai->parent), describearcinst(ai));
638 }
639 }
640 }
641 freepolygon(poly0);
642 freepolygon(poly1);
643 }
644
db_setarcinst(ARCINST * ai,INTBIG fx,INTBIG fy,INTBIG tx,INTBIG ty)645 void db_setarcinst(ARCINST *ai, INTBIG fx, INTBIG fy, INTBIG tx, INTBIG ty)
646 {
647 /* check for null arcinst motion */
648 if (fx == ai->end[0].xpos && fy == ai->end[0].ypos &&
649 tx == ai->end[1].xpos && ty == ai->end[1].ypos) return;
650
651 ai->end[0].xpos = fx; ai->end[0].ypos = fy;
652 ai->end[1].xpos = tx; ai->end[1].ypos = ty;
653 ai->length = computedistance(fx,fy, tx,ty);
654 determineangle(ai);
655 updategeom(ai->geom, ai->parent);
656 }
657
658 /*
659 * Routine to change the value of lambda in technology "tech" to
660 * "newlambda".
661 */
changetechnologylambda(TECHNOLOGY * tech,INTBIG newlambda)662 void changetechnologylambda(TECHNOLOGY *tech, INTBIG newlambda)
663 {
664 REGISTER NODEPROTO *np;
665 REGISTER ARCPROTO *ap;
666 REGISTER INTBIG oldlambda;
667
668 oldlambda = tech->deflambda;
669 if (newlambda <= 0) newlambda = 1;
670 if (newlambda == oldlambda) return;
671
672 /* change the default width of the primitive arc prototypes */
673 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
674 {
675 ap->nominalwidth = muldiv(ap->nominalwidth, newlambda, oldlambda);
676 }
677
678 /* now change the default size of the primitive node prototypes */
679 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
680 {
681 np->lowx = muldiv(np->lowx, newlambda, oldlambda);
682 np->highx = muldiv(np->highx, newlambda, oldlambda);
683 np->lowy = muldiv(np->lowy, newlambda, oldlambda);
684 np->highy = muldiv(np->highy, newlambda, oldlambda);
685 }
686
687 /* finally, reset the default lambda value */
688 tech->deflambda = newlambda;
689
690 /* mark a change to the database */
691 db_changetimestamp++;
692 }
693
694 /*
695 * Routine to change the internal units in library "whichlib" from "oldunits"
696 * to "newunits". If "whichlib" is NOLIBRARY, change the entire database (all
697 * libraries and technologies).
698 */
changeinternalunits(LIBRARY * whichlib,INTBIG oldunits,INTBIG newunits)699 void changeinternalunits(LIBRARY *whichlib, INTBIG oldunits, INTBIG newunits)
700 {
701 REGISTER INTBIG hardscaleerror, softscaleerror, len;
702 INTBIG num, den;
703 REGISTER INTBIG i;
704 REGISTER CHAR *errortype, *errorlocation;
705 REGISTER TECHNOLOGY *tech;
706 REGISTER LIBRARY *lib;
707 REGISTER NODEPROTO *np;
708 REGISTER ARCPROTO *ap;
709 REGISTER NODEINST *ni;
710 REGISTER ARCINST *ai;
711 REGISTER VARIABLE *var;
712 REGISTER WINDOWPART *w;
713
714 hardscaleerror = softscaleerror = 0;
715 db_getinternalunitscale(&num, &den, oldunits, newunits);
716 if (whichlib == NOLIBRARY)
717 {
718 /* global change: set units */
719 if ((oldunits&INTERNALUNITS) == newunits) return;
720 el_units = (el_units & ~INTERNALUNITS) | newunits;
721
722 /* scale all technologies */
723 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
724 {
725 /* scale arc width */
726 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
727 {
728 hardscaleerror += db_scaleunits(&ap->nominalwidth, num, den);
729 }
730
731 /* scale node sizes */
732 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
733 {
734 hardscaleerror += db_scaleunits(&np->lowx, num, den);
735 hardscaleerror += db_scaleunits(&np->highx, num, den);
736 hardscaleerror += db_scaleunits(&np->lowy, num, den);
737 hardscaleerror += db_scaleunits(&np->highy, num, den);
738 }
739
740 /* finally, scale lambda */
741 hardscaleerror += db_scaleunits(&tech->deflambda, num, den);
742 if (tech->deflambda <= 0) tech->deflambda = 1;
743 }
744
745 /* scale lambda in libraries */
746 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
747 for(i=0; i<el_maxtech; i++)
748 hardscaleerror += db_scaleunits(&lib->lambda[i], num, den);
749
750 /* scale all display windows */
751 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
752 {
753 if (w->curnodeproto == NONODEPROTO) continue;
754 softscaleerror += db_scaleunits(&w->screenlx, num, den);
755 softscaleerror += db_scaleunits(&w->screenly, num, den);
756 softscaleerror += db_scaleunits(&w->screenhx, num, den);
757 softscaleerror += db_scaleunits(&w->screenhy, num, den);
758 }
759 }
760
761 /* scale all appropriate libraries */
762 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
763 {
764 /* only scale requested library if request was made */
765 if (whichlib != NOLIBRARY && whichlib != lib) continue;
766
767 /* scale each cell */
768 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
769 {
770 /* scale nodes */
771 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
772 {
773 hardscaleerror += db_scaleunits(&ni->lowx, num, den);
774 hardscaleerror += db_scaleunits(&ni->highx, num, den);
775 hardscaleerror += db_scaleunits(&ni->lowy, num, den);
776 hardscaleerror += db_scaleunits(&ni->highy, num, den);
777 if (ni->proto->primindex != 0)
778 {
779 /* look for trace data on primitives */
780 var = gettrace(ni);
781 if (var != NOVARIABLE)
782 {
783 len = getlength(var);
784 for(i=0; i<len; i++)
785 hardscaleerror += db_scaleunits(&((INTBIG *)var->addr)[i], num, den);
786 }
787 }
788 updategeom(ni->geom, np);
789 }
790
791 /* scale arcs */
792 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
793 {
794 hardscaleerror += db_scaleunits(&ai->width, num, den);
795 hardscaleerror += db_scaleunits(&ai->end[0].xpos, num, den);
796 hardscaleerror += db_scaleunits(&ai->end[0].ypos, num, den);
797 hardscaleerror += db_scaleunits(&ai->end[1].xpos, num, den);
798 hardscaleerror += db_scaleunits(&ai->end[1].ypos, num, den);
799 ai->length = computedistance(ai->end[0].xpos, ai->end[0].ypos,
800 ai->end[1].xpos, ai->end[1].ypos);
801 updategeom(ai->geom, np);
802
803 /* look for curvature data */
804 var = getvalkey((INTBIG)ai, VARCINST, VINTEGER, el_arc_radius_key);
805 if (var != NOVARIABLE) hardscaleerror += db_scaleunits(&var->addr, num, den);
806 }
807
808 /* scale cell size */
809 db_boundcell(np, &np->lowx, &np->highx, &np->lowy, &np->highy);
810 }
811 lib->userbits = (lib->userbits & ~LIBUNITS) |
812 (((newunits & INTERNALUNITS) >> INTERNALUNITSSH) << LIBUNITSSH);
813 if (lib->firstnodeproto != NONODEPROTO) lib->userbits |= LIBCHANGEDMAJOR;
814 }
815
816 /* report any failures */
817 if (hardscaleerror != 0 || softscaleerror != 0)
818 {
819 if (den > num) errortype = _("roundoff"); else
820 errortype = _("overflow");
821 if (hardscaleerror == 0) errorlocation = _("display"); else
822 {
823 if (whichlib == NOLIBRARY) errorlocation = _("database"); else
824 errorlocation = _("library");
825 }
826 ttyputerr(_("Change caused %s errors in %s"), errortype, errorlocation);
827 if (hardscaleerror != 0)
828 {
829 if (whichlib == NOLIBRARY)
830 {
831 ttyputmsg(_("Recommend check of database for validity and keep old library files"));
832 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
833 lib->userbits &= ~READFROMDISK;
834 } else
835 {
836 ttyputmsg(_("Recommend check of database for validity and keep old library file"));
837 whichlib->userbits &= ~READFROMDISK;
838 }
839 } else
840 {
841 ttyputmsg(_("Recommend redisplay"));
842 }
843 }
844
845 /* mark a change to the database */
846 db_changetimestamp++;
847 }
848
849 /*
850 * Routine to scale "value" by "num"/"den". Returns zero if scale worked,
851 * nonzero if overflow/underflow occurred.
852 */
db_scaleunits(INTBIG * value,INTBIG num,INTBIG den)853 INTBIG db_scaleunits(INTBIG *value, INTBIG num, INTBIG den)
854 {
855 REGISTER INTBIG orig, scaled, reconstructed;
856
857 orig = *value;
858 scaled = muldiv(orig, num, den);
859 *value = scaled;
860 reconstructed = muldiv(scaled, den, num);
861 if (orig == reconstructed) return(0);
862 return(1);
863 }
864