1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: conlay.c
6 * Hierarchical layout constraint system
7 * Written by: Steven M. Rubin, Static Free Software
8 *
9 * Copyright (c) 2001 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 #include "global.h"
32 #include "conlay.h"
33 #include "database.h"
34 #include "usr.h"
35
36 /* working memory for "cla_modwithin()" */
37 static INTBIG cla_workingarccount = 0;
38 static ARCINST **cla_workingarcs;
39
40 /* routines referenced in "conlin.c"*/
41 void cla_oldportposition(NODEINST*, PORTPROTO*, INTBIG*, INTBIG*);
42 void cla_adjustmatrix(NODEINST*, PORTPROTO*, XARRAY);
43
44 /* prototypes for local routines */
45 static BOOLEAN cla_modifynodeinst(NODEINST *ni, INTBIG deltalx, INTBIG deltaly, INTBIG deltahx,
46 INTBIG deltahy, INTBIG dangle, INTBIG dtrans, BOOLEAN announce);
47 static BOOLEAN cla_modnodearcs(NODEINST*, INTBIG, INTBIG);
48 static void cla_modwithin(NODEINST*, INTBIG, INTBIG);
49 static BOOLEAN cla_modrigid(NODEINST*, INTBIG, INTBIG);
50 static BOOLEAN cla_modflex(NODEINST*, INTBIG, INTBIG);
51 static void cla_nonorthogfixang(ARCINST*, INTBIG, INTBIG, NODEINST*, INTBIG[2], INTBIG[2]);
52 static void cla_ensurearcinst(ARCINST*, INTBIG);
53 static void cla_updatearc(ARCINST*, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG);
54 static void cla_domovearcinst(ARCINST*, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG);
55 static void cla_makeoldrot(NODEINST*, XARRAY);
56 static void cla_makeoldtrans(NODEINST*, XARRAY);
57 static void cla_computecell(NODEPROTO*, BOOLEAN);
58 static BOOLEAN cla_lookdown(NODEPROTO*);
59
60 #define CLA_DEBUG 1 /* comment out for normal life */
61
62 /* command completion table for this constraint solver */
63 static KEYWORD layconopt[] =
64 {
65 {x_("debug-toggle"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
66 TERMKEY
67 };
68 COMCOMP cla_layconp = {layconopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
69 0, x_(" \t"), M_("layout constraint system option"), 0};
70
71 INTBIG cla_changeclock;
72 #ifdef CLA_DEBUG
73 static BOOLEAN cla_conlaydebug;
74 #endif
75 CONSTRAINT *cla_constraint; /* the constraint object for this solver */
76
77 /******************** CONSTRAINT SYSTEM HOOKS *************************/
78
cla_layconinit(CONSTRAINT * con)79 void cla_layconinit(CONSTRAINT *con)
80 {
81 /* only function during pass 1 of initialization */
82 if (con == NOCONSTRAINT) return;
83 cla_constraint = con;
84 cla_changeclock = 10;
85 #ifdef CLA_DEBUG
86 cla_conlaydebug = FALSE;
87 #endif
88 }
89
cla_layconterm(void)90 void cla_layconterm(void)
91 {
92 if (cla_workingarccount > 0) efree((CHAR *)cla_workingarcs);
93 cla_workingarccount = 0;
94 }
95
cla_layconsetmode(INTBIG count,CHAR * par[])96 void cla_layconsetmode(INTBIG count, CHAR *par[])
97 {
98 REGISTER INTBIG l;
99 REGISTER CHAR *pp;
100
101 if (count == 0)
102 {
103 ttyputusage(x_("constraint tell layout OPTION"));
104 return;
105 }
106
107 if (el_curconstraint != cla_constraint)
108 {
109 ttyputerr(M_("Must first switch to this solver with 'constraint use'"));
110 return;
111 }
112
113 l = estrlen(pp = par[0]);
114
115 /* debugging switch */
116 if (namesamen(pp, x_("debug-toggle"), l) == 0 && l >= 1)
117 {
118 #ifdef CLA_DEBUG
119 cla_conlaydebug = !cla_conlaydebug;
120 if (cla_conlaydebug) ttyputmsg(M_("Layout constraint debugging on")); else
121 ttyputmsg(M_("Layout constraint debugging off"));
122 #else
123 ttyputmsg(M_("Sorry, constraint debugging code has been compiled out"));
124 #endif
125 return;
126 }
127 ttyputbadusage(x_("constraint tell layout"));
128 }
129
130 /*
131 * the valid "command" is "describearc" which returns a string that describes
132 * the constraints on the arc in "arg1".
133 */
cla_layconrequest(CHAR * command,INTBIG arg1)134 INTBIG cla_layconrequest(CHAR *command, INTBIG arg1)
135 {
136 REGISTER ARCINST *ai;
137 REGISTER INTBIG l;
138 REGISTER void *infstr;
139
140 l = estrlen(command);
141
142 if (namesamen(command, x_("describearc"), l) == 0)
143 {
144 ai = (ARCINST *)arg1;
145 infstr = initinfstr();
146 if ((ai->userbits&FIXED) != 0) addtoinfstr(infstr, 'R'); else
147 {
148 switch (ai->userbits&(FIXANG|CANTSLIDE))
149 {
150 case 0: addtoinfstr(infstr, 'S'); break;
151 case FIXANG: addstringtoinfstr(infstr, x_("FS")); break;
152 case CANTSLIDE: addtoinfstr(infstr, 'X'); break;
153 case FIXANG|CANTSLIDE: addtoinfstr(infstr, 'F'); break;
154 }
155 }
156 return((INTBIG)returninfstr(infstr));
157 }
158 return(0);
159 }
160
161 /*
162 * routine to do hierarchical update on any cells that changed
163 */
cla_layconsolve(NODEPROTO * np)164 void cla_layconsolve(NODEPROTO *np)
165 {
166 REGISTER CHANGECELL *cc;
167 REGISTER CHANGEBATCH *curbatch;
168 REGISTER CHANGE *c;
169
170 /* if only one cell is requested, solve that */
171 curbatch = db_getcurrentbatch();
172 if (np != NONODEPROTO)
173 {
174 cla_computecell(np, FALSE);
175 } else
176 {
177 /* solve all cells that changed */
178 if (curbatch != NOCHANGEBATCH)
179 for(cc = curbatch->firstchangecell; cc != NOCHANGECELL; cc = cc->nextchangecell)
180 cla_computecell(cc->changecell, cc->forcedlook);
181 }
182
183 if (curbatch == NOCHANGEBATCH) return;
184 for(c = curbatch->changehead; c != NOCHANGE; c = c->nextchange)
185 switch (c->changetype)
186 {
187 case NODEINSTNEW:
188 case NODEINSTKILL:
189 case NODEINSTMOD:
190 ((NODEINST *)c->entryaddr)->changeaddr = (CHAR *)NOCHANGE;
191 break;
192 case ARCINSTNEW:
193 case ARCINSTKILL:
194 case ARCINSTMOD:
195 ((ARCINST *)c->entryaddr)->changeaddr = (CHAR *)NOCHANGE;
196 break;
197 case PORTPROTONEW:
198 case PORTPROTOKILL:
199 case PORTPROTOMOD:
200 ((PORTPROTO *)c->entryaddr)->changeaddr = (CHAR *)NOCHANGE;
201 break;
202 case NODEPROTONEW:
203 case NODEPROTOKILL:
204 case NODEPROTOMOD:
205 ((NODEPROTO *)c->entryaddr)->changeaddr = (CHAR *)NOCHANGE;
206 break;
207 }
208 }
209
210 /*
211 * If an export is created, touch all instances of the cell
212 */
cla_layconnewobject(INTBIG addr,INTBIG type)213 void cla_layconnewobject(INTBIG addr, INTBIG type)
214 {
215 REGISTER NODEPROTO *np;
216 REGISTER PORTPROTO *pp;
217 REGISTER NODEINST *ni;
218
219 if (type == VPORTPROTO)
220 {
221 pp = (PORTPROTO *)addr;
222 np = pp->parent;
223 for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
224 (void)db_change((INTBIG)ni, OBJECTSTART, VNODEINST, 0, 0, 0, 0, 0);
225 for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
226 (void)db_change((INTBIG)ni, NODEINSTMOD, ni->lowx, ni->lowy,
227 ni->highx, ni->highy, ni->rotation, ni->transpose);
228 for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
229 (void)db_change((INTBIG)ni, OBJECTEND, VNODEINST, 0, 0, 0, 0, 0);
230 }
231 }
232
233 /*
234 * If an export is deleted, touch all instances of the cell
235 */
cla_layconkillobject(INTBIG addr,INTBIG type)236 void cla_layconkillobject(INTBIG addr, INTBIG type)
237 {
238 REGISTER NODEPROTO *np;
239 REGISTER PORTPROTO *pp;
240 REGISTER NODEINST *ni;
241
242 if (type == VPORTPROTO)
243 {
244 pp = (PORTPROTO *)addr;
245 np = pp->parent;
246 for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
247 {
248 (void)db_change((INTBIG)ni, OBJECTSTART, VNODEINST, 0, 0, 0, 0, 0);
249 (void)db_change((INTBIG)ni, NODEINSTMOD, ni->lowx, ni->lowy,
250 ni->highx, ni->highy, ni->rotation, ni->transpose);
251 (void)db_change((INTBIG)ni, OBJECTEND, VNODEINST, 0, 0, 0, 0, 0);
252 }
253 }
254 }
255
256 /*
257 * If an export is renamed, touch all instances of the cell
258 */
cla_layconnewvariable(INTBIG addr,INTBIG type,INTBIG skey,INTBIG stype)259 void cla_layconnewvariable(INTBIG addr, INTBIG type, INTBIG skey, INTBIG stype)
260 {
261 CHAR *name;
262 REGISTER NODEPROTO *np;
263 REGISTER PORTPROTO *pp;
264 REGISTER NODEINST *ni;
265
266 if (type == VPORTPROTO)
267 {
268 if ((stype&VCREF) != 0)
269 {
270 name = changedvariablename(type, skey, stype);
271 if (estrcmp(name, x_("protoname")) == 0)
272 {
273 pp = (PORTPROTO *)addr;
274 np = pp->parent;
275 for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
276 {
277 (void)db_change((INTBIG)ni, OBJECTSTART, VNODEINST, 0, 0, 0, 0, 0);
278 (void)db_change((INTBIG)ni, NODEINSTMOD, ni->lowx, ni->lowy,
279 ni->highx, ni->highy, ni->rotation, ni->transpose);
280 (void)db_change((INTBIG)ni, OBJECTEND, VNODEINST, 0, 0, 0, 0, 0);
281 }
282 }
283 }
284 }
285 }
286
287 /*
288 * set layout constraints on arc instance "ai" according to "changetype".
289 * the routine returns true if the arc change is not successful (or already
290 * done)
291 */
cla_layconsetobject(INTBIG addr,INTBIG type,INTBIG changetype,INTBIG changedata)292 BOOLEAN cla_layconsetobject(INTBIG addr, INTBIG type, INTBIG changetype,
293 INTBIG /*@unused@*/ changedata)
294 {
295 REGISTER ARCINST *ai;
296
297 if ((type&VTYPE) != VARCINST) return(TRUE);
298 ai = (ARCINST *)addr;
299 if (ai == NOARCINST) return(TRUE);
300 switch (changetype)
301 {
302 case CHANGETYPERIGID: /* arc rigid */
303 if ((ai->userbits & FIXED) != 0) return(TRUE);
304 (void)setval((INTBIG)ai, VARCINST, x_("userbits"), ai->userbits|FIXED, VINTEGER);
305 break;
306 case CHANGETYPEUNRIGID: /* arc un-rigid */
307 if ((ai->userbits & FIXED) == 0) return(TRUE);
308 (void)setval((INTBIG)ai, VARCINST, x_("userbits"), ai->userbits & ~FIXED, VINTEGER);
309 break;
310 case CHANGETYPEFIXEDANGLE: /* arc fixed-angle */
311 if ((ai->userbits & FIXANG) != 0) return(TRUE);
312 (void)setval((INTBIG)ai, VARCINST, x_("userbits"), ai->userbits|FIXANG, VINTEGER);
313 break;
314 case CHANGETYPENOTFIXEDANGLE: /* arc not fixed-angle */
315 if ((ai->userbits & FIXANG) == 0) return(TRUE);
316 (void)setval((INTBIG)ai, VARCINST, x_("userbits"), ai->userbits & ~FIXANG, VINTEGER);
317 break;
318 case CHANGETYPESLIDABLE: /* arc slidable */
319 if ((ai->userbits & CANTSLIDE) == 0) return(TRUE);
320 (void)setval((INTBIG)ai, VARCINST, x_("userbits"), ai->userbits & ~CANTSLIDE, VINTEGER);
321 break;
322 case CHANGETYPENOTSLIDABLE: /* arc nonslidable */
323 if ((ai->userbits & CANTSLIDE) != 0) return(TRUE);
324 (void)setval((INTBIG)ai, VARCINST, x_("userbits"), ai->userbits|CANTSLIDE, VINTEGER);
325 break;
326 case CHANGETYPETEMPRIGID: /* arc temporarily rigid */
327 if (ai->changed == cla_changeclock + 2) return(TRUE);
328 ai->changed = cla_changeclock + 2;
329 break;
330 case CHANGETYPETEMPUNRIGID: /* arc temporarily un-rigid */
331 if (ai->changed == cla_changeclock + 3) return(TRUE);
332 ai->changed = cla_changeclock + 3;
333 break;
334 case CHANGETYPEREMOVETEMP: /* remove temporarily state */
335 if (ai->changed != cla_changeclock + 3 && ai->changed != cla_changeclock + 2) return(TRUE);
336 ai->changed = cla_changeclock - 3;
337 break;
338 }
339 return(FALSE);
340 }
341
cla_layconmodifynodeinst(NODEINST * ni,INTBIG dlx,INTBIG dly,INTBIG dhx,INTBIG dhy,INTBIG drot,INTBIG dtrans)342 void cla_layconmodifynodeinst(NODEINST *ni, INTBIG dlx, INTBIG dly, INTBIG dhx, INTBIG dhy,
343 INTBIG drot, INTBIG dtrans)
344 {
345 /* advance the change clock */
346 cla_changeclock += 4;
347
348 /* change the nodeinst */
349 if (cla_modifynodeinst(ni, dlx, dly, dhx, dhy, drot, dtrans, FALSE))
350 db_forcehierarchicalanalysis(ni->parent);
351
352 /* change the arcs on the nodeinst */
353 if (cla_modnodearcs(ni, drot, dtrans))
354 db_forcehierarchicalanalysis(ni->parent);
355 }
356
cla_layconmodifynodeinsts(INTBIG count,NODEINST ** nis,INTBIG * dlxs,INTBIG * dlys,INTBIG * dhxs,INTBIG * dhys,INTBIG * drots,INTBIG * dtranss)357 void cla_layconmodifynodeinsts(INTBIG count, NODEINST **nis, INTBIG *dlxs, INTBIG *dlys,
358 INTBIG *dhxs, INTBIG *dhys, INTBIG *drots, INTBIG *dtranss)
359 {
360 REGISTER INTBIG i;
361 REGISTER NODEPROTO *parent;
362
363 /* advance the change clock */
364 cla_changeclock += 4;
365
366 /* change the nodeinst */
367 parent = NONODEPROTO;
368 for(i=0; i<count; i++)
369 {
370 if (cla_modifynodeinst(nis[i], dlxs[i], dlys[i], dhxs[i], dhys[i],
371 drots[i], dtranss[i], FALSE)) parent = nis[i]->parent;
372 }
373
374 /* change the arcs on the nodeinst */
375 for(i=0; i<count; i++)
376 {
377 if (cla_modnodearcs(nis[i], drots[i], dtranss[i]))
378 parent = nis[i]->parent;
379 }
380 if (parent != NONODEPROTO) db_forcehierarchicalanalysis(parent);
381 }
382
cla_layconmodifyarcinst(ARCINST * ai,INTBIG oldx0,INTBIG oldy0,INTBIG oldx1,INTBIG oldy1,INTBIG oldwid,INTBIG oldlen)383 void cla_layconmodifyarcinst(ARCINST /*@unused@*/ *ai, INTBIG /*@unused@*/ oldx0,
384 INTBIG /*@unused@*/ oldy0, INTBIG /*@unused@*/ oldx1,
385 INTBIG /*@unused@*/ oldy1, INTBIG /*@unused@*/ oldwid, INTBIG /*@unused@*/ oldlen) {}
cla_layconmodifyportproto(PORTPROTO * pp,NODEINST * oni,PORTPROTO * opp)386 void cla_layconmodifyportproto(PORTPROTO /*@unused@*/ *pp, NODEINST /*@unused@*/ *oni,
387 PORTPROTO /*@unused@*/ *opp) {}
cla_layconmodifynodeproto(NODEPROTO * np)388 void cla_layconmodifynodeproto(NODEPROTO /*@unused@*/ *np) {}
cla_layconnewlib(LIBRARY * lib)389 void cla_layconnewlib(LIBRARY /*@unused@*/ *lib) {}
cla_layconkilllib(LIBRARY * lib)390 void cla_layconkilllib(LIBRARY /*@unused@*/ *lib) {}
cla_layconkillvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG saddr,INTBIG stype,UINTBIG * olddes)391 void cla_layconkillvariable(INTBIG /*@unused@*/ addr, INTBIG /*@unused@*/ type,
392 INTBIG /*@unused@*/ key, INTBIG /*@unused@*/ saddr,
393 INTBIG /*@unused@*/ stype, UINTBIG /*@unused@*/ *olddes) {}
cla_layconinsertvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG aindex)394 void cla_layconinsertvariable(INTBIG /*@unused@*/ addr, INTBIG /*@unused@*/ type,
395 INTBIG /*@unused@*/ key, INTBIG /*@unused@*/ aindex) {}
cla_laycondeletevariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG aindex,INTBIG oldval)396 void cla_laycondeletevariable(INTBIG /*@unused@*/ addr, INTBIG /*@unused@*/ type,
397 INTBIG /*@unused@*/ key, INTBIG /*@unused@*/ aindex, INTBIG /*@unused@*/ oldval) {}
cla_layconsetvariable(void)398 void cla_layconsetvariable(void) {}
399
400 /******************** TEXT MODIFICATION CODE *************************/
401
402 /* #define TEXTPARTOFOBJECTBOUNDS 1 */
403
cla_layconmodifyvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG stype,INTBIG aindex,INTBIG oldval)404 void cla_layconmodifyvariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG stype,
405 INTBIG aindex, INTBIG oldval)
406 {
407 #ifdef TEXTPARTOFOBJECTBOUNDS
408 REGISTER CHAR *name;
409 REGISTER PORTPROTO *pp;
410 REGISTER NODEINST *ni;
411
412 /* look for modified text descriptor on exports */
413 if (type == VPORTPROTO)
414 {
415 if ((stype&VCREF) != 0)
416 {
417 name = changedvariablename(type, key, stype);
418 if (estrcmp(name, x_("textdescript")) == 0)
419 {
420 if (aindex == 1)
421 {
422 pp = (PORTPROTO *)addr;
423 ni = pp->subnodeinst;
424 updategeom(ni->geom, ni->parent);
425 }
426 }
427 }
428 }
429 #endif
430 }
431
cla_layconmodifydescript(INTBIG addr,INTBIG type,INTBIG key,UINTBIG * olddes)432 void cla_layconmodifydescript(INTBIG addr, INTBIG type, INTBIG key, UINTBIG *olddes)
433 {
434 #ifdef TEXTPARTOFOBJECTBOUNDS
435 REGISTER NODEINST *ni;
436 REGISTER ARCINST *ai;
437 REGISTER PORTPROTO *pp;
438
439 switch (type)
440 {
441 case VNODEINST:
442 ni = (NODEINST *)addr;
443 updategeom(ni->geom, ni->parent);
444 break;
445 case VPORTPROTO:
446 pp = (PORTPROTO *)addr;
447 ni = pp->subnodeinst;
448 updategeom(ni->geom, ni->parent);
449 break;
450 case VARCINST:
451 ai = (ARCINST *)addr;
452 updategeom(ai->geom, ai->parent);
453 break;
454 }
455 #endif
456 }
457
458 /******************** NODE MODIFICATION CODE *************************/
459
460 /*
461 * The meaning of cla_changeclock for object modification:
462 *
463 * ai->changed < cla_changeclock-2 unmodified arcs
464 * ai->changed == cla_changeclock-2 unmodified rigid arcs
465 * ai->changed == cla_changeclock-1 unmodified unrigid arcs
466 * ai->changed == cla_changeclock modified rigid arcs
467 * ai->changed == cla_changeclock+1 modified unrigid arcs
468 * ni->changed < cla_changeclock-1 unmodified nodes
469 * ni->changed == cla_changeclock-1 size-changed nodes
470 * ni->changed == cla_changeclock position-changed nodes
471 */
472
473 /*
474 * routine to modify nodeinst "ni" by "deltalx" in low X, "deltaly" in low Y,
475 * "deltahx" in high X, "deltahy" in high Y, and "dangle" tenth-degrees. If
476 * "announce" is true, report "start" and "end" changes on the node.
477 * If the nodeinst is a portproto of the current cell and has any arcs
478 * connected to it, the routine returns nonzero to indicate that the outer
479 * cell has ports that moved (the nodeinst has exports).
480 */
cla_modifynodeinst(NODEINST * ni,INTBIG deltalx,INTBIG deltaly,INTBIG deltahx,INTBIG deltahy,INTBIG dangle,INTBIG dtrans,BOOLEAN announce)481 BOOLEAN cla_modifynodeinst(NODEINST *ni, INTBIG deltalx, INTBIG deltaly, INTBIG deltahx,
482 INTBIG deltahy, INTBIG dangle, INTBIG dtrans, BOOLEAN announce)
483 {
484 REGISTER INTBIG oldlx, oldly, oldhx, oldhy, change;
485 REGISTER INTSML oldang, oldtrans;
486
487 /* determine whether this is a position or size change */
488 if (deltalx == deltahx && deltaly == deltahy)
489 {
490 if (deltalx == 0 && deltaly == 0 && dangle == 0 && dtrans == 0) change = -1; else
491 change = 0;
492 } else change = -1;
493
494 /* reject if this change has already been done */
495 if (ni->changed >= cla_changeclock+change) return(FALSE);
496
497 /* if simple rotation on transposed nodeinst, reverse rotation */
498 if (ni->transpose != 0 && dtrans == 0) dangle = (3600 - dangle) % 3600;
499
500 if (ni->changed < cla_changeclock-1 && announce)
501 (void)db_change((INTBIG)ni, OBJECTSTART, VNODEINST, 0, 0, 0, 0, 0);
502
503 /* make changes to the nodeinst */
504 oldang = ni->rotation; ni->rotation = (INTSML)((ni->rotation + dangle) % 3600);
505 oldtrans = ni->transpose; ni->transpose = (INTSML)((ni->transpose + dtrans) & 1);
506 oldlx = ni->lowx; ni->lowx += deltalx;
507 oldhx = ni->highx; ni->highx += deltahx;
508 oldly = ni->lowy; ni->lowy += deltaly;
509 oldhy = ni->highy; ni->highy += deltahy;
510 updategeom(ni->geom, ni->parent);
511
512 #ifdef CLA_DEBUG
513 if (cla_conlaydebug)
514 ttyputmsg(M_("Change node %s by X(%s %s) Y(%s %s) r=%ld t=%ld"),
515 describenodeinst(ni), latoa(deltalx, 0), latoa(deltahx, 0), latoa(deltaly, 0),
516 latoa(deltahy, 0), dangle, dtrans);
517 #endif
518
519 /* mark that this nodeinst has changed */
520 if (ni->changed < cla_changeclock-1)
521 {
522 ni->changeaddr = (CHAR *)db_change((INTBIG)ni, NODEINSTMOD, oldlx,
523 oldly, oldhx, oldhy, oldang, oldtrans);
524 if (announce)
525 (void)db_change((INTBIG)ni, OBJECTEND, VNODEINST, 0, 0, 0, 0, 0);
526 }
527
528 ni->changed = cla_changeclock + change;
529
530 /* see if this nodeinst is a port of the current cell */
531 if (ni->firstportexpinst == NOPORTEXPINST) return(FALSE);
532 return(TRUE);
533 }
534
535 /*
536 * routine to modify all of the arcs connected to nodeinst "ni" (which has
537 * been rotated by "dangle" tenth-degrees). If the routine returns nonzero,
538 * some ports on the current cell have moved and the cell must be
539 * re-examined for portproto locations.
540 */
cla_modnodearcs(NODEINST * ni,INTBIG dangle,INTBIG dtrans)541 BOOLEAN cla_modnodearcs(NODEINST *ni, INTBIG dangle, INTBIG dtrans)
542 {
543 REGISTER BOOLEAN examinecell;
544
545 /* assume cell needs no further looks */
546 examinecell = FALSE;
547
548 /* next look at arcs that run within this nodeinst */
549 cla_modwithin(ni, dangle, dtrans);
550
551 /* next look at the rest of the rigid arcs on this nodeinst */
552 if (cla_modrigid(ni, dangle, dtrans)) examinecell = TRUE;
553
554 /* finally, look at rest of the flexible arcs on this nodeinst */
555 if (cla_modflex(ni, dangle, dtrans)) examinecell = TRUE;
556
557 return(examinecell);
558 }
559
560 /*
561 * routine to modify the arcs that run within nodeinst "ni"
562 */
cla_modwithin(NODEINST * ni,INTBIG dangle,INTBIG dtrans)563 void cla_modwithin(NODEINST *ni, INTBIG dangle, INTBIG dtrans)
564 {
565 REGISTER PORTARCINST *pi;
566 REGISTER ARCINST *ai;
567 REGISTER INTBIG ox, oy, i, total;
568 INTBIG nox, noy, onox, onoy;
569 XARRAY trans;
570
571 /* ignore all this stuff if the node just got created */
572 if (((CHANGE *)ni->changeaddr)->changetype == NODEINSTNEW) return;
573
574 /* build a list of arcs with both ends on this nodeinst */
575 total = 0;
576 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
577 {
578 /* ignore if arcinst is not within the node */
579 ai = pi->conarcinst;
580 if (ai->end[0].nodeinst != ai->end[1].nodeinst) continue;
581 if (ai->changed == cla_changeclock) continue;
582 total++;
583 }
584 if (total == 0) return;
585 if (total > cla_workingarccount)
586 {
587 if (cla_workingarccount > 0) efree((CHAR *)cla_workingarcs);
588 cla_workingarccount = 0;
589 cla_workingarcs = (ARCINST **)emalloc(total * (sizeof (ARCINST *)), db_cluster);
590 if (cla_workingarcs == 0) return;
591 cla_workingarccount = total;
592 }
593 total = 0;
594 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
595 {
596 /* ignore if arcinst is not within the node */
597 ai = pi->conarcinst;
598 if (ai->end[0].nodeinst != ai->end[1].nodeinst) continue;
599 if (ai->changed == cla_changeclock) continue;
600 for(i=0; i<total; i++) if (cla_workingarcs[i] == ai) break;
601 if (i >= total)
602 cla_workingarcs[total++] = ai;
603 }
604
605 /* look for arcs with both ends on this nodeinst */
606 for(i=0; i<total; i++)
607 {
608 ai = cla_workingarcs[i];
609 if ((ai->userbits&DEADA) != 0) continue;
610
611 /* prepare transformation matrix */
612 makeangle(dangle, dtrans, trans);
613
614 /* compute old center of nodeinst */
615 ox = (((CHANGE *)ni->changeaddr)->p1 + ((CHANGE *)ni->changeaddr)->p3) / 2;
616 oy = (((CHANGE *)ni->changeaddr)->p2 + ((CHANGE *)ni->changeaddr)->p4) / 2;
617
618 /* determine the new ends of the arcinst */
619 cla_adjustmatrix(ni, ai->end[0].portarcinst->proto, trans);
620 xform(ai->end[0].xpos-ox, ai->end[0].ypos-oy, &nox, &noy, trans);
621 cla_adjustmatrix(ni, ai->end[1].portarcinst->proto, trans);
622 xform(ai->end[1].xpos-ox, ai->end[1].ypos-oy, &onox, &onoy, trans);
623 #ifdef CLA_DEBUG
624 if (cla_conlaydebug)
625 ttyputmsg(M_("Internal arc %s moves 0:%s,%s 1:%s,%s"),
626 describearcinst(ai), latoa(nox, 0), latoa(noy, 0), latoa(onox, 0), latoa(onoy, 0));
627 #endif
628 /* move the arcinst */
629 cla_domovearcinst(ai, nox, noy, onox, onoy, 0);
630 }
631 }
632
633 /*
634 * routine to modify the rigid arcs that run from nodeinst "ni". The nodeinst
635 * has changed "dangle" tenth-degrees. If any nodes that are ports in the
636 * current cell change position, the routine returns nonzero to indicate
637 * that instances of the current cell must be examined for arcinst motion.
638 */
cla_modrigid(NODEINST * ni,INTBIG dangle,INTBIG dtrans)639 BOOLEAN cla_modrigid(NODEINST *ni, INTBIG dangle, INTBIG dtrans)
640 {
641 REGISTER PORTPROTO *opt;
642 REGISTER PORTARCINST *pi;
643 REGISTER ARCINST *ai, **arclist;
644 REGISTER NODEINST *ono;
645 INTBIG ax[2], ay[2], onox, onoy, dx, dy;
646 XARRAY trans;
647 REGISTER INTBIG othx, othy, ox, oy, i, total, thisend, thatend;
648 REGISTER INTBIG nextangle;
649 REGISTER BOOLEAN examinecell, locked;
650
651 /* build a list of the rigid arcs on this nodeinst */
652 total = 0;
653 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
654 {
655 /* ignore if arcinst is not rigid */
656 ai = pi->conarcinst;
657 if (ai->changed == cla_changeclock-1 || ai->changed == cla_changeclock+1) continue;
658 if (ai->changed != cla_changeclock-2 && (ai->userbits&FIXED) == 0) continue;
659 total++;
660 }
661 if (total == 0) return(FALSE);
662 arclist = (ARCINST **)emalloc(total * (sizeof (ARCINST *)), el_tempcluster);
663 if (arclist == 0) return(FALSE);
664 i = 0;
665 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
666 {
667 /* ignore if arcinst is not rigid */
668 ai = pi->conarcinst;
669 if (ai->changed == cla_changeclock-1 || ai->changed == cla_changeclock+1) continue;
670 if (ai->changed != cla_changeclock-2 && (ai->userbits&FIXED) == 0) continue;
671 arclist[i++] = ai;
672 }
673
674 /* if simple rotation on transposed nodeinst, reverse rotation */
675 nextangle = dangle;
676 if (((CHANGE *)ni->changeaddr)->changetype != NODEINSTNEW &&
677 ((CHANGE *)ni->changeaddr)->p6 != 0 && dtrans != 0)
678 nextangle = (3600 - dangle) % 3600;
679
680 /* prepare transformation matrix and angle/transposition information */
681 makeangle(nextangle, dtrans, trans);
682
683 /* look for rigid arcs on this nodeinst */
684 examinecell = FALSE;
685 for(i=0; i<total; i++)
686 {
687 ai = arclist[i];
688 if ((ai->userbits&DEADA) != 0) continue;
689 ai->userbits &= ~FIXEDMOD;
690
691 /* if rigid arcinst has already been changed check its connectivity */
692 if (ai->changed == cla_changeclock)
693 {
694 cla_ensurearcinst(ai, 0);
695 continue;
696 }
697
698 /* find out which end of the arcinst is where, ignore internal arcs */
699 thisend = thatend = 0;
700 if (ai->end[0].nodeinst == ni) thatend++;
701 if (ai->end[1].nodeinst == ni) thisend++;
702 if (thisend == thatend) continue;
703
704 if (((CHANGE *)ni->changeaddr)->changetype == NODEINSTNEW) ox = oy = 0; else
705 {
706 ox = (((CHANGE *)ni->changeaddr)->p1 + ((CHANGE *)ni->changeaddr)->p3) / 2;
707 oy = (((CHANGE *)ni->changeaddr)->p2 + ((CHANGE *)ni->changeaddr)->p4) / 2;
708 cla_adjustmatrix(ni, ai->end[thisend].portarcinst->proto, trans);
709 }
710
711 /* figure out the new location of this arcinst connection */
712 xform(ai->end[thisend].xpos-ox, ai->end[thisend].ypos-oy,
713 &ax[thisend], &ay[thisend], trans);
714
715 ono = ai->end[thatend].nodeinst;
716 opt = ai->end[thatend].portarcinst->proto;
717 #ifdef CLA_DEBUG
718 if (cla_conlaydebug)
719 ttyputmsg(M_("Modify rigid arc %s from %s to %s"),
720 describearcinst(ai), describenodeinst(ni), describenodeinst(ono));
721 #endif
722
723 /* figure out the new location of that arcinst connection */
724 xform(ai->end[thatend].xpos-ox, ai->end[thatend].ypos-oy, &ax[thatend],
725 &ay[thatend], trans);
726 #ifdef CLA_DEBUG
727 if (cla_conlaydebug)
728 ttyputmsg(M_("Other end of arc moves to (%s,%s)"),
729 latoa(ax[thatend], 0), latoa(ay[thatend], 0));
730 #endif
731
732 /* see if other nodeinst has changed */
733 locked = FALSE;
734 if (ono->changed == cla_changeclock) locked = TRUE; else
735 {
736 if ((ono->userbits&NILOCKED) != 0) locked = TRUE; else
737 {
738 if (ono->proto->primindex == 0)
739 {
740 if ((ono->parent->userbits&NPILOCKED) != 0) locked = TRUE;
741 } else
742 {
743 if ((us_useroptions&NOPRIMCHANGES) != 0 &&
744 (ono->proto->userbits&LOCKEDPRIM) != 0) locked = TRUE;
745 }
746 }
747 }
748 if (!locked)
749 {
750 /* compute port motion within the other nodeinst (is this right? !!!) */
751 cla_oldportposition(ono, opt, &onox, &onoy);
752 portposition(ono, opt, &dx, &dy);
753 othx = dx - onox; othy = dy - onoy;
754
755 /* figure out the new location of the other nodeinst */
756 onox = (ono->lowx + ono->highx) / 2;
757 onoy = (ono->lowy + ono->highy) / 2;
758 xform(onox-ox, onoy-oy, &dx, &dy, trans);
759 dx = dx - onox - othx;
760 dy = dy - onoy - othy;
761
762 /* move the other nodeinst */
763 nextangle = dangle;
764 if (dtrans != 0 && ono->transpose != ((CHANGE *)ni->changeaddr)->p6)
765 nextangle = (3600 - nextangle) % 3600;
766
767 /* ignore null motion on nodes that have already been examined */
768 if (dx != 0 || dy != 0 || nextangle != 0 || dtrans != 0 || ono->changed != cla_changeclock-1)
769 {
770 ai->userbits |= FIXEDMOD;
771 if (cla_modifynodeinst(ono, dx, dy, dx, dy, nextangle, dtrans, TRUE))
772 examinecell = TRUE;
773 }
774 }
775
776 /* move the arcinst */
777 #ifdef CLA_DEBUG
778 if (cla_conlaydebug)
779 ttyputmsg(M_("Now arc runs from (%s,%s) to (%s,%s)"),
780 latoa(ax[0], 0), latoa(ay[0], 0), latoa(ax[1], 0), latoa(ay[1], 0));
781 #endif
782 cla_domovearcinst(ai, ax[0],ay[0], ax[1],ay[1], 0);
783 }
784
785 /* re-scan rigid arcs and recursively modify arcs on other nodes */
786 for(i=0; i<total; i++)
787 {
788 ai = arclist[i];
789 if ((ai->userbits&DEADA) != 0) continue;
790
791 /* only want arcinst that was just explored */
792 if ((ai->userbits & FIXEDMOD) == 0) continue;
793
794 /* get the other nodeinst */
795 if (ai->end[0].nodeinst == ni) ono = ai->end[1].nodeinst; else
796 ono = ai->end[0].nodeinst;
797
798 nextangle = dangle;
799 if (dtrans != 0 && ((CHANGE *)ono->changeaddr)->p6 != ((CHANGE *)ni->changeaddr)->p6)
800 nextangle = (3600 - nextangle) % 3600;
801 if (cla_modnodearcs(ono, nextangle, dtrans)) examinecell = TRUE;
802 }
803 efree((CHAR *)arclist);
804 return(examinecell);
805 }
806
807 /*
808 * routine to modify the flexible arcs connected to nodeinst "ni". If any
809 * nodes that are ports move, the routine returns nonzero to indicate that
810 * instances of the current cell must be examined for arcinst motion
811 */
cla_modflex(NODEINST * ni,INTBIG dangle,INTBIG dtrans)812 BOOLEAN cla_modflex(NODEINST *ni, INTBIG dangle, INTBIG dtrans)
813 {
814 REGISTER PORTARCINST *pi;
815 REGISTER ARCINST *ai, **arclist;
816 REGISTER NODEINST *ono;
817 REGISTER INTBIG i, total, ox, oy, odx, ody, thisend, thatend, mangle;
818 REGISTER INTBIG nextangle;
819 REGISTER BOOLEAN examinecell;
820 XARRAY trans;
821 INTBIG ax[2], ay[2], dx, dy, lx, hx, ly, hy;
822 static POLYGON *poly = NOPOLYGON;
823
824 /* build a list of the flexible arcs on this nodeinst */
825 total = 0;
826 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
827 {
828 /* ignore if arcinst is not flexible */
829 ai = pi->conarcinst;
830 if (ai->changed == cla_changeclock-2 || ai->changed == cla_changeclock) continue;
831 if (ai->changed != cla_changeclock-1 && (ai->userbits&FIXED) != 0) continue;
832 total++;
833 }
834 if (total == 0) return(FALSE);
835 arclist = (ARCINST **)emalloc(total * (sizeof (ARCINST *)), el_tempcluster);
836 if (arclist == 0) return(FALSE);
837 i = 0;
838 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
839 {
840 /* ignore if arcinst is not flexible */
841 ai = pi->conarcinst;
842 if (ai->changed == cla_changeclock-2 || ai->changed == cla_changeclock) continue;
843 if (ai->changed != cla_changeclock-1 && (ai->userbits&FIXED) != 0) continue;
844 arclist[i++] = ai;
845 }
846
847 /* if simple rotation on transposed nodeinst, reverse rotation */
848 nextangle = dangle;
849 if (((CHANGE *)ni->changeaddr)->changetype != NODEINSTNEW &&
850 ((CHANGE *)ni->changeaddr)->p6 != 0 && dtrans != 0)
851 nextangle = (3600 - dangle) % 3600;
852
853 /* prepare transformation matrix and angle/transposition information */
854 makeangle(nextangle, dtrans, trans);
855
856 /* look at all of the flexible arcs on this nodeinst */
857 examinecell = FALSE;
858 for(i=0; i<total; i++)
859 {
860 ai = arclist[i];
861 if ((ai->userbits&DEADA) != 0) continue;
862
863 /* if flexible arcinst has been changed, verify its connectivity */
864 #ifdef CLA_DEBUG
865 if (cla_conlaydebug)
866 {
867 ttyputmsg(M_("Considering arc %s (clock=%ld, curclock=%ld)"),
868 describearcinst(ai), ai->changed, cla_changeclock+1);
869 }
870 #endif
871 if (ai->changed >= cla_changeclock+1)
872 {
873 cla_ensurearcinst(ai, 1);
874 continue;
875 }
876
877 /* figure where each end of the arcinst is, ignore internal arcs */
878 thisend = thatend = 0;
879 if (ai->end[0].nodeinst == ni) thatend++;
880 if (ai->end[1].nodeinst == ni) thisend++;
881 if (thisend == thatend) continue;
882
883 /* if nodeinst motion stays within port area, ignore the arcinst */
884 if ((ai->userbits&CANTSLIDE) == 0 &&
885 db_stillinport(ai, thisend, ai->end[thisend].xpos, ai->end[thisend].ypos))
886 continue;
887
888 if (((CHANGE *)ni->changeaddr)->changetype == NODEINSTNEW) ox = oy = 0; else
889 {
890 ox = (((CHANGE *)ni->changeaddr)->p1 + ((CHANGE *)ni->changeaddr)->p3) / 2;
891 oy = (((CHANGE *)ni->changeaddr)->p2 + ((CHANGE *)ni->changeaddr)->p4) / 2;
892 cla_adjustmatrix(ni, ai->end[thisend].portarcinst->proto, trans);
893 }
894
895 /* figure out the new location of this arcinst connection */
896 xform(ai->end[thisend].xpos-ox, ai->end[thisend].ypos-oy,
897 &ax[thisend], &ay[thisend], trans);
898
899 /* make sure the arc end is still in the port */
900 (void)needstaticpolygon(&poly, 4, db_cluster);
901 shapeportpoly(ai->end[thisend].nodeinst, ai->end[thisend].portarcinst->proto,
902 poly, FALSE);
903 if (!isinside(ax[thisend], ay[thisend], poly))
904 {
905 getbbox(poly, &lx, &hx, &ly, &hy);
906 if (ay[thisend] >= ly && ay[thisend] <= hy)
907 {
908 /* extend arc horizontally to fit in port */
909 if (ax[thisend] < lx) ax[thisend] = lx; else
910 if (ax[thisend] > hx) ax[thisend] = hx;
911 } else if (ax[thisend] >= lx && ax[thisend] <= hx)
912 {
913 /* extend arc vertically to fit in port */
914 if (ay[thisend] < ly) ay[thisend] = ly; else
915 if (ay[thisend] > hy) ay[thisend] = hy;
916 } else
917 {
918 /* extend arc arbitrarily to fit in port */
919 closestpoint(poly, &ax[thisend], &ay[thisend]);
920 }
921 }
922
923 /* get other end of arcinst and its position */
924 ono = ai->end[thatend].nodeinst;
925 ax[thatend] = ai->end[thatend].xpos;
926 ay[thatend] = ai->end[thatend].ypos;
927 #ifdef CLA_DEBUG
928 if (cla_conlaydebug)
929 {
930 ttyputmsg(M_("Modify flexible arc %s from %s to %s"),
931 describearcinst(ai), describenodeinst(ni), describenodeinst(ono));
932 }
933 #endif
934
935 /* see if other nodeinst has changed */
936 mangle = 1;
937 if ((ai->userbits&FIXANG) == 0) mangle = 0; else
938 {
939 if ((ono->userbits&NILOCKED) != 0) mangle = 0; else
940 {
941 if (ono->proto->primindex == 0)
942 {
943 if ((ono->parent->userbits&NPILOCKED) != 0) mangle = 0;
944 } else
945 {
946 if ((us_useroptions&NOPRIMCHANGES) != 0 &&
947 (ono->proto->userbits&LOCKEDPRIM) != 0) mangle = 0;
948 }
949 }
950 }
951 if (mangle != 0)
952 {
953 /* other nodeinst untouched, mangle it */
954 dx = ax[thisend] - ai->end[thisend].xpos;
955 dy = ay[thisend] - ai->end[thisend].ypos;
956 odx = ax[thatend] - ai->end[thatend].xpos;
957 ody = ay[thatend] - ai->end[thatend].ypos;
958 if (ai->end[thisend].xpos == ai->end[thatend].xpos)
959 {
960 /* null arcinst must not be explicitly horizontal */
961 if (ai->end[thisend].ypos != ai->end[thatend].ypos ||
962 ((ai->userbits&AANGLE) >> AANGLESH) == 90 ||
963 ((ai->userbits&AANGLE) >> AANGLESH) == 270)
964 {
965 /* vertical arcinst: see if it really moved in X */
966 if (dx == odx) dx = odx = 0;
967
968 /* move horizontal, shrink vertical */
969 ax[thatend] += dx-odx;
970
971 /* see if next nodeinst need not be moved */
972 if (dx != odx && (ai->userbits&CANTSLIDE) == 0 &&
973 db_stillinport(ai, thatend, ax[thatend], ay[thatend]))
974 dx = odx = 0;
975
976 /* if other node already moved, don't move it any more */
977 if (ono->changed >= cla_changeclock) dx = odx = 0;
978
979 #ifdef CLA_DEBUG
980 if (cla_conlaydebug)
981 ttyputmsg(M_(" Moving other end of arc to (%s,%s), other node by (%s,0)"),
982 latoa(ax[thatend], 0), latoa(ay[thatend], 0), latoa(dx-odx, 0));
983 #endif
984 if (dx != odx)
985 {
986 if (cla_modifynodeinst(ono, dx-odx, 0, dx-odx, 0, 0, 0, TRUE))
987 examinecell = TRUE;
988 }
989 cla_domovearcinst(ai, ax[0],ay[0], ax[1],ay[1], 1);
990 if (dx != odx)
991 if (cla_modnodearcs(ono, 0, 0)) examinecell = TRUE;
992 continue;
993 }
994 }
995 if (ai->end[thisend].ypos == ai->end[thatend].ypos)
996 {
997 /* horizontal arcinst: see if it really moved in Y */
998 if (dy == ody) dy = ody = 0;
999
1000 /* shrink horizontal, move vertical */
1001 ay[thatend] += dy-ody;
1002
1003 /* see if next nodeinst need not be moved */
1004 if (dy != ody && (ai->userbits&CANTSLIDE) == 0 &&
1005 db_stillinport(ai, thatend, ax[thatend], ay[thatend]))
1006 dy = ody = 0;
1007
1008 /* if other node already moved, don't move it any more */
1009 if (ono->changed >= cla_changeclock) dx = odx = 0;
1010
1011 #ifdef CLA_DEBUG
1012 if (cla_conlaydebug)
1013 ttyputmsg(M_(" Moving other end of arc to (%s,%s), other node by (0,%s)"),
1014 latoa(ax[thatend], 0), latoa(ay[thatend], 0), latoa(dy-ody, 0));
1015 #endif
1016 if (dy != ody)
1017 {
1018 if (cla_modifynodeinst(ono, 0, dy-ody, 0, dy-ody, 0, 0, TRUE))
1019 examinecell = TRUE;
1020 }
1021 cla_domovearcinst(ai, ax[0],ay[0], ax[1],ay[1], 1);
1022 if (dy != ody) if (cla_modnodearcs(ono, 0, 0)) examinecell = TRUE;
1023 continue;
1024 }
1025
1026 /***** THIS CODE HANDLES ALL-ANGLE RIGIDITY WITH THE FIXED-ANGLE CONSTRAINT *****/
1027
1028 /* special code to handle nonorthogonal fixed-angles */
1029 cla_nonorthogfixang(ai, thisend, thatend, ono, ax, ay);
1030 dx = ax[thatend] - ai->end[thatend].xpos;
1031 dy = ay[thatend] - ai->end[thatend].ypos;
1032
1033 /* change the arc */
1034 cla_updatearc(ai, ax[0],ay[0], ax[1],ay[1], 1);
1035
1036 /* if other node already moved, don't move it any more */
1037 if (ono->changed >= cla_changeclock) dx = dy = 0;
1038
1039 if (dx != 0 || dy != 0)
1040 {
1041 if (cla_modifynodeinst(ono, dx, dy, dx, dy, 0, 0, TRUE))
1042 examinecell = TRUE;
1043 if (cla_modnodearcs(ono, 0, 0)) examinecell = TRUE;
1044 }
1045 continue;
1046 }
1047
1048 /* other node has changed or arc is funny, just use its position */
1049 #ifdef CLA_DEBUG
1050 if (cla_conlaydebug)
1051 ttyputmsg(M_(" ! Moving arc %s to (%s,%s)-(%s,%s)"), describearcinst(ai),
1052 latoa(ax[0], 0), latoa(ay[0], 0), latoa(ax[1], 0), latoa(ay[1], 0));
1053 #endif
1054 cla_domovearcinst(ai, ax[0],ay[0], ax[1],ay[1], 1);
1055 }
1056 efree((CHAR *)arclist);
1057 return(examinecell);
1058 }
1059
1060 /*
1061 * routine to determine the motion of a nonorthogonal arcinst "ai" given that
1062 * its "thisend" end has moved to (ax[thisend],ay[thisend]) and its other end must be
1063 * determined in (ax[thatend],ay[thatend]). The node on the other end is "ono".
1064 */
cla_nonorthogfixang(ARCINST * ai,INTBIG thisend,INTBIG thatend,NODEINST * ono,INTBIG ax[2],INTBIG ay[2])1065 void cla_nonorthogfixang(ARCINST *ai, INTBIG thisend, INTBIG thatend, NODEINST *ono,
1066 INTBIG ax[2], INTBIG ay[2])
1067 {
1068 REGISTER PORTARCINST *pi;
1069 REGISTER ARCINST *oai, *bestai;
1070 REGISTER INTBIG bestdist;
1071 INTBIG ix, iy;
1072
1073 /* look for longest other arc on "ono" to determine proper end position */
1074 bestdist = -1;
1075 for(pi = ono->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1076 {
1077 oai = pi->conarcinst;
1078 if (oai == ai) continue;
1079 if (oai->length < bestdist) continue;
1080 bestdist = oai->length;
1081 bestai = oai;
1082 }
1083
1084 /* if no other arcs, allow that end to move the same as this end */
1085 if (bestdist < 0)
1086 {
1087 ax[thatend] += ax[thisend] - ai->end[thisend].xpos;
1088 ay[thatend] += ay[thisend] - ai->end[thisend].ypos;
1089 return;
1090 }
1091
1092 /* compute intersection of arc "bestai" with new moved arc "ai" */
1093 if (intersect(ax[thisend],ay[thisend], ((ai->userbits&AANGLE) >> AANGLESH) * 10,
1094 bestai->end[0].xpos, bestai->end[0].ypos,
1095 ((bestai->userbits&AANGLE) >> AANGLESH) * 10, &ix, &iy) < 0)
1096 {
1097 ax[thatend] += ax[thisend] - ai->end[thisend].xpos;
1098 ay[thatend] += ay[thisend] - ai->end[thisend].ypos;
1099 return;
1100 }
1101 ax[thatend] = ix;
1102 ay[thatend] = iy;
1103 }
1104
1105 /*
1106 * routine to ensure that arcinst "ai" is still connected properly at each
1107 * end. If it is not, it must be jogged or adjusted. The nature of the
1108 * arcinst is in "arctyp" (0 for rigid, 1 for flexible)
1109 */
cla_ensurearcinst(ARCINST * ai,INTBIG arctyp)1110 void cla_ensurearcinst(ARCINST *ai, INTBIG arctyp)
1111 {
1112 REGISTER BOOLEAN inside0, inside1;
1113 INTBIG lx0, lx1, hx0, hx1, ly0, ly1, hy0, hy1, fx, fy, tx, ty;
1114 static POLYGON *poly0 = NOPOLYGON, *poly1 = NOPOLYGON;
1115
1116 /* if nothing is outside port, quit */
1117 inside0 = db_stillinport(ai, 0, ai->end[0].xpos, ai->end[0].ypos);
1118 inside1 = db_stillinport(ai, 1, ai->end[1].xpos, ai->end[1].ypos);
1119 if (inside0 && inside1) return;
1120
1121 /* make sure there is a polygon */
1122 (void)needstaticpolygon(&poly0, 4, cla_constraint->cluster);
1123 (void)needstaticpolygon(&poly1, 4, cla_constraint->cluster);
1124
1125 /* get area of the ports */
1126 shapeportpoly(ai->end[0].nodeinst, ai->end[0].portarcinst->proto, poly0, FALSE);
1127 shapeportpoly(ai->end[1].nodeinst, ai->end[1].portarcinst->proto, poly1, FALSE);
1128
1129 /* if arcinst is not fixed-angle, run it directly to the port centers */
1130 if ((ai->userbits&FIXANG) == 0)
1131 {
1132 getcenter(poly0, &fx, &fy);
1133 getcenter(poly1, &tx, &ty);
1134 #ifdef CLA_DEBUG
1135 if (cla_conlaydebug)
1136 ttyputmsg(M_("Ensuring rigid arc %s"), describearcinst(ai));
1137 #endif
1138 cla_domovearcinst(ai, fx, fy, tx, ty, arctyp);
1139 return;
1140 }
1141
1142 /* get bounding boxes of polygons */
1143 getbbox(poly0, &lx0, &hx0, &ly0, &hy0);
1144 getbbox(poly1, &lx1, &hx1, &ly1, &hy1);
1145
1146 /* if manhattan path runs between the ports, adjust the arcinst */
1147 if (lx0 <= hx1 && lx1 <= hx0)
1148 {
1149 /* arcinst runs vertically */
1150 tx = fx = (maxi(lx0,lx1) + mini(hx0,hx1)) / 2;
1151 fy = (ly0+hy0) / 2; ty = (ly1+hy1) / 2;
1152 closestpoint(poly0, &fx, &fy);
1153 closestpoint(poly1, &tx, &ty);
1154 #ifdef CLA_DEBUG
1155 if (cla_conlaydebug)
1156 ttyputmsg(M_("Ensuring manhattan arc %s"), describearcinst(ai));
1157 #endif
1158 cla_domovearcinst(ai, fx, fy, tx, ty, arctyp);
1159 return;
1160 }
1161 if (ly0 <= hy1 && ly1 <= hy0)
1162 {
1163 /* arcinst runs horizontally */
1164 ty = fy = (maxi(ly0,ly1) + mini(hy0,hy1)) / 2;
1165 fx = (lx0+hx0) / 2; tx = (lx1+hx1) / 2;
1166 closestpoint(poly0, &fx, &fy);
1167 closestpoint(poly1, &tx, &ty);
1168 #ifdef CLA_DEBUG
1169 if (cla_conlaydebug)
1170 ttyputmsg(M_("Ensuring manhattan arc %s"), describearcinst(ai));
1171 #endif
1172 cla_domovearcinst(ai, fx, fy, tx, ty, arctyp);
1173 return;
1174 }
1175
1176 /* give up and jog the arcinst */
1177 getcenter(poly0, &fx, &fy);
1178 getcenter(poly1, &tx, &ty);
1179 cla_domovearcinst(ai, fx, fy, tx, ty, arctyp);
1180 }
1181
1182 /*
1183 * routine to update arc "ai" so that its ends run from (fx,fy) to (tx,ty).
1184 * The type of the arc is in "arctyp" for marking the change.
1185 */
cla_updatearc(ARCINST * ai,INTBIG fx,INTBIG fy,INTBIG tx,INTBIG ty,INTBIG arctyp)1186 void cla_updatearc(ARCINST *ai, INTBIG fx, INTBIG fy, INTBIG tx, INTBIG ty, INTBIG arctyp)
1187 {
1188 REGISTER INTBIG oldxA, oldyA, oldxB, oldyB, oldlen;
1189
1190 (void)db_change((INTBIG)ai, OBJECTSTART, VARCINST, 0, 0, 0, 0, 0);
1191
1192 /* save old arc state */
1193 oldxA = ai->end[0].xpos; oldyA = ai->end[0].ypos;
1194 oldxB = ai->end[1].xpos; oldyB = ai->end[1].ypos;
1195 oldlen = ai->length;
1196
1197 /* set the proper arcinst position */
1198 #ifdef CLA_DEBUG
1199 if (cla_conlaydebug)
1200 ttyputmsg(M_("Change arc %s from (%s,%s)-(%s,%s) to (%s,%s)-(%s,%s)"),
1201 describearcinst(ai), latoa(ai->end[0].xpos, 0), latoa(ai->end[0].ypos, 0),
1202 latoa(ai->end[1].xpos, 0), latoa(ai->end[1].ypos, 0),
1203 latoa(fx, 0), latoa(fy, 0), latoa(tx, 0), latoa(ty, 0));
1204 #endif
1205 ai->end[0].xpos = fx;
1206 ai->end[0].ypos = fy;
1207 ai->end[1].xpos = tx;
1208 ai->end[1].ypos = ty;
1209 ai->length = computedistance(fx,fy, tx,ty);
1210 determineangle(ai);
1211 (void)setshrinkvalue(ai, TRUE);
1212 updategeom(ai->geom, ai->parent);
1213
1214 /* see if the arc has changed before */
1215 if (((CHANGE *)ai->changeaddr) == NOCHANGE)
1216 {
1217 /* announce new arcinst change */
1218 ai->changeaddr = (CHAR *)db_change((INTBIG)ai, ARCINSTMOD, oldxA,
1219 oldyA, oldxB, oldyB, ai->width, oldlen);
1220 ai->changed = cla_changeclock + arctyp;
1221 }
1222 (void)db_change((INTBIG)ai, OBJECTEND, VARCINST, 0, 0, 0, 0, 0);
1223 }
1224
cla_domovearcinst(ARCINST * ai,INTBIG fx,INTBIG fy,INTBIG tx,INTBIG ty,INTBIG arctyp)1225 void cla_domovearcinst(ARCINST *ai, INTBIG fx, INTBIG fy, INTBIG tx, INTBIG ty, INTBIG arctyp)
1226 {
1227 REGISTER NODEPROTO *np, *pnt;
1228 REGISTER ARCPROTO *ap;
1229 REGISTER ARCINST *ar1, *ar2, *ar3;
1230 REGISTER PORTPROTO *pp, *fpt, *tpt;
1231 REGISTER NODEINST *no1, *no2, *fno, *tno;
1232 REGISTER INTBIG oldxA, oldyA, oldxB, oldyB, wid, oldbits, lx, hx, ly, hy;
1233 INTBIG psx, psy;
1234
1235 /* check for null arcinst motion */
1236 if (fx == ai->end[0].xpos && fy == ai->end[0].ypos &&
1237 tx == ai->end[1].xpos && ty == ai->end[1].ypos)
1238 {
1239 /* only ignore null motion on fixed-angle requests */
1240 if (arctyp != 0) return;
1241 }
1242
1243 /* if the angle is the same or doesn't need to be, simply make the change */
1244 if ((ai->userbits&FIXANG) == 0 ||
1245 ((ai->userbits&FIXED) != 0 && ai->changed != cla_changeclock-1) ||
1246 ai->changed == cla_changeclock-2 ||
1247 (fx == tx && fy == ty) ||
1248 ((((INTBIG)ai->userbits&AANGLE) >> AANGLESH)*10)%1800 == figureangle(fx, fy, tx, ty)%1800)
1249 {
1250 cla_updatearc(ai, fx, fy, tx, ty, arctyp);
1251 return;
1252 }
1253 #ifdef CLA_DEBUG
1254 if (cla_conlaydebug)
1255 {
1256 ttyputmsg(M_("Jogging arc %s (0%o) to run from (%s,%s) to (%s,%s)"),
1257 describearcinst(ai), ai, latoa(fx, 0), latoa(fy, 0), latoa(tx, 0), latoa(ty, 0));
1258 }
1259 #endif
1260
1261 /* manhattan arcinst becomes nonmanhattan: remember facts about it */
1262 fno = ai->end[0].nodeinst; fpt = ai->end[0].portarcinst->proto;
1263 tno = ai->end[1].nodeinst; tpt = ai->end[1].portarcinst->proto;
1264 ap = ai->proto; pnt = ai->parent; wid = ai->width;
1265 oldbits = ai->userbits;
1266
1267 /* figure out what nodeinst proto connects these arcs */
1268 np = getpinproto(ap);
1269 defaultnodesize(np, &psx, &psy);
1270
1271 /* replace it with three arcs and two nodes */
1272 if (ai->end[0].xpos == ai->end[1].xpos)
1273 {
1274 /* arcinst was vertical */
1275 oldyA = oldyB = (ty+fy) / 2;
1276 oldxA = fx; oldxB = tx;
1277 lx = oldxB - psx/2; hx = lx + psx;
1278 ly = oldyB - psy/2; hy = ly + psy;
1279 no1 = db_newnodeinst(np, lx, hx, ly, hy, 0, 0, pnt);
1280 lx = oldxA - psx/2; hx = lx + psx;
1281 ly = oldyA - psy/2; hy = ly + psy;
1282 no2 = db_newnodeinst(np, lx, hx, ly, hy, 0, 0, pnt);
1283 } else
1284 {
1285 /* assume horizontal arcinst */
1286 oldyA = fy; oldyB = ty;
1287 oldxA = oldxB = (tx+fx) / 2;
1288 lx = oldxB - psx/2; hx = lx + psx;
1289 ly = oldyB - psy/2; hy = ly + psy;
1290 no1 = db_newnodeinst(np, lx, hx, ly, hy, 0, 0, pnt);
1291 lx = oldxA - psx/2; hx = lx + psx;
1292 ly = oldyA - psy/2; hy = ly + psy;
1293 no2 = db_newnodeinst(np, lx, hx, ly, hy, 0, 0, pnt);
1294 }
1295 if (no1 == NONODEINST || no2 == NONODEINST)
1296 {
1297 ttyputerr(_("Problem creating jog pins"));
1298 return;
1299 }
1300 (void)db_change((INTBIG)no1, OBJECTEND, VNODEINST, 0, 0, 0, 0, 0);
1301 (void)db_change((INTBIG)no2, OBJECTEND, VNODEINST, 0, 0, 0, 0, 0);
1302 pp = np->firstportproto;
1303 ar1 = db_newarcinst(ap, wid, oldbits, fno, fpt, fx,fy, no2, pp, oldxA,oldyA, pnt);
1304 if ((oldbits&ISNEGATED) != 0) oldbits &= ~ISNEGATED;
1305 ar2 = db_newarcinst(ap, wid, oldbits, no2, pp, oldxA,oldyA, no1, pp, oldxB,oldyB, pnt);
1306 ar3 = db_newarcinst(ap, wid, oldbits, no1, pp, oldxB,oldyB, tno, tpt, tx,ty, pnt);
1307 if (ar1 == NOARCINST || ar2 == NOARCINST || ar3 == NOARCINST)
1308 {
1309 ttyputerr(_("Problem creating jog arcs"));
1310 return;
1311 }
1312 (void)copyvars((INTBIG)ai, VARCINST, (INTBIG)ar2, VARCINST, FALSE);
1313 (void)db_change((INTBIG)ar1, OBJECTEND, VARCINST, 0, 0, 0, 0, 0);
1314 (void)db_change((INTBIG)ar2, OBJECTEND, VARCINST, 0, 0, 0, 0, 0);
1315 (void)db_change((INTBIG)ar3, OBJECTEND, VARCINST, 0, 0, 0, 0, 0);
1316 ar1->changed = cla_changeclock + arctyp;
1317 ar2->changed = cla_changeclock + arctyp;
1318 ar3->changed = cla_changeclock + arctyp;
1319
1320 /* now kill the arcinst */
1321 (void)db_change((INTBIG)ai, OBJECTSTART, VARCINST, 0, 0, 0, 0, 0);
1322 if ((CHANGE *)ai->changeaddr != NOCHANGE)
1323 {
1324 ai->end[0].xpos = ((CHANGE *)ai->changeaddr)->p1;
1325 ai->end[0].ypos = ((CHANGE *)ai->changeaddr)->p2;
1326 ai->end[1].xpos = ((CHANGE *)ai->changeaddr)->p3;
1327 ai->end[1].ypos = ((CHANGE *)ai->changeaddr)->p4;
1328 ai->length = computedistance(ai->end[0].xpos, ai->end[0].ypos,
1329 ai->end[1].xpos, ai->end[1].ypos);
1330 ai->width = ((CHANGE *)ai->changeaddr)->p5;
1331 determineangle(ai);
1332 }
1333 db_killarcinst(ai);
1334 }
1335
1336 /*
1337 * routine to adjust the transformation matrix "trans" by placing translation
1338 * information for nodeinst "ni", port "pp".
1339 *
1340 * there are only two types of nodeinst changes: internal and external.
1341 * The internal changes are scaling and port motion changes that
1342 * are usually caused by other changes within the cell. The external
1343 * changes are rotation and transposition. These two changes never
1344 * occur at the same time. There is also translation change that
1345 * can occur at any time and is of no importance here. What is
1346 * important is that the transformation matrix "trans" handles
1347 * the external changes and internal changes. External changes are already
1348 * set by the "makeangle" subroutine and internal changes are
1349 * built into the matrix here.
1350 */
cla_adjustmatrix(NODEINST * ni,PORTPROTO * pp,XARRAY trans)1351 void cla_adjustmatrix(NODEINST *ni, PORTPROTO *pp, XARRAY trans)
1352 {
1353 REGISTER INTBIG ox, oy;
1354 INTBIG onox, onoy, dx, dy;
1355
1356 if (((CHANGE *)ni->changeaddr)->p5 == ni->rotation &&
1357 ((CHANGE *)ni->changeaddr)->p6 == ni->transpose)
1358 {
1359 /* nodeinst did not rotate: adjust for port motion */
1360 cla_oldportposition(ni, pp, &onox, &onoy);
1361 portposition(ni, pp, &dx, &dy);
1362 ox = (((CHANGE *)ni->changeaddr)->p1 + ((CHANGE *)ni->changeaddr)->p3) / 2;
1363 oy = (((CHANGE *)ni->changeaddr)->p2 + ((CHANGE *)ni->changeaddr)->p4) / 2;
1364 #ifdef CLA_DEBUG
1365 if (cla_conlaydebug)
1366 {
1367 ttyputmsg(M_("Node %s port %s was at (%s,%s), is at (%s,%s)"), describenodeinst(ni),
1368 pp->protoname, latoa(onox, 0), latoa(onoy, 0), latoa(dx, 0), latoa(dy, 0));
1369 ttyputmsg(M_(" Node moved (%s,%s)"), latoa(ox, 0), latoa(oy, 0));
1370 }
1371 #endif
1372 trans[2][0] = dx - onox + ox; trans[2][1] = dy - onoy + oy;
1373 } else
1374 {
1375 /* nodeinst rotated: adjust for nodeinst motion */
1376 trans[2][0] = (ni->lowx + ni->highx) / 2;
1377 trans[2][1] = (ni->lowy + ni->highy) / 2;
1378 }
1379 }
1380
1381 /*
1382 * routine to compute the position of portproto "pp" on nodeinst "ni" and
1383 * place the center of the area in the parameters "x" and "y". The position
1384 * is the "old" position, as determined by any changes that may have occured
1385 * to the nodeinst (and any sub-nodes).
1386 */
cla_oldportposition(NODEINST * ni,PORTPROTO * pp,INTBIG * x,INTBIG * y)1387 void cla_oldportposition(NODEINST *ni, PORTPROTO *pp, INTBIG *x, INTBIG *y)
1388 {
1389 REGISTER INTBIG lox, hix, loy, hiy;
1390 XARRAY localtran, subrot, temptr;
1391 static POLYGON *poly = NOPOLYGON;
1392
1393 /* make sure there is a polygon */
1394 (void)needstaticpolygon(&poly, 4, cla_constraint->cluster);
1395
1396 /* descend to the primitive node */
1397 cla_makeoldrot(ni, subrot);
1398 while (ni->proto->primindex == 0)
1399 {
1400 cla_makeoldtrans(ni, localtran);
1401 transmult(localtran, subrot, temptr);
1402 if (((CHANGE *)pp->changeaddr) != NOCHANGE &&
1403 ((CHANGE *)pp->changeaddr)->changetype == PORTPROTOMOD)
1404 {
1405 /* special code for moved port prototypes */
1406 ni = (NODEINST *)((CHANGE *)pp->changeaddr)->p1;
1407 pp = (PORTPROTO *)((CHANGE *)pp->changeaddr)->p2;
1408 } else
1409 {
1410 ni = pp->subnodeinst;
1411 pp = pp->subportproto;
1412 }
1413 cla_makeoldrot(ni, localtran);
1414 transmult(localtran, temptr, subrot);
1415 }
1416
1417 /* save the actual extents of the nodeinst */
1418 lox = ni->lowx; hix = ni->highx;
1419 loy = ni->lowy; hiy = ni->highy;
1420
1421 /* if the node changed, reset it temporarily */
1422 if (((CHANGE *)ni->changeaddr) != NOCHANGE &&
1423 ((CHANGE *)ni->changeaddr)->changetype == NODEINSTMOD)
1424 {
1425 ni->lowx = ((CHANGE *)ni->changeaddr)->p1;
1426 ni->highx = ((CHANGE *)ni->changeaddr)->p3;
1427 ni->lowy = ((CHANGE *)ni->changeaddr)->p2;
1428 ni->highy = ((CHANGE *)ni->changeaddr)->p4;
1429 }
1430
1431 /* now get the polygon describing the port */
1432 shapetransportpoly(ni, pp, poly, subrot);
1433
1434 /* reset the bounds of the nodeinst */
1435 ni->lowx = lox; ni->highx = hix;
1436 ni->lowy = loy; ni->highy = hiy;
1437
1438 /* compute the center of the port */
1439 getcenter(poly, x, y);
1440 }
1441
cla_makeoldrot(NODEINST * ni,XARRAY trans)1442 void cla_makeoldrot(NODEINST *ni, XARRAY trans)
1443 {
1444 REGISTER INTBIG nlx, nly, nhx, nhy;
1445 REGISTER INTSML nr, nt;
1446
1447 /* save values */
1448 nlx = ni->lowx; nly = ni->lowy;
1449 nhx = ni->highx; nhy = ni->highy;
1450 nr = ni->rotation; nt = ni->transpose;
1451
1452 /* set to previous values if they changed */
1453 if (((CHANGE *)ni->changeaddr) != NOCHANGE &&
1454 ((CHANGE *)ni->changeaddr)->changetype == NODEINSTMOD)
1455 {
1456 ni->lowx = ((CHANGE *)ni->changeaddr)->p1;
1457 ni->lowy = ((CHANGE *)ni->changeaddr)->p2;
1458 ni->highx = ((CHANGE *)ni->changeaddr)->p3;
1459 ni->highy = ((CHANGE *)ni->changeaddr)->p4;
1460 ni->rotation = (INTSML)((CHANGE *)ni->changeaddr)->p5;
1461 ni->transpose = (INTSML)((CHANGE *)ni->changeaddr)->p6;
1462 }
1463
1464 /* create the former rotation matrix */
1465 makerot(ni, trans);
1466
1467 /* restore values */
1468 ni->lowx = nlx; ni->lowy = nly;
1469 ni->highx = nhx; ni->highy = nhy;
1470 ni->rotation = nr; ni->transpose = nt;
1471 }
1472
cla_makeoldtrans(NODEINST * ni,XARRAY trans)1473 void cla_makeoldtrans(NODEINST *ni, XARRAY trans)
1474 {
1475 REGISTER INTBIG nlx, nly, nhx, nhy, ntlx, ntly, nthx, nthy;
1476 REGISTER NODEPROTO *np;
1477
1478 /* save values */
1479 np = ni->proto;
1480 nlx = ni->lowx; nly = ni->lowy;
1481 nhx = ni->highx; nhy = ni->highy;
1482 ntlx = np->lowx; ntly = np->lowy;
1483 nthx = np->highx; nthy = np->highy;
1484
1485 /* set to previous values if they changed */
1486 if (((CHANGE *)ni->changeaddr) != NOCHANGE &&
1487 ((CHANGE *)ni->changeaddr)->changetype == NODEINSTMOD)
1488 {
1489 ni->lowx = ((CHANGE *)ni->changeaddr)->p1;
1490 ni->lowy = ((CHANGE *)ni->changeaddr)->p2;
1491 ni->highx = ((CHANGE *)ni->changeaddr)->p3;
1492 ni->highy = ((CHANGE *)ni->changeaddr)->p4;
1493 }
1494 if (((CHANGE *)np->changeaddr) != NOCHANGE &&
1495 ((CHANGE *)np->changeaddr)->changetype == NODEPROTOMOD)
1496 {
1497 np->lowx = ((CHANGE *)np->changeaddr)->p1;
1498 np->highx = ((CHANGE *)np->changeaddr)->p2;
1499 np->lowy = ((CHANGE *)np->changeaddr)->p3;
1500 np->highy = ((CHANGE *)np->changeaddr)->p4;
1501 }
1502
1503 /* create the former translation matrix */
1504 maketrans(ni, trans);
1505
1506 /* restore values */
1507 ni->lowx = nlx; ni->lowy = nly;
1508 ni->highx = nhx; ni->highy = nhy;
1509 np->lowx = ntlx; np->lowy = ntly;
1510 np->highx = nthx; np->highy = nthy;
1511 }
1512
1513 /*
1514 * routine to re-compute the bounds of the cell "cell" (because an object
1515 * has been added or removed from it) and store these bounds in the nominal
1516 * size and the size of each instantiation of the cell. It is also necessary
1517 * to re-position each instantiation of the cell in its proper position list.
1518 * If "forcedlook" is true, the cell is re-examined regardless of
1519 * whether its size changed.
1520 */
cla_computecell(NODEPROTO * cell,BOOLEAN forcedlook)1521 void cla_computecell(NODEPROTO *cell, BOOLEAN forcedlook)
1522 {
1523 REGISTER NODEINST *ni, *lni;
1524 REGISTER NODEPROTO *np, *oneparent;
1525 INTBIG nlx, nhx, nly, nhy, offx, offy;
1526 XARRAY trans;
1527 REGISTER INTBIG dlx, dly, dhx, dhy, flx, fhx, fly, fhy;
1528 REGISTER BOOLEAN mixed;
1529 REGISTER CHANGE *c;
1530 REGISTER LIBRARY *lib;
1531
1532 #ifdef CLA_DEBUG
1533 if (cla_conlaydebug)
1534 ttyputmsg(M_("In computecell on cell %s (fl=%ld)"),
1535 cell->protoname, forcedlook);
1536 #endif
1537 /* get current boundary of cell */
1538 db_boundcell(cell, &nlx,&nhx, &nly,&nhy);
1539
1540 /* quit if it has not changed */
1541 if (cell->lowx == nlx && cell->highx == nhx && cell->lowy == nly &&
1542 cell->highy == nhy && !forcedlook) return;
1543
1544 /* advance the change clock */
1545 cla_changeclock += 4;
1546
1547 /* get former size of cell from change information */
1548 flx = cell->lowx; fhx = cell->highx;
1549 fly = cell->lowy; fhy = cell->highy;
1550 c = (CHANGE *)cell->changeaddr;
1551 if (c != NOCHANGE && c->changetype == NODEPROTOMOD)
1552 {
1553 /* modification changes carry original size */
1554 flx = c->p1; fhx = c->p2;
1555 fly = c->p3; fhy = c->p4;
1556 }
1557
1558 /* update the cell size */
1559 cell->lowx = nlx; cell->highx = nhx;
1560 cell->lowy = nly; cell->highy = nhy;
1561 cell->changeaddr = (CHAR *)db_change((INTBIG)cell, NODEPROTOMOD, flx, fhx, fly, fhy, 0, 0);
1562
1563 /* see if all instances of this cell are in the same location */
1564 mixed = FALSE;
1565 oneparent = NONODEPROTO;
1566 lni = NONODEINST;
1567 for(ni = cell->firstinst; ni != NONODEINST; ni = ni->nextinst)
1568 {
1569 oneparent = ni->parent;
1570 if (lni != NONODEINST) if (ni->parent != lni->parent) mixed = TRUE;
1571 lni = ni;
1572 }
1573
1574 /* if there are no constrained instances of the cell, no change */
1575 if (oneparent == NONODEPROTO) return;
1576
1577 /* if all parent cells the same, make changes to the instances */
1578 if (!mixed && !forcedlook)
1579 {
1580 #ifdef CLA_DEBUG
1581 if (cla_conlaydebug)
1582 ttyputmsg(M_(" Recomputing uniform parents of cell %s"),
1583 describenodeproto(cell));
1584 #endif
1585 dlx = cell->lowx - flx; dhx = cell->highx - fhx;
1586 dly = cell->lowy - fly; dhy = cell->highy - fhy;
1587 for(ni = cell->firstinst; ni != NONODEINST; ni = ni->nextinst)
1588 {
1589 makeangle(ni->rotation, ni->transpose, trans);
1590 xform(dhx+dlx, dhy+dly, &offx, &offy, trans);
1591 nlx = (dlx-dhx+offx)/2; nhx = offx - nlx;
1592 nly = (dly-dhy+offy)/2; nhy = offy - nly;
1593 if (cla_modifynodeinst(ni, nlx, nly, nhx, nhy, 0, 0, TRUE)) forcedlook = TRUE;
1594 }
1595 for(ni = cell->firstinst; ni != NONODEINST; ni = ni->nextinst)
1596 if (cla_modnodearcs(ni, 0, 0)) forcedlook = TRUE;
1597 cla_computecell(oneparent, forcedlook);
1598 return;
1599 }
1600
1601 /*
1602 * if instances are scattered or port motion has occured, examine
1603 * entire database in proper recursive order and adjust cell sizes
1604 */
1605 #ifdef CLA_DEBUG
1606 if (cla_conlaydebug)
1607 ttyputmsg(M_(" Performing complex tree examination"));
1608 #endif
1609 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1610 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1611 np->userbits &= ~(CELLMOD|CELLNOMOD);
1612 cell->userbits |= CELLMOD;
1613 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1614 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1615 {
1616 /* only want cells with no instances as roots of trees */
1617 if (np->firstinst != NONODEINST) continue;
1618
1619 /* now look recursively at the nodes in this cell */
1620 (void)cla_lookdown(np);
1621 }
1622 }
1623
cla_lookdown(NODEPROTO * start)1624 BOOLEAN cla_lookdown(NODEPROTO *start)
1625 {
1626 REGISTER NODEINST *ni;
1627 REGISTER NODEPROTO *np;
1628 REGISTER INTBIG dlx, dhx, dly, dhy, flx, fhx, fly, fhy;
1629 REGISTER BOOLEAN forcedlook, foundone;
1630 INTBIG nlx, nhx, nly, nhy, offx, offy;
1631 XARRAY trans;
1632
1633 /* first look recursively to the bottom to see if this cell changed */
1634 for(ni = start->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1635 if (ni->proto->primindex == 0) ni->userbits |= MARKN; else
1636 ni->userbits &= ~MARKN;
1637
1638 foundone = TRUE;
1639 while (foundone)
1640 {
1641 foundone = FALSE;
1642 for(ni = start->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1643 {
1644 if ((ni->userbits & MARKN) == 0) continue;
1645 ni->userbits &= ~MARKN;
1646 np = ni->proto;
1647
1648 /* ignore recursive references (showing icon in contents) */
1649 if (isiconof(np, start)) continue;
1650
1651 /* if this nodeinst is to change, mark the parent cell also */
1652 if ((np->userbits & CELLMOD) != 0) start->userbits |= CELLMOD;
1653
1654 /* don't look inside if the cell is certified */
1655 if ((np->userbits & (CELLNOMOD|CELLMOD)) != 0) continue;
1656
1657 /* look inside nodeinst to see if it changed */
1658 if (cla_lookdown(np)) start->userbits |= CELLMOD;
1659 foundone = TRUE;
1660 }
1661 }
1662
1663 /* if this cell did not change, certify so and quit */
1664 if ((start->userbits & CELLMOD) == 0)
1665 {
1666 start->userbits |= CELLNOMOD;
1667 return(FALSE);
1668 }
1669
1670 /* mark those nodes that must change */
1671 for(ni = start->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1672 {
1673 np = ni->proto;
1674 ni->userbits &= ~(MARKN|TOUCHN);
1675 if (np->primindex != 0) continue;
1676 if (isiconof(np, start)) continue;
1677 if ((np->userbits & CELLMOD) == 0) continue;
1678 ni->userbits |= MARKN | TOUCHN;
1679 }
1680 #ifdef CLA_DEBUG
1681 if (cla_conlaydebug)
1682 ttyputmsg(M_(" Complex tree search at cell %s"), describenodeproto(start));
1683 #endif
1684 /* modify the nodes in this cell that changed */
1685 forcedlook = FALSE;
1686 foundone = TRUE;
1687 while (foundone)
1688 {
1689 foundone = FALSE;
1690 for(ni = start->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1691 {
1692 if ((ni->userbits & MARKN) == 0) continue;
1693 ni->userbits &= ~MARKN;
1694 np = ni->proto;
1695
1696 /* determine original size of cell */
1697 if ((CHANGE *)np->changeaddr != NOCHANGE &&
1698 ((CHANGE *)np->changeaddr)->changetype == NODEPROTOMOD)
1699 {
1700 /* modification changes carry original size */
1701 flx = ((CHANGE *)np->changeaddr)->p1;
1702 fhx = ((CHANGE *)np->changeaddr)->p2;
1703 fly = ((CHANGE *)np->changeaddr)->p3;
1704 fhy = ((CHANGE *)np->changeaddr)->p4;
1705 } else
1706 {
1707 /* creation changes have no original size: use current size */
1708 flx = np->lowx; fhx = np->highx;
1709 fly = np->lowy; fhy = np->highy;
1710 }
1711 if (ni->highx-ni->lowx == np->highx-np->lowx && ni->highy-ni->lowy == np->highy-np->lowy)
1712 nlx = nhx = nly = nhy = 0; else
1713 {
1714 dlx = np->lowx - flx; dhx = np->highx - fhx;
1715 dly = np->lowy - fly; dhy = np->highy - fhy;
1716 makeangle(ni->rotation, ni->transpose, trans);
1717 xform(dhx+dlx, dhy+dly, &offx, &offy, trans);
1718 nlx = (dlx-dhx+offx)/2; nhx = offx - nlx;
1719 nly = (dly-dhy+offy)/2; nhy = offy - nly;
1720 }
1721 if (cla_modifynodeinst(ni, nlx, nly, nhx, nhy, 0, 0, TRUE)) forcedlook = TRUE;
1722 foundone = TRUE;
1723 }
1724 }
1725
1726 /* now change the arcs in the nodes in this cell that changed */
1727 foundone = TRUE;
1728 while (foundone)
1729 {
1730 foundone = FALSE;
1731 for(ni = start->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1732 {
1733 if ((ni->userbits & TOUCHN) == 0) continue;
1734 ni->userbits &= ~TOUCHN;
1735 if (cla_modnodearcs(ni, 0, 0)) forcedlook = TRUE;
1736 foundone = TRUE;
1737 }
1738 }
1739
1740 /* now change the size of this cell */
1741 db_boundcell(start, &nlx,&nhx, &nly,&nhy);
1742
1743 /* quit if it has not changed */
1744 if (start->lowx == nlx && start->highx == nhx && start->lowy == nly &&
1745 start->highy == nhy && !forcedlook)
1746 {
1747 start->userbits |= CELLNOMOD;
1748 return(FALSE);
1749 }
1750
1751 /* update the cell size */
1752 start->changeaddr = (CHAR *)db_change((INTBIG)start, NODEPROTOMOD,
1753 start->lowx, start->highx, start->lowy, start->highy, 0, 0);
1754 start->lowx = nlx; start->highx = nhx;
1755 start->lowy = nly; start->highy = nhy;
1756 return(TRUE);
1757 }
1758