2
* Electric(tm) VLSI Design System
5
* Hierarchical layout constraint system
6
* Written by: Steven M. Rubin, Static Free Software
8
* Copyright (c) 2001 Static Free Software
10
* Electric(tm) is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* Electric(tm) is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with Electric(tm); see the file COPYING. If not, write to
22
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23
* Boston, Mass 02111-1307, USA.
25
* Static Free Software
27
* Portola Valley, California 94028
28
* info@staticfreesoft.com
35
/* working memory for "cla_modwithin()" */
36
static INTBIG cla_workingarccount = 0;
37
static ARCINST **cla_workingarcs;
39
/* routines referenced in "conlin.c"*/
40
void cla_oldportposition(NODEINST*, PORTPROTO*, INTBIG*, INTBIG*);
41
void cla_adjustmatrix(NODEINST*, PORTPROTO*, XARRAY);
43
/* prototypes for local routines */
44
static BOOLEAN cla_modifynodeinst(NODEINST *ni, INTBIG deltalx, INTBIG deltaly, INTBIG deltahx,
45
INTBIG deltahy, INTBIG dangle, INTBIG dtrans, BOOLEAN announce);
46
static BOOLEAN cla_modnodearcs(NODEINST*, INTBIG, INTBIG);
47
static void cla_modwithin(NODEINST*, INTBIG, INTBIG);
48
static BOOLEAN cla_modrigid(NODEINST*, INTBIG, INTBIG);
49
static BOOLEAN cla_modflex(NODEINST*, INTBIG, INTBIG);
50
static void cla_nonorthogfixang(ARCINST*, INTBIG, INTBIG, NODEINST*, INTBIG[2], INTBIG[2]);
51
static void cla_ensurearcinst(ARCINST*, INTBIG);
52
static void cla_updatearc(ARCINST*, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG);
53
static void cla_domovearcinst(ARCINST*, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG);
54
static void cla_makeoldrot(NODEINST*, XARRAY);
55
static void cla_makeoldtrans(NODEINST*, XARRAY);
56
static void cla_computefacet(NODEPROTO*, BOOLEAN);
57
static BOOLEAN cla_lookdown(NODEPROTO*);
59
#define CLA_DEBUG 1 /* comment out for normal life */
61
/* command completion table for this constraint solver */
62
static KEYWORD layconopt[] =
64
{"debug-toggle", 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
67
COMCOMP cla_layconp = {layconopt, NOTOPLIST, NONEXTLIST, NOPARAMS, NOBACKUP,
68
0, " \t", M_("layout constraint system option"), 0};
70
INTBIG cla_changeclock;
72
static BOOLEAN cla_conlaydebug;
74
CONSTRAINT *cla_constraint; /* the constraint object for this solver */
76
/******************** CONSTRAINT SYSTEM HOOKS *************************/
78
void cla_layconinit(CONSTRAINT *con)
80
/* only function during pass 1 of initialization */
81
if (con == NOCONSTRAINT) return;
85
cla_conlaydebug = FALSE;
89
void cla_layconterm(void)
91
if (cla_workingarccount > 0) efree((char *)cla_workingarcs);
92
cla_workingarccount = 0;
95
void cla_layconsetmode(INTBIG count, char *par[])
102
ttyputusage("constraint tell layout OPTION");
106
if (el_curconstraint != cla_constraint)
108
ttyputerr(M_("Must first switch to this solver with 'constraint use'"));
112
l = strlen(pp = par[0]);
114
/* debugging switch */
115
if (namesamen(pp, "debug-toggle", l) == 0 && l >= 1)
118
cla_conlaydebug = !cla_conlaydebug;
119
if (cla_conlaydebug) ttyputmsg(M_("Layout constraint debugging on")); else
120
ttyputmsg(M_("Layout constraint debugging off"));
122
ttyputmsg(M_("Sorry, constraint debugging code has been compiled out"));
126
ttyputbadusage("constraint tell layout");
130
* the valid "command" is "describearc" which returns a string that describes
131
* the constraints on the arc in "arg1".
133
INTBIG cla_layconrequest(char *command, INTBIG arg1)
135
REGISTER ARCINST *ai;
140
if (namesamen(command, "describearc", l) == 0)
142
ai = (ARCINST *)arg1;
144
if ((ai->userbits&FIXED) != 0) (void)addtoinfstr('R'); else
146
switch (ai->userbits&(FIXANG|CANTSLIDE))
148
case 0: (void)addtoinfstr('S'); break;
149
case FIXANG: (void)addstringtoinfstr("FS"); break;
150
case CANTSLIDE: (void)addtoinfstr('X'); break;
151
case FIXANG|CANTSLIDE: (void)addtoinfstr('F'); break;
154
return((INTBIG)returninfstr());
160
* routine to do hierarchical update on any facets that changed
162
void cla_layconsolve(NODEPROTO *np)
164
REGISTER CHANGEFACET *cc;
165
REGISTER CHANGEBATCH *curbatch;
168
/* if only one facet is requested, solve that */
169
curbatch = db_getcurrentbatch();
170
if (np != NONODEPROTO)
172
cla_computefacet(np, FALSE);
175
/* solve all facets that changed */
176
if (curbatch != NOCHANGEBATCH)
177
for(cc = curbatch->firstchangefacet; cc != NOCHANGEFACET; cc = cc->nextchangefacet)
178
cla_computefacet(cc->changefacet, cc->forcedlook);
181
if (curbatch == NOCHANGEBATCH) return;
182
for(c = curbatch->changehead; c != NOCHANGE; c = c->nextchange)
183
switch (c->changetype)
188
((NODEINST *)c->entryaddr)->changeaddr = (char *)NOCHANGE;
193
((ARCINST *)c->entryaddr)->changeaddr = (char *)NOCHANGE;
198
((PORTPROTO *)c->entryaddr)->changeaddr = (char *)NOCHANGE;
203
((NODEPROTO *)c->entryaddr)->changeaddr = (char *)NOCHANGE;
209
* If an export is created, touch all instances of the facet
211
void cla_layconnewobject(INTBIG addr, INTBIG type)
213
REGISTER NODEPROTO *np;
214
REGISTER PORTPROTO *pp;
215
REGISTER NODEINST *ni;
217
if (type == VPORTPROTO)
219
pp = (PORTPROTO *)addr;
221
for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
223
(void)db_change((INTBIG)ni, OBJECTSTART, VNODEINST, 0, 0, 0, 0, 0);
224
(void)db_change((INTBIG)ni, NODEINSTMOD, ni->lowx, ni->lowy,
225
ni->highx, ni->highy, ni->rotation, ni->transpose);
226
(void)db_change((INTBIG)ni, OBJECTEND, VNODEINST, 0, 0, 0, 0, 0);
232
* If an export is deleted, touch all instances of the facet
234
void cla_layconkillobject(INTBIG addr, INTBIG type)
236
REGISTER NODEPROTO *np;
237
REGISTER PORTPROTO *pp;
238
REGISTER NODEINST *ni;
240
if (type == VPORTPROTO)
242
pp = (PORTPROTO *)addr;
244
for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
246
(void)db_change((INTBIG)ni, OBJECTSTART, VNODEINST, 0, 0, 0, 0, 0);
247
(void)db_change((INTBIG)ni, NODEINSTMOD, ni->lowx, ni->lowy,
248
ni->highx, ni->highy, ni->rotation, ni->transpose);
249
(void)db_change((INTBIG)ni, OBJECTEND, VNODEINST, 0, 0, 0, 0, 0);
255
* If an export is renamed, touch all instances of the facet
257
void cla_layconnewvariable(INTBIG addr, INTBIG type, INTBIG skey, INTBIG stype)
260
REGISTER NODEPROTO *np;
261
REGISTER PORTPROTO *pp;
262
REGISTER NODEINST *ni;
264
if (type == VPORTPROTO)
266
if ((stype&VCREF) != 0)
268
name = changedvariablename(type, skey, stype);
269
if (strcmp(name, "protoname") == 0)
271
pp = (PORTPROTO *)addr;
273
for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
275
(void)db_change((INTBIG)ni, OBJECTSTART, VNODEINST, 0, 0, 0, 0, 0);
276
(void)db_change((INTBIG)ni, NODEINSTMOD, ni->lowx, ni->lowy,
277
ni->highx, ni->highy, ni->rotation, ni->transpose);
278
(void)db_change((INTBIG)ni, OBJECTEND, VNODEINST, 0, 0, 0, 0, 0);
286
* set layout constraints on arc instance "ai" according to "changetype".
287
* the routine returns true if the arc change is not successful (or already
290
BOOLEAN cla_layconsetobject(INTBIG addr, INTBIG type, INTBIG changetype,
291
INTBIG /*@unused@*/ changedata)
293
REGISTER ARCINST *ai;
295
if ((type&VTYPE) != VARCINST) return(TRUE);
296
ai = (ARCINST *)addr;
297
if (ai == NOARCINST) return(TRUE);
300
case CHANGETYPERIGID: /* arc rigid */
301
if ((ai->userbits & FIXED) != 0) return(TRUE);
302
(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits|FIXED, VINTEGER);
304
case CHANGETYPEUNRIGID: /* arc un-rigid */
305
if ((ai->userbits & FIXED) == 0) return(TRUE);
306
(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits & ~FIXED, VINTEGER);
308
case CHANGETYPEFIXEDANGLE: /* arc fixed-angle */
309
if ((ai->userbits & FIXANG) != 0) return(TRUE);
310
(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits|FIXANG, VINTEGER);
312
case CHANGETYPENOTFIXEDANGLE: /* arc not fixed-angle */
313
if ((ai->userbits & FIXANG) == 0) return(TRUE);
314
(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits & ~FIXANG, VINTEGER);
316
case CHANGETYPESLIDABLE: /* arc slidable */
317
if ((ai->userbits & CANTSLIDE) == 0) return(TRUE);
318
(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits & ~CANTSLIDE, VINTEGER);
320
case CHANGETYPENOTSLIDABLE: /* arc nonslidable */
321
if ((ai->userbits & CANTSLIDE) != 0) return(TRUE);
322
(void)setval((INTBIG)ai, VARCINST, "userbits", ai->userbits|CANTSLIDE, VINTEGER);
324
case CHANGETYPETEMPRIGID: /* arc temporarily rigid */
325
if (ai->changed == cla_changeclock + 2) return(TRUE);
326
ai->changed = cla_changeclock + 2;
328
case CHANGETYPETEMPUNRIGID: /* arc temporarily un-rigid */
329
if (ai->changed == cla_changeclock + 3) return(TRUE);
330
ai->changed = cla_changeclock + 3;
332
case CHANGETYPEREMOVETEMP: /* remove temporarily state */
333
if (ai->changed != cla_changeclock + 3 && ai->changed != cla_changeclock + 2) return(TRUE);
334
ai->changed = cla_changeclock - 3;
340
void cla_layconmodifynodeinst(NODEINST *ni, INTBIG dlx, INTBIG dly, INTBIG dhx, INTBIG dhy,
341
INTBIG drot, INTBIG dtrans)
343
/* advance the change clock */
344
cla_changeclock += 4;
346
/* change the nodeinst */
347
if (cla_modifynodeinst(ni, dlx, dly, dhx, dhy, drot, dtrans, FALSE))
348
db_forcehierarchicalanalysis(ni->parent);
350
/* change the arcs on the nodeinst */
351
if (cla_modnodearcs(ni, drot, dtrans))
352
db_forcehierarchicalanalysis(ni->parent);
355
void cla_layconmodifynodeinsts(INTBIG count, NODEINST **nis, INTBIG *dlxs, INTBIG *dlys,
356
INTBIG *dhxs, INTBIG *dhys, INTBIG *drots, INTBIG *dtranss)
359
REGISTER NODEPROTO *parent;
361
/* advance the change clock */
362
cla_changeclock += 4;
364
/* change the nodeinst */
365
parent = NONODEPROTO;
366
for(i=0; i<count; i++)
368
if (cla_modifynodeinst(nis[i], dlxs[i], dlys[i], dhxs[i], dhys[i],
369
drots[i], dtranss[i], FALSE)) parent = nis[i]->parent;
372
/* change the arcs on the nodeinst */
373
for(i=0; i<count; i++)
375
if (cla_modnodearcs(nis[i], drots[i], dtranss[i]))
376
parent = nis[i]->parent;
378
if (parent != NONODEPROTO) db_forcehierarchicalanalysis(parent);
381
void cla_layconmodifyarcinst(ARCINST /*@unused@*/ *ai, INTBIG /*@unused@*/ oldx0,
382
INTBIG /*@unused@*/ oldy0, INTBIG /*@unused@*/ oldx1,
383
INTBIG /*@unused@*/ oldy1, INTBIG /*@unused@*/ oldwid, INTBIG /*@unused@*/ oldlen) {}
384
void cla_layconmodifyportproto(PORTPROTO /*@unused@*/ *pp, NODEINST /*@unused@*/ *oni,
385
PORTPROTO /*@unused@*/ *opp) {}
386
void cla_layconmodifynodeproto(NODEPROTO /*@unused@*/ *np) {}
387
void cla_layconnewlib(LIBRARY /*@unused@*/ *lib) {}
388
void cla_layconkilllib(LIBRARY /*@unused@*/ *lib) {}
389
void cla_layconkillvariable(INTBIG /*@unused@*/ addr, INTBIG /*@unused@*/ type,
390
INTBIG /*@unused@*/ key, INTBIG /*@unused@*/ saddr,
391
INTBIG /*@unused@*/ stype, UINTBIG /*@unused@*/ *olddes) {}
392
void cla_layconinsertvariable(INTBIG /*@unused@*/ addr, INTBIG /*@unused@*/ type,
393
INTBIG /*@unused@*/ key, INTBIG /*@unused@*/ aindex) {}
394
void cla_laycondeletevariable(INTBIG /*@unused@*/ addr, INTBIG /*@unused@*/ type,
395
INTBIG /*@unused@*/ key, INTBIG /*@unused@*/ aindex, INTBIG /*@unused@*/ oldval) {}
396
void cla_layconsetvariable(void) {}
398
/******************** TEXT MODIFICATION CODE *************************/
400
/* #define TEXTPARTOFOBJECTBOUNDS 1 */
402
void cla_layconmodifyvariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG stype,
403
INTBIG aindex, INTBIG oldval)
405
#ifdef TEXTPARTOFOBJECTBOUNDS
407
REGISTER PORTPROTO *pp;
408
REGISTER NODEINST *ni;
410
/* look for modified text descriptor on exports */
411
if (type == VPORTPROTO)
413
if ((stype&VCREF) != 0)
415
name = changedvariablename(type, key, stype);
416
if (strcmp(name, "textdescript") == 0)
420
pp = (PORTPROTO *)addr;
421
ni = pp->subnodeinst;
422
updategeom(ni->geom, ni->parent);
430
void cla_layconmodifydescript(INTBIG addr, INTBIG type, INTBIG key, UINTBIG *olddes)
432
#ifdef TEXTPARTOFOBJECTBOUNDS
433
REGISTER NODEINST *ni;
434
REGISTER ARCINST *ai;
435
REGISTER PORTPROTO *pp;
440
ni = (NODEINST *)addr;
441
updategeom(ni->geom, ni->parent);
444
pp = (PORTPROTO *)addr;
445
ni = pp->subnodeinst;
446
updategeom(ni->geom, ni->parent);
449
ai = (ARCINST *)addr;
450
updategeom(ai->geom, ai->parent);
456
/******************** NODE MODIFICATION CODE *************************/
459
* The meaning of cla_changeclock for object modification:
461
* ai->changed < cla_changeclock-2 unmodified arcs
462
* ai->changed == cla_changeclock-2 unmodified rigid arcs
463
* ai->changed == cla_changeclock-1 unmodified unrigid arcs
464
* ai->changed == cla_changeclock modified rigid arcs
465
* ai->changed == cla_changeclock+1 modified unrigid arcs
466
* ni->changed < cla_changeclock-1 unmodified nodes
467
* ni->changed == cla_changeclock-1 size-changed nodes
468
* ni->changed == cla_changeclock position-changed nodes
472
* routine to modify nodeinst "ni" by "deltalx" in low X, "deltaly" in low Y,
473
* "deltahx" in high X, "deltahy" in high Y, and "dangle" tenth-degrees. If
474
* "announce" is true, report "start" and "end" changes on the node.
475
* If the nodeinst is a portproto of the current facet and has any arcs
476
* connected to it, the routine returns nonzero to indicate that the outer
477
* facet has ports that moved (the nodeinst has exports).
479
BOOLEAN cla_modifynodeinst(NODEINST *ni, INTBIG deltalx, INTBIG deltaly, INTBIG deltahx,
480
INTBIG deltahy, INTBIG dangle, INTBIG dtrans, BOOLEAN announce)
482
REGISTER INTBIG oldlx, oldly, oldhx, oldhy, change;
483
REGISTER INTSML oldang, oldtrans;
485
/* determine whether this is a position or size change */
486
if (deltalx == deltahx && deltaly == deltahy)
488
if (deltalx == 0 && deltaly == 0 && dangle == 0 && dtrans == 0) change = -1; else
492
/* reject if this change has already been done */
493
if (ni->changed >= cla_changeclock+change) return(FALSE);
495
/* if simple rotation on transposed nodeinst, reverse rotation */
496
if (ni->transpose != 0 && dtrans == 0) dangle = (3600 - dangle) % 3600;
498
if (ni->changed < cla_changeclock-1 && announce)
499
(void)db_change((INTBIG)ni, OBJECTSTART, VNODEINST, 0, 0, 0, 0, 0);
501
/* make changes to the nodeinst */
502
oldang = ni->rotation; ni->rotation = (ni->rotation + dangle) % 3600;
503
oldtrans = ni->transpose; ni->transpose = (ni->transpose + dtrans) & 1;
504
oldlx = ni->lowx; ni->lowx += deltalx;
505
oldhx = ni->highx; ni->highx += deltahx;
506
oldly = ni->lowy; ni->lowy += deltaly;
507
oldhy = ni->highy; ni->highy += deltahy;
508
updategeom(ni->geom, ni->parent);
512
ttyputmsg(M_("Change node %s by X(%s %s) Y(%s %s) r=%ld t=%ld"),
513
describenodeinst(ni), latoa(deltalx), latoa(deltahx), latoa(deltaly),
514
latoa(deltahy), dangle, dtrans);
517
/* mark that this nodeinst has changed */
518
if (ni->changed < cla_changeclock-1)
520
ni->changeaddr = (char *)db_change((INTBIG)ni, NODEINSTMOD, oldlx,
521
oldly, oldhx, oldhy, oldang, oldtrans);
523
(void)db_change((INTBIG)ni, OBJECTEND, VNODEINST, 0, 0, 0, 0, 0);
526
ni->changed = cla_changeclock + change;
528
/* see if this nodeinst is a port of the current facet */
529
if (ni->firstportexpinst == NOPORTEXPINST) return(FALSE);
534
* routine to modify all of the arcs connected to nodeinst "ni" (which has
535
* been rotated by "dangle" tenth-degrees). If the routine returns nonzero,
536
* some ports on the current facet have moved and the facet must be
537
* re-examined for portproto locations.
539
BOOLEAN cla_modnodearcs(NODEINST *ni, INTBIG dangle, INTBIG dtrans)
541
REGISTER BOOLEAN examinefacet;
543
/* assume facet needs no further looks */
544
examinefacet = FALSE;
546
/* next look at arcs that run within this nodeinst */
547
cla_modwithin(ni, dangle, dtrans);
549
/* next look at the rest of the rigid arcs on this nodeinst */
550
if (cla_modrigid(ni, dangle, dtrans)) examinefacet = TRUE;
552
/* finally, look at rest of the flexible arcs on this nodeinst */
553
if (cla_modflex(ni, dangle, dtrans)) examinefacet = TRUE;
555
return(examinefacet);
559
* routine to modify the arcs that run within nodeinst "ni"
561
void cla_modwithin(NODEINST *ni, INTBIG dangle, INTBIG dtrans)
563
REGISTER PORTARCINST *pi;
564
REGISTER ARCINST *ai;
565
REGISTER INTBIG ox, oy, i, total;
566
INTBIG nox, noy, onox, onoy;
569
/* ignore all this stuff if the node just got created */
570
if (((CHANGE *)ni->changeaddr)->changetype == NODEINSTNEW) return;
572
/* build a list of arcs with both ends on this nodeinst */
574
for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
576
/* ignore if arcinst is not within the node */
578
if (ai->end[0].nodeinst != ai->end[1].nodeinst) continue;
579
if (ai->changed == cla_changeclock) continue;
582
if (total == 0) return;
583
if (total > cla_workingarccount)
585
if (cla_workingarccount > 0) efree((char *)cla_workingarcs);
586
cla_workingarccount = 0;
587
cla_workingarcs = (ARCINST **)emalloc(total * (sizeof (ARCINST *)), db_cluster);
588
if (cla_workingarcs == 0) return;
589
cla_workingarccount = total;
592
for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
594
/* ignore if arcinst is not within the node */
596
if (ai->end[0].nodeinst != ai->end[1].nodeinst) continue;
597
if (ai->changed == cla_changeclock) continue;
598
for(i=0; i<total; i++) if (cla_workingarcs[i] == ai) break;
600
cla_workingarcs[total++] = ai;
603
/* look for arcs with both ends on this nodeinst */
604
for(i=0; i<total; i++)
606
ai = cla_workingarcs[i];
607
if ((ai->userbits&DEADA) != 0) continue;
609
/* prepare transformation matrix */
610
makeangle(dangle, dtrans, trans);
612
/* compute old center of nodeinst */
613
ox = (((CHANGE *)ni->changeaddr)->p1 + ((CHANGE *)ni->changeaddr)->p3) / 2;
614
oy = (((CHANGE *)ni->changeaddr)->p2 + ((CHANGE *)ni->changeaddr)->p4) / 2;
616
/* determine the new ends of the arcinst */
617
cla_adjustmatrix(ni, ai->end[0].portarcinst->proto, trans);
618
xform(ai->end[0].xpos-ox, ai->end[0].ypos-oy, &nox, &noy, trans);
619
cla_adjustmatrix(ni, ai->end[1].portarcinst->proto, trans);
620
xform(ai->end[1].xpos-ox, ai->end[1].ypos-oy, &onox, &onoy, trans);
623
ttyputmsg(M_("Internal arc %s moves 0:%s,%s 1:%s,%s"),
624
describearcinst(ai), latoa(nox), latoa(noy), latoa(onox), latoa(onoy));
626
/* move the arcinst */
627
cla_domovearcinst(ai, nox, noy, onox, onoy, 0);
632
* routine to modify the rigid arcs that run from nodeinst "ni". The nodeinst
633
* has changed "dangle" tenth-degrees. If any nodes that are ports in the
634
* current facet change position, the routine returns nonzero to indicate
635
* that instances of the current facet must be examined for arcinst motion.
637
BOOLEAN cla_modrigid(NODEINST *ni, INTBIG dangle, INTBIG dtrans)
639
REGISTER PORTPROTO *opt;
640
REGISTER PORTARCINST *pi;
641
REGISTER ARCINST *ai, **arclist;
642
REGISTER NODEINST *ono;
643
INTBIG ax[2], ay[2], onox, onoy, dx, dy;
645
REGISTER INTBIG othx, othy, ox, oy, i, total, thisend, thatend;
646
REGISTER INTBIG nextangle;
647
REGISTER BOOLEAN examinefacet, locked;
649
/* build a list of the rigid arcs on this nodeinst */
651
for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
653
/* ignore if arcinst is not rigid */
655
if (ai->changed == cla_changeclock-1 || ai->changed == cla_changeclock+1) continue;
656
if (ai->changed != cla_changeclock-2 && (ai->userbits&FIXED) == 0) continue;
659
if (total == 0) return(FALSE);
660
arclist = (ARCINST **)emalloc(total * (sizeof (ARCINST *)), el_tempcluster);
661
if (arclist == 0) return(FALSE);
663
for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
665
/* ignore if arcinst is not rigid */
667
if (ai->changed == cla_changeclock-1 || ai->changed == cla_changeclock+1) continue;
668
if (ai->changed != cla_changeclock-2 && (ai->userbits&FIXED) == 0) continue;
672
/* if simple rotation on transposed nodeinst, reverse rotation */
674
if (((CHANGE *)ni->changeaddr)->changetype != NODEINSTNEW &&
675
((CHANGE *)ni->changeaddr)->p6 != 0 && dtrans != 0)
676
nextangle = (3600 - dangle) % 3600;
678
/* prepare transformation matrix and angle/transposition information */
679
makeangle(nextangle, dtrans, trans);
681
/* look for rigid arcs on this nodeinst */
682
examinefacet = FALSE;
683
for(i=0; i<total; i++)
686
if ((ai->userbits&DEADA) != 0) continue;
687
ai->userbits &= ~FIXEDMOD;
689
/* if rigid arcinst has already been changed check its connectivity */
690
if (ai->changed == cla_changeclock)
692
cla_ensurearcinst(ai, 0);
696
/* find out which end of the arcinst is where, ignore internal arcs */
697
thisend = thatend = 0;
698
if (ai->end[0].nodeinst == ni) thatend++;
699
if (ai->end[1].nodeinst == ni) thisend++;
700
if (thisend == thatend) continue;
702
if (((CHANGE *)ni->changeaddr)->changetype == NODEINSTNEW) ox = oy = 0; else
704
ox = (((CHANGE *)ni->changeaddr)->p1 + ((CHANGE *)ni->changeaddr)->p3) / 2;
705
oy = (((CHANGE *)ni->changeaddr)->p2 + ((CHANGE *)ni->changeaddr)->p4) / 2;
706
cla_adjustmatrix(ni, ai->end[thisend].portarcinst->proto, trans);
709
/* figure out the new location of this arcinst connection */
710
xform(ai->end[thisend].xpos-ox, ai->end[thisend].ypos-oy,
711
&ax[thisend], &ay[thisend], trans);
713
ono = ai->end[thatend].nodeinst;
714
opt = ai->end[thatend].portarcinst->proto;
717
ttyputmsg(M_("Modify rigid arc %s from %s to %s"),
718
describearcinst(ai), describenodeinst(ni), describenodeinst(ono));
721
/* figure out the new location of that arcinst connection */
722
xform(ai->end[thatend].xpos-ox, ai->end[thatend].ypos-oy, &ax[thatend],
723
&ay[thatend], trans);
726
ttyputmsg(M_("Other end of arc moves to (%s,%s)"),
727
latoa(ax[thatend]), latoa(ay[thatend]));
730
/* see if other nodeinst has changed */
732
if (ono->changed == cla_changeclock) locked = TRUE;
733
if (ono->proto->primindex == 0)
735
if ((ono->parent->userbits&NILOCKED) != 0) locked = TRUE;
738
if ((us_useroptions&NOPRIMCHANGES) != 0 &&
739
(ono->proto->userbits&LOCKEDPRIM) != 0) locked = TRUE;
743
/* compute port motion within the other nodeinst (is this right? !!!) */
744
cla_oldportposition(ono, opt, &onox, &onoy);
745
portposition(ono, opt, &dx, &dy);
746
othx = dx - onox; othy = dy - onoy;
748
/* figure out the new location of the other nodeinst */
749
onox = (ono->lowx + ono->highx) / 2;
750
onoy = (ono->lowy + ono->highy) / 2;
751
xform(onox-ox, onoy-oy, &dx, &dy, trans);
752
dx = dx - onox - othx;
753
dy = dy - onoy - othy;
755
/* move the other nodeinst */
757
if (dtrans != 0 && ono->transpose != ((CHANGE *)ni->changeaddr)->p6)
758
nextangle = (3600 - nextangle) % 3600;
760
/* ignore null motion on nodes that have already been examined */
761
if (dx != 0 || dy != 0 || nextangle != 0 || dtrans != 0 || ono->changed != cla_changeclock-1)
763
ai->userbits |= FIXEDMOD;
764
if (cla_modifynodeinst(ono, dx, dy, dx, dy, nextangle, dtrans, TRUE))
769
/* move the arcinst */
772
ttyputmsg(M_("Now arc runs from (%s,%s) to (%s,%s)"),
773
latoa(ax[0]), latoa(ay[0]), latoa(ax[1]), latoa(ay[1]));
775
cla_domovearcinst(ai, ax[0],ay[0], ax[1],ay[1], 0);
778
/* re-scan rigid arcs and recursively modify arcs on other nodes */
779
for(i=0; i<total; i++)
782
if ((ai->userbits&DEADA) != 0) continue;
784
/* only want arcinst that was just explored */
785
if ((ai->userbits & FIXEDMOD) == 0) continue;
787
/* get the other nodeinst */
788
if (ai->end[0].nodeinst == ni) ono = ai->end[1].nodeinst; else
789
ono = ai->end[0].nodeinst;
792
if (dtrans != 0 && ((CHANGE *)ono->changeaddr)->p6 != ((CHANGE *)ni->changeaddr)->p6)
793
nextangle = (3600 - nextangle) % 3600;
794
if (cla_modnodearcs(ono, nextangle, dtrans)) examinefacet = TRUE;
796
efree((char *)arclist);
797
return(examinefacet);
801
* routine to modify the flexible arcs connected to nodeinst "ni". If any
802
* nodes that are ports move, the routine returns nonzero to indicate that
803
* instances of the current facet must be examined for arcinst motion
805
BOOLEAN cla_modflex(NODEINST *ni, INTBIG dangle, INTBIG dtrans)
807
REGISTER PORTARCINST *pi;
808
REGISTER ARCINST *ai, **arclist;
809
REGISTER NODEINST *ono;
810
REGISTER INTBIG i, total, ox, oy, odx, ody, thisend, thatend, mangle;
811
REGISTER INTBIG nextangle;
812
REGISTER BOOLEAN examinefacet;
814
INTBIG ax[2], ay[2], dx, dy, lx, hx, ly, hy;
815
static POLYGON *poly = NOPOLYGON;
817
/* build a list of the flexible arcs on this nodeinst */
819
for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
821
/* ignore if arcinst is not flexible */
823
if (ai->changed == cla_changeclock-2 || ai->changed == cla_changeclock) continue;
824
if (ai->changed != cla_changeclock-1 && (ai->userbits&FIXED) != 0) continue;
827
if (total == 0) return(FALSE);
828
arclist = (ARCINST **)emalloc(total * (sizeof (ARCINST *)), el_tempcluster);
829
if (arclist == 0) return(FALSE);
831
for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
833
/* ignore if arcinst is not flexible */
835
if (ai->changed == cla_changeclock-2 || ai->changed == cla_changeclock) continue;
836
if (ai->changed != cla_changeclock-1 && (ai->userbits&FIXED) != 0) continue;
840
/* if simple rotation on transposed nodeinst, reverse rotation */
842
if (((CHANGE *)ni->changeaddr)->changetype != NODEINSTNEW &&
843
((CHANGE *)ni->changeaddr)->p6 != 0 && dtrans != 0)
844
nextangle = (3600 - dangle) % 3600;
846
/* prepare transformation matrix and angle/transposition information */
847
makeangle(nextangle, dtrans, trans);
849
/* look at all of the flexible arcs on this nodeinst */
850
examinefacet = FALSE;
851
for(i=0; i<total; i++)
854
if ((ai->userbits&DEADA) != 0) continue;
856
/* if flexible arcinst has been changed, verify its connectivity */
860
ttyputmsg(M_("Considering arc %s (clock=%ld, curclock=%ld)"),
861
describearcinst(ai), ai->changed, cla_changeclock+1);
864
if (ai->changed >= cla_changeclock+1)
866
cla_ensurearcinst(ai, 1);
870
/* figure where each end of the arcinst is, ignore internal arcs */
871
thisend = thatend = 0;
872
if (ai->end[0].nodeinst == ni) thatend++;
873
if (ai->end[1].nodeinst == ni) thisend++;
874
if (thisend == thatend) continue;
876
/* if nodeinst motion stays within port area, ignore the arcinst */
877
if ((ai->userbits&CANTSLIDE) == 0 &&
878
db_stillinport(ai, thisend, ai->end[thisend].xpos, ai->end[thisend].ypos))
881
if (((CHANGE *)ni->changeaddr)->changetype == NODEINSTNEW) ox = oy = 0; else
883
ox = (((CHANGE *)ni->changeaddr)->p1 + ((CHANGE *)ni->changeaddr)->p3) / 2;
884
oy = (((CHANGE *)ni->changeaddr)->p2 + ((CHANGE *)ni->changeaddr)->p4) / 2;
885
cla_adjustmatrix(ni, ai->end[thisend].portarcinst->proto, trans);
888
/* figure out the new location of this arcinst connection */
889
xform(ai->end[thisend].xpos-ox, ai->end[thisend].ypos-oy,
890
&ax[thisend], &ay[thisend], trans);
892
/* make sure the arc end is still in the port */
893
if (poly == NOPOLYGON) poly = allocstaticpolygon(4, db_cluster);
894
shapeportpoly(ai->end[thisend].nodeinst, ai->end[thisend].portarcinst->proto,
896
if (!isinside(ax[thisend], ay[thisend], poly))
898
getbbox(poly, &lx, &hx, &ly, &hy);
899
if (ay[thisend] >= ly && ay[thisend] <= hy)
901
/* extend arc horizontally to fit in port */
902
if (ax[thisend] < lx) ax[thisend] = lx; else
903
if (ax[thisend] > hx) ax[thisend] = hx;
904
} else if (ax[thisend] >= lx && ax[thisend] <= hx)
906
/* extend arc vertically to fit in port */
907
if (ay[thisend] < ly) ay[thisend] = ly; else
908
if (ay[thisend] > hy) ay[thisend] = hy;
911
/* extend arc arbitrarily to fit in port */
912
closestpoint(poly, &ax[thisend], &ay[thisend]);
916
/* get other end of arcinst and its position */
917
ono = ai->end[thatend].nodeinst;
918
ax[thatend] = ai->end[thatend].xpos;
919
ay[thatend] = ai->end[thatend].ypos;
923
ttyputmsg(M_("Modify flexible arc %s from %s to %s"),
924
describearcinst(ai), describenodeinst(ni), describenodeinst(ono));
928
/* see if other nodeinst has changed */
930
if ((ai->userbits&FIXANG) == 0) mangle = 0;
931
if (ono->proto->primindex == 0)
933
if ((ono->parent->userbits&NILOCKED) != 0) mangle = 0;
936
if ((us_useroptions&NOPRIMCHANGES) != 0 &&
937
(ono->proto->userbits&LOCKEDPRIM) != 0) mangle = 0;
941
/* other nodeinst untouched, mangle it */
942
dx = ax[thisend] - ai->end[thisend].xpos;
943
dy = ay[thisend] - ai->end[thisend].ypos;
944
odx = ax[thatend] - ai->end[thatend].xpos;
945
ody = ay[thatend] - ai->end[thatend].ypos;
946
if (ai->end[thisend].xpos == ai->end[thatend].xpos)
948
/* null arcinst must not be explicitly horizontal */
949
if (ai->end[thisend].ypos != ai->end[thatend].ypos ||
950
((ai->userbits&AANGLE) >> AANGLESH) == 90 ||
951
((ai->userbits&AANGLE) >> AANGLESH) == 270)
953
/* vertical arcinst: see if it really moved in X */
954
if (dx == odx) dx = odx = 0;
956
/* move horizontal, shrink vertical */
957
ax[thatend] += dx-odx;
959
/* see if next nodeinst need not be moved */
960
if (dx != odx && (ai->userbits&CANTSLIDE) == 0 &&
961
db_stillinport(ai, thatend, ax[thatend], ay[thatend]))
964
/* if other node already moved, don't move it any more */
965
if (ono->changed >= cla_changeclock) dx = odx = 0;
969
ttyputmsg(M_(" Moving other end of arc to (%s,%s), other node by (%s,0)"),
970
latoa(ax[thatend]), latoa(ay[thatend]), latoa(dx-odx));
974
if (cla_modifynodeinst(ono, dx-odx, 0, dx-odx, 0, 0, 0, TRUE))
977
cla_domovearcinst(ai, ax[0],ay[0], ax[1],ay[1], 1);
979
if (cla_modnodearcs(ono, 0, 0)) examinefacet = TRUE;
983
if (ai->end[thisend].ypos == ai->end[thatend].ypos)
985
/* horizontal arcinst: see if it really moved in Y */
986
if (dy == ody) dy = ody = 0;
988
/* shrink horizontal, move vertical */
989
ay[thatend] += dy-ody;
991
/* see if next nodeinst need not be moved */
992
if (dy != ody && (ai->userbits&CANTSLIDE) == 0 &&
993
db_stillinport(ai, thatend, ax[thatend], ay[thatend]))
996
/* if other node already moved, don't move it any more */
997
if (ono->changed >= cla_changeclock) dx = odx = 0;
1000
if (cla_conlaydebug)
1001
ttyputmsg(M_(" Moving other end of arc to (%s,%s), other node by (0,%s)"),
1002
latoa(ax[thatend]), latoa(ay[thatend]), latoa(dy-ody));
1006
if (cla_modifynodeinst(ono, 0, dy-ody, 0, dy-ody, 0, 0, TRUE))
1007
examinefacet = TRUE;
1009
cla_domovearcinst(ai, ax[0],ay[0], ax[1],ay[1], 1);
1010
if (dy != ody) if (cla_modnodearcs(ono, 0, 0)) examinefacet = TRUE;
1014
/***** THIS CODE HANDLES ALL-ANGLE RIGIDITY WITH THE FIXED-ANGLE CONSTRAINT *****/
1016
/* special code to handle nonorthogonal fixed-angles */
1017
cla_nonorthogfixang(ai, thisend, thatend, ono, ax, ay);
1018
dx = ax[thatend] - ai->end[thatend].xpos;
1019
dy = ay[thatend] - ai->end[thatend].ypos;
1021
/* change the arc */
1022
cla_updatearc(ai, ax[0],ay[0], ax[1],ay[1], 1);
1024
/* if other node already moved, don't move it any more */
1025
if (ono->changed >= cla_changeclock) dx = dy = 0;
1027
if (dx != 0 || dy != 0)
1029
if (cla_modifynodeinst(ono, dx, dy, dx, dy, 0, 0, TRUE))
1030
examinefacet = TRUE;
1031
if (cla_modnodearcs(ono, 0, 0)) examinefacet = TRUE;
1036
/* other node has changed or arc is funny, just use its position */
1038
if (cla_conlaydebug)
1039
ttyputmsg(M_(" ! Moving arc %s to (%s,%s)-(%s,%s)"), describearcinst(ai),
1040
latoa(ax[0]), latoa(ay[0]), latoa(ax[1]), latoa(ay[1]));
1042
cla_domovearcinst(ai, ax[0],ay[0], ax[1],ay[1], 1);
1044
efree((char *)arclist);
1045
return(examinefacet);
1049
* routine to determine the motion of a nonorthogonal arcinst "ai" given that
1050
* its "thisend" end has moved to (ax[thisend],ay[thisend]) and its other end must be
1051
* determined in (ax[thatend],ay[thatend]). The node on the other end is "ono".
1053
void cla_nonorthogfixang(ARCINST *ai, INTBIG thisend, INTBIG thatend, NODEINST *ono,
1054
INTBIG ax[2], INTBIG ay[2])
1056
REGISTER PORTARCINST *pi;
1057
REGISTER ARCINST *oai, *bestai;
1058
REGISTER INTBIG bestdist;
1061
/* look for longest other arc on "ono" to determine proper end position */
1063
for(pi = ono->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1065
oai = pi->conarcinst;
1066
if (oai == ai) continue;
1067
if (oai->length < bestdist) continue;
1068
bestdist = oai->length;
1072
/* if no other arcs, allow that end to move the same as this end */
1075
ax[thatend] += ax[thisend] - ai->end[thisend].xpos;
1076
ay[thatend] += ay[thisend] - ai->end[thisend].ypos;
1080
/* compute intersection of arc "bestai" with new moved arc "ai" */
1081
if (intersect(ax[thisend],ay[thisend], ((ai->userbits&AANGLE) >> AANGLESH) * 10,
1082
bestai->end[0].xpos, bestai->end[0].ypos,
1083
((bestai->userbits&AANGLE) >> AANGLESH) * 10, &ix, &iy) < 0)
1085
ax[thatend] += ax[thisend] - ai->end[thisend].xpos;
1086
ay[thatend] += ay[thisend] - ai->end[thisend].ypos;
1094
* routine to ensure that arcinst "ai" is still connected properly at each
1095
* end. If it is not, it must be jogged or adjusted. The nature of the
1096
* arcinst is in "arctyp" (0 for rigid, 1 for flexible)
1098
void cla_ensurearcinst(ARCINST *ai, INTBIG arctyp)
1100
REGISTER BOOLEAN inside0, inside1;
1101
INTBIG lx0, lx1, hx0, hx1, ly0, ly1, hy0, hy1, fx, fy, tx, ty;
1102
static POLYGON *poly0 = NOPOLYGON, *poly1 = NOPOLYGON;
1104
/* if nothing is outside port, quit */
1105
inside0 = db_stillinport(ai, 0, ai->end[0].xpos, ai->end[0].ypos);
1106
inside1 = db_stillinport(ai, 1, ai->end[1].xpos, ai->end[1].ypos);
1107
if (inside0 && inside1) return;
1109
/* make sure there is a polygon */
1110
if (poly0 == NOPOLYGON) poly0 = allocstaticpolygon(4, cla_constraint->cluster);
1111
if (poly1 == NOPOLYGON) poly1 = allocstaticpolygon(4, cla_constraint->cluster);
1113
/* get area of the ports */
1114
shapeportpoly(ai->end[0].nodeinst, ai->end[0].portarcinst->proto, poly0, FALSE);
1115
shapeportpoly(ai->end[1].nodeinst, ai->end[1].portarcinst->proto, poly1, FALSE);
1117
/* if arcinst is not fixed-angle, run it directly to the port centers */
1118
if ((ai->userbits&FIXANG) == 0)
1120
getcenter(poly0, &fx, &fy);
1121
getcenter(poly1, &tx, &ty);
1123
if (cla_conlaydebug)
1124
ttyputmsg(M_("Ensuring rigid arc %s"), describearcinst(ai));
1126
cla_domovearcinst(ai, fx, fy, tx, ty, arctyp);
1130
/* get bounding boxes of polygons */
1131
getbbox(poly0, &lx0, &hx0, &ly0, &hy0);
1132
getbbox(poly1, &lx1, &hx1, &ly1, &hy1);
1134
/* if manhattan path runs between the ports, adjust the arcinst */
1135
if (lx0 <= hx1 && lx1 <= hx0)
1137
/* arcinst runs vertically */
1138
tx = fx = (maxi(lx0,lx1) + mini(hx0,hx1)) / 2;
1139
fy = (ly0+hy0) / 2; ty = (ly1+hy1) / 2;
1140
closestpoint(poly0, &fx, &fy);
1141
closestpoint(poly1, &tx, &ty);
1143
if (cla_conlaydebug)
1144
ttyputmsg(M_("Ensuring manhattan arc %s"), describearcinst(ai));
1146
cla_domovearcinst(ai, fx, fy, tx, ty, arctyp);
1149
if (ly0 <= hy1 && ly1 <= hy0)
1151
/* arcinst runs horizontally */
1152
ty = fy = (maxi(ly0,ly1) + mini(hy0,hy1)) / 2;
1153
fx = (lx0+hx0) / 2; tx = (lx1+hx1) / 2;
1154
closestpoint(poly0, &fx, &fy);
1155
closestpoint(poly1, &tx, &ty);
1157
if (cla_conlaydebug)
1158
ttyputmsg(M_("Ensuring manhattan arc %s"), describearcinst(ai));
1160
cla_domovearcinst(ai, fx, fy, tx, ty, arctyp);
1164
/* give up and jog the arcinst */
1165
getcenter(poly0, &fx, &fy);
1166
getcenter(poly1, &tx, &ty);
1167
cla_domovearcinst(ai, fx, fy, tx, ty, arctyp);
1171
* routine to update arc "ai" so that its ends run from (fx,fy) to (tx,ty).
1172
* The type of the arc is in "arctyp" for marking the change.
1174
void cla_updatearc(ARCINST *ai, INTBIG fx, INTBIG fy, INTBIG tx, INTBIG ty, INTBIG arctyp)
1176
REGISTER INTBIG oldxA, oldyA, oldxB, oldyB, oldlen;
1178
(void)db_change((INTBIG)ai, OBJECTSTART, VARCINST, 0, 0, 0, 0, 0);
1180
/* save old arc state */
1181
oldxA = ai->end[0].xpos; oldyA = ai->end[0].ypos;
1182
oldxB = ai->end[1].xpos; oldyB = ai->end[1].ypos;
1183
oldlen = ai->length;
1185
/* set the proper arcinst position */
1187
if (cla_conlaydebug)
1188
ttyputmsg(M_("Change arc %s from (%s,%s)-(%s,%s) to (%s,%s)-(%s,%s)"),
1189
describearcinst(ai), latoa(ai->end[0].xpos), latoa(ai->end[0].ypos),
1190
latoa(ai->end[1].xpos), latoa(ai->end[1].ypos),
1191
latoa(fx), latoa(fy), latoa(tx), latoa(ty));
1193
ai->end[0].xpos = fx;
1194
ai->end[0].ypos = fy;
1195
ai->end[1].xpos = tx;
1196
ai->end[1].ypos = ty;
1197
ai->length = computedistance(fx,fy, tx,ty);
1199
(void)setshrinkvalue(ai, TRUE);
1200
updategeom(ai->geom, ai->parent);
1202
/* see if the arc has changed before */
1203
if (((CHANGE *)ai->changeaddr) == NOCHANGE)
1205
/* announce new arcinst change */
1206
ai->changeaddr = (char *)db_change((INTBIG)ai, ARCINSTMOD, oldxA,
1207
oldyA, oldxB, oldyB, ai->width, oldlen);
1208
ai->changed = cla_changeclock + arctyp;
1210
(void)db_change((INTBIG)ai, OBJECTEND, VARCINST, 0, 0, 0, 0, 0);
1213
void cla_domovearcinst(ARCINST *ai, INTBIG fx, INTBIG fy, INTBIG tx, INTBIG ty, INTBIG arctyp)
1215
REGISTER NODEPROTO *np, *pnt;
1216
REGISTER ARCPROTO *ap;
1217
REGISTER ARCINST *ar1, *ar2, *ar3;
1218
REGISTER PORTPROTO *pp, *fpt, *tpt;
1219
REGISTER NODEINST *no1, *no2, *fno, *tno;
1220
REGISTER INTBIG oldxA, oldyA, oldxB, oldyB, wid, oldbits, lx, hx, ly, hy;
1223
/* check for null arcinst motion */
1224
if (fx == ai->end[0].xpos && fy == ai->end[0].ypos &&
1225
tx == ai->end[1].xpos && ty == ai->end[1].ypos)
1227
/* only ignore null motion on fixed-angle requests */
1228
if (arctyp != 0) return;
1231
/* if the angle is the same or doesn't need to be, simply make the change */
1232
if ((ai->userbits&FIXANG) == 0 ||
1233
((ai->userbits&FIXED) != 0 && ai->changed != cla_changeclock-1) ||
1234
ai->changed == cla_changeclock-2 ||
1235
(fx == tx && fy == ty) ||
1236
((((INTBIG)ai->userbits&AANGLE) >> AANGLESH)*10)%1800 == figureangle(fx, fy, tx, ty)%1800)
1238
cla_updatearc(ai, fx, fy, tx, ty, arctyp);
1242
if (cla_conlaydebug)
1244
ttyputmsg(M_("Jogging arc %s (0%o) to run from (%s,%s) to (%s,%s)"),
1245
describearcinst(ai), ai, latoa(fx), latoa(fy), latoa(tx), latoa(ty));
1249
/* manhattan arcinst becomes nonmanhattan: remember facts about it */
1250
fno = ai->end[0].nodeinst; fpt = ai->end[0].portarcinst->proto;
1251
tno = ai->end[1].nodeinst; tpt = ai->end[1].portarcinst->proto;
1252
ap = ai->proto; pnt = ai->parent; wid = ai->width;
1253
oldbits = ai->userbits;
1255
/* figure out what nodeinst proto connects these arcs */
1256
np = getpinproto(ap);
1257
defaultnodesize(np, &psx, &psy);
1259
/* replace it with three arcs and two nodes */
1260
if (ai->end[0].xpos == ai->end[1].xpos)
1262
/* arcinst was vertical */
1263
oldyA = oldyB = (ty+fy) / 2;
1264
oldxA = fx; oldxB = tx;
1265
lx = oldxB - psx/2; hx = lx + psx;
1266
ly = oldyB - psy/2; hy = ly + psy;
1267
no1 = db_newnodeinst(np, lx, hx, ly, hy, 0, 0, pnt);
1268
lx = oldxA - psx/2; hx = lx + psx;
1269
ly = oldyA - psy/2; hy = ly + psy;
1270
no2 = db_newnodeinst(np, lx, hx, ly, hy, 0, 0, pnt);
1273
/* assume horizontal arcinst */
1274
oldyA = fy; oldyB = ty;
1275
oldxA = oldxB = (tx+fx) / 2;
1276
lx = oldxB - psx/2; hx = lx + psx;
1277
ly = oldyB - psy/2; hy = ly + psy;
1278
no1 = db_newnodeinst(np, lx, hx, ly, hy, 0, 0, pnt);
1279
lx = oldxA - psx/2; hx = lx + psx;
1280
ly = oldyA - psy/2; hy = ly + psy;
1281
no2 = db_newnodeinst(np, lx, hx, ly, hy, 0, 0, pnt);
1283
if (no1 == NONODEINST || no2 == NONODEINST)
1285
ttyputerr(_("Problem creating jog pins"));
1288
(void)db_change((INTBIG)no1, OBJECTEND, VNODEINST, 0, 0, 0, 0, 0);
1289
(void)db_change((INTBIG)no2, OBJECTEND, VNODEINST, 0, 0, 0, 0, 0);
1290
pp = np->firstportproto;
1291
ar1 = db_newarcinst(ap, wid, oldbits, fno, fpt, fx,fy, no2, pp, oldxA,oldyA, pnt);
1292
if ((oldbits&ISNEGATED) != 0) oldbits &= ~ISNEGATED;
1293
ar2 = db_newarcinst(ap, wid, oldbits, no2, pp, oldxA,oldyA, no1, pp, oldxB,oldyB, pnt);
1294
ar3 = db_newarcinst(ap, wid, oldbits, no1, pp, oldxB,oldyB, tno, tpt, tx,ty, pnt);
1295
if (ar1 == NOARCINST || ar2 == NOARCINST || ar3 == NOARCINST)
1297
ttyputerr(_("Problem creating jog arcs"));
1300
(void)copyvars((INTBIG)ai, VARCINST, (INTBIG)ar2, VARCINST);
1301
(void)db_change((INTBIG)ar1, OBJECTEND, VARCINST, 0, 0, 0, 0, 0);
1302
(void)db_change((INTBIG)ar2, OBJECTEND, VARCINST, 0, 0, 0, 0, 0);
1303
(void)db_change((INTBIG)ar3, OBJECTEND, VARCINST, 0, 0, 0, 0, 0);
1304
ar1->changed = cla_changeclock + arctyp;
1305
ar2->changed = cla_changeclock + arctyp;
1306
ar3->changed = cla_changeclock + arctyp;
1308
/* now kill the arcinst */
1309
(void)db_change((INTBIG)ai, OBJECTSTART, VARCINST, 0, 0, 0, 0, 0);
1310
if ((CHANGE *)ai->changeaddr != NOCHANGE)
1312
ai->end[0].xpos = ((CHANGE *)ai->changeaddr)->p1;
1313
ai->end[0].ypos = ((CHANGE *)ai->changeaddr)->p2;
1314
ai->end[1].xpos = ((CHANGE *)ai->changeaddr)->p3;
1315
ai->end[1].ypos = ((CHANGE *)ai->changeaddr)->p4;
1316
ai->length = computedistance(ai->end[0].xpos, ai->end[0].ypos,
1317
ai->end[1].xpos, ai->end[1].ypos);
1318
ai->width = ((CHANGE *)ai->changeaddr)->p5;
1325
* routine to adjust the transformation matrix "trans" by placing translation
1326
* information for nodeinst "ni", port "pp".
1328
* there are only two types of nodeinst changes: internal and external.
1329
* The internal changes are scaling and port motion changes that
1330
* are usually caused by other changes within the facet. The external
1331
* changes are rotation and transposition. These two changes never
1332
* occur at the same time. There is also translation change that
1333
* can occur at any time and is of no importance here. What is
1334
* important is that the transformation matrix "trans" handles
1335
* the external changes and internal changes. External changes are already
1336
* set by the "makeangle" subroutine and internal changes are
1337
* built into the matrix here.
1339
void cla_adjustmatrix(NODEINST *ni, PORTPROTO *pp, XARRAY trans)
1341
REGISTER INTBIG ox, oy;
1342
INTBIG onox, onoy, dx, dy;
1344
if (((CHANGE *)ni->changeaddr)->p5 == ni->rotation &&
1345
((CHANGE *)ni->changeaddr)->p6 == ni->transpose)
1347
/* nodeinst did not rotate: adjust for port motion */
1348
cla_oldportposition(ni, pp, &onox, &onoy);
1349
portposition(ni, pp, &dx, &dy);
1350
ox = (((CHANGE *)ni->changeaddr)->p1 + ((CHANGE *)ni->changeaddr)->p3) / 2;
1351
oy = (((CHANGE *)ni->changeaddr)->p2 + ((CHANGE *)ni->changeaddr)->p4) / 2;
1353
if (cla_conlaydebug)
1355
ttyputmsg(M_("Node %s port %s was at (%s,%s), is at (%s,%s)"), describenodeinst(ni),
1356
pp->protoname, latoa(onox), latoa(onoy), latoa(dx), latoa(dy));
1357
ttyputmsg(M_(" Node moved (%s,%s)"), latoa(ox), latoa(oy));
1360
trans[2][0] = dx - onox + ox; trans[2][1] = dy - onoy + oy;
1363
/* nodeinst rotated: adjust for nodeinst motion */
1364
trans[2][0] = (ni->lowx + ni->highx) / 2;
1365
trans[2][1] = (ni->lowy + ni->highy) / 2;
1370
* routine to compute the position of portproto "pp" on nodeinst "ni" and
1371
* place the center of the area in the parameters "x" and "y". The position
1372
* is the "old" position, as determined by any changes that may have occured
1373
* to the nodeinst (and any sub-nodes).
1375
void cla_oldportposition(NODEINST *ni, PORTPROTO *pp, INTBIG *x, INTBIG *y)
1377
REGISTER INTBIG lox, hix, loy, hiy;
1378
XARRAY localtran, subrot, temptr;
1379
static POLYGON *poly = NOPOLYGON;
1381
/* make sure there is a polygon */
1382
if (poly == NOPOLYGON) poly = allocstaticpolygon(4, cla_constraint->cluster);
1384
/* descend to the primitive node */
1385
cla_makeoldrot(ni, subrot);
1386
while (ni->proto->primindex == 0)
1388
cla_makeoldtrans(ni, localtran);
1389
transmult(localtran, subrot, temptr);
1390
if (((CHANGE *)pp->changeaddr) != NOCHANGE &&
1391
((CHANGE *)pp->changeaddr)->changetype == PORTPROTOMOD)
1393
/* special code for moved port prototypes */
1394
ni = (NODEINST *)((CHANGE *)pp->changeaddr)->p1;
1395
pp = (PORTPROTO *)((CHANGE *)pp->changeaddr)->p2;
1398
ni = pp->subnodeinst;
1399
pp = pp->subportproto;
1401
cla_makeoldrot(ni, localtran);
1402
transmult(localtran, temptr, subrot);
1405
/* save the actual extents of the nodeinst */
1406
lox = ni->lowx; hix = ni->highx;
1407
loy = ni->lowy; hiy = ni->highy;
1409
/* if the node changed, reset it temporarily */
1410
if (((CHANGE *)ni->changeaddr) != NOCHANGE &&
1411
((CHANGE *)ni->changeaddr)->changetype == NODEINSTMOD)
1413
ni->lowx = ((CHANGE *)ni->changeaddr)->p1;
1414
ni->highx = ((CHANGE *)ni->changeaddr)->p3;
1415
ni->lowy = ((CHANGE *)ni->changeaddr)->p2;
1416
ni->highy = ((CHANGE *)ni->changeaddr)->p4;
1419
/* now get the polygon describing the port */
1420
shapetransportpoly(ni, pp, poly, subrot);
1422
/* reset the bounds of the nodeinst */
1423
ni->lowx = lox; ni->highx = hix;
1424
ni->lowy = loy; ni->highy = hiy;
1426
/* compute the center of the port */
1427
getcenter(poly, x, y);
1430
void cla_makeoldrot(NODEINST *ni, XARRAY trans)
1432
REGISTER INTBIG nlx, nly, nhx, nhy;
1433
REGISTER INTSML nr, nt;
1436
nlx = ni->lowx; nly = ni->lowy;
1437
nhx = ni->highx; nhy = ni->highy;
1438
nr = ni->rotation; nt = ni->transpose;
1440
/* set to previous values if they changed */
1441
if (((CHANGE *)ni->changeaddr) != NOCHANGE &&
1442
((CHANGE *)ni->changeaddr)->changetype == NODEINSTMOD)
1444
ni->lowx = ((CHANGE *)ni->changeaddr)->p1;
1445
ni->lowy = ((CHANGE *)ni->changeaddr)->p2;
1446
ni->highx = ((CHANGE *)ni->changeaddr)->p3;
1447
ni->highy = ((CHANGE *)ni->changeaddr)->p4;
1448
ni->rotation = (INTSML)((CHANGE *)ni->changeaddr)->p5;
1449
ni->transpose = (INTSML)((CHANGE *)ni->changeaddr)->p6;
1452
/* create the former rotation matrix */
1455
/* restore values */
1456
ni->lowx = nlx; ni->lowy = nly;
1457
ni->highx = nhx; ni->highy = nhy;
1458
ni->rotation = nr; ni->transpose = nt;
1461
void cla_makeoldtrans(NODEINST *ni, XARRAY trans)
1463
REGISTER INTBIG nlx, nly, nhx, nhy, ntlx, ntly, nthx, nthy;
1464
REGISTER NODEPROTO *np;
1468
nlx = ni->lowx; nly = ni->lowy;
1469
nhx = ni->highx; nhy = ni->highy;
1470
ntlx = np->lowx; ntly = np->lowy;
1471
nthx = np->highx; nthy = np->highy;
1473
/* set to previous values if they changed */
1474
if (((CHANGE *)ni->changeaddr) != NOCHANGE &&
1475
((CHANGE *)ni->changeaddr)->changetype == NODEINSTMOD)
1477
ni->lowx = ((CHANGE *)ni->changeaddr)->p1;
1478
ni->lowy = ((CHANGE *)ni->changeaddr)->p2;
1479
ni->highx = ((CHANGE *)ni->changeaddr)->p3;
1480
ni->highy = ((CHANGE *)ni->changeaddr)->p4;
1482
if (((CHANGE *)np->changeaddr) != NOCHANGE &&
1483
((CHANGE *)np->changeaddr)->changetype == NODEPROTOMOD)
1485
np->lowx = ((CHANGE *)np->changeaddr)->p1;
1486
np->highx = ((CHANGE *)np->changeaddr)->p2;
1487
np->lowy = ((CHANGE *)np->changeaddr)->p3;
1488
np->highy = ((CHANGE *)np->changeaddr)->p4;
1491
/* create the former translation matrix */
1492
maketrans(ni, trans);
1494
/* restore values */
1495
ni->lowx = nlx; ni->lowy = nly;
1496
ni->highx = nhx; ni->highy = nhy;
1497
np->lowx = ntlx; np->lowy = ntly;
1498
np->highx = nthx; np->highy = nthy;
1502
* routine to re-compute the bounds of the facet "facet" (because an object
1503
* has been added or removed from it) and store these bounds in the nominal
1504
* size and the size of each instantiation of the facet. It is also necessary
1505
* to re-position each instantiation of the facet in its proper position list.
1506
* If "forcedlook" is true, the facet is re-examined regardless of
1507
* whether its size changed.
1509
void cla_computefacet(NODEPROTO *facet, BOOLEAN forcedlook)
1511
REGISTER NODEINST *ni, *lni;
1512
REGISTER NODEPROTO *np, *oneparent;
1513
INTBIG nlx, nhx, nly, nhy, offx, offy;
1515
REGISTER INTBIG dlx, dly, dhx, dhy, flx, fhx, fly, fhy;
1516
REGISTER BOOLEAN mixed;
1518
REGISTER LIBRARY *lib;
1521
if (cla_conlaydebug)
1522
ttyputmsg(M_("In computefacet on facet %s (fl=%ld)"),
1523
facet->cell->cellname, forcedlook);
1525
/* get current boundary of facet */
1526
db_boundfacet(facet, &nlx,&nhx, &nly,&nhy);
1528
/* quit if it has not changed */
1529
if (facet->lowx == nlx && facet->highx == nhx && facet->lowy == nly &&
1530
facet->highy == nhy && !forcedlook) return;
1532
/* advance the change clock */
1533
cla_changeclock += 4;
1535
/* get former size of facet from change information */
1536
flx = facet->lowx; fhx = facet->highx;
1537
fly = facet->lowy; fhy = facet->highy;
1538
c = (CHANGE *)facet->changeaddr;
1539
if (c != NOCHANGE && c->changetype == NODEPROTOMOD)
1541
/* modification changes carry original size */
1542
flx = c->p1; fhx = c->p2;
1543
fly = c->p3; fhy = c->p4;
1546
/* update the facet size */
1547
facet->lowx = nlx; facet->highx = nhx;
1548
facet->lowy = nly; facet->highy = nhy;
1549
facet->changeaddr = (char *)db_change((INTBIG)facet, NODEPROTOMOD, flx, fhx, fly, fhy, 0, 0);
1551
/* see if all instances of this facet are in the same location */
1553
oneparent = NONODEPROTO;
1555
for(ni = facet->firstinst; ni != NONODEINST; ni = ni->nextinst)
1557
oneparent = ni->parent;
1558
if (lni != NONODEINST) if (ni->parent != lni->parent) mixed = TRUE;
1562
/* if there are no constrained instances of the facet, no change */
1563
if (oneparent == NONODEPROTO) return;
1565
/* if all parent facets the same, make changes to the instances */
1566
if (!mixed && !forcedlook)
1569
if (cla_conlaydebug)
1570
ttyputmsg(M_(" Recomputing uniform parents of facet %s"),
1571
describenodeproto(facet));
1573
dlx = facet->lowx - flx; dhx = facet->highx - fhx;
1574
dly = facet->lowy - fly; dhy = facet->highy - fhy;
1575
for(ni = facet->firstinst; ni != NONODEINST; ni = ni->nextinst)
1577
makeangle(ni->rotation, ni->transpose, trans);
1578
xform(dhx+dlx, dhy+dly, &offx, &offy, trans);
1579
nlx = (dlx-dhx+offx)/2; nhx = offx - nlx;
1580
nly = (dly-dhy+offy)/2; nhy = offy - nly;
1581
if (cla_modifynodeinst(ni, nlx, nly, nhx, nhy, 0, 0, TRUE)) forcedlook = TRUE;
1583
for(ni = facet->firstinst; ni != NONODEINST; ni = ni->nextinst)
1584
if (cla_modnodearcs(ni, 0, 0)) forcedlook = TRUE;
1585
cla_computefacet(oneparent, forcedlook);
1590
* if instances are scattered or port motion has occured, examine
1591
* entire database in proper recursive order and adjust facet sizes
1594
if (cla_conlaydebug)
1595
ttyputmsg(M_(" Performing complex tree examination"));
1597
for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1598
for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1599
np->userbits &= ~(FACETMOD|FACETNOMOD);
1600
facet->userbits |= FACETMOD;
1601
for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1602
for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1604
/* only want facets with no instances as roots of trees */
1605
if (np->firstinst != NONODEINST) continue;
1607
/* now look recursively at the nodes in this facet */
1608
(void)cla_lookdown(np);
1612
BOOLEAN cla_lookdown(NODEPROTO *start)
1614
REGISTER NODEINST *ni;
1615
REGISTER NODEPROTO *np;
1616
REGISTER INTBIG dlx, dhx, dly, dhy, flx, fhx, fly, fhy;
1617
REGISTER BOOLEAN forcedlook, foundone;
1618
INTBIG nlx, nhx, nly, nhy, offx, offy;
1621
/* first look recursively to the bottom to see if this facet changed */
1622
for(ni = start->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1623
if (ni->proto->primindex == 0) ni->userbits |= MARKN; else
1624
ni->userbits &= ~MARKN;
1630
for(ni = start->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1632
if ((ni->userbits & MARKN) == 0) continue;
1633
ni->userbits &= ~MARKN;
1636
/* ignore recursive references (showing icon in contents) */
1637
/* if (np->cell == start->cell) continue; */
1639
/* if this nodeinst is to change, mark the parent facet also */
1640
if ((np->userbits & FACETMOD) != 0) start->userbits |= FACETMOD;
1642
/* don't look inside if the facet is certified */
1643
if ((np->userbits & (FACETNOMOD|FACETMOD)) != 0) continue;
1645
/* look inside nodeinst to see if it changed */
1646
if (cla_lookdown(np)) start->userbits |= FACETMOD;
1651
/* if this facet did not change, certify so and quit */
1652
if ((start->userbits & FACETMOD) == 0)
1654
start->userbits |= FACETNOMOD;
1658
/* mark those nodes that must change */
1659
for(ni = start->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1662
ni->userbits &= ~(MARKN|TOUCHN);
1663
if (np->primindex != 0) continue;
1664
/* if (np->cell == start->cell) continue; */
1665
if ((np->userbits & FACETMOD) == 0) continue;
1666
ni->userbits |= MARKN | TOUCHN;
1669
if (cla_conlaydebug)
1670
ttyputmsg(M_(" Complex tree search at facet %s"), describenodeproto(start));
1672
/* modify the nodes in this facet that changed */
1678
for(ni = start->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1680
if ((ni->userbits & MARKN) == 0) continue;
1681
ni->userbits &= ~MARKN;
1684
/* determine original size of facet */
1685
if ((CHANGE *)np->changeaddr != NOCHANGE &&
1686
((CHANGE *)np->changeaddr)->changetype == NODEPROTOMOD)
1688
/* modification changes carry original size */
1689
flx = ((CHANGE *)np->changeaddr)->p1;
1690
fhx = ((CHANGE *)np->changeaddr)->p2;
1691
fly = ((CHANGE *)np->changeaddr)->p3;
1692
fhy = ((CHANGE *)np->changeaddr)->p4;
1695
/* creation changes have no original size: use current size */
1696
flx = np->lowx; fhx = np->highx;
1697
fly = np->lowy; fhy = np->highy;
1699
if (ni->highx-ni->lowx == np->highx-np->lowx && ni->highy-ni->lowy == np->highy-np->lowy)
1700
nlx = nhx = nly = nhy = 0; else
1702
dlx = np->lowx - flx; dhx = np->highx - fhx;
1703
dly = np->lowy - fly; dhy = np->highy - fhy;
1704
makeangle(ni->rotation, ni->transpose, trans);
1705
xform(dhx+dlx, dhy+dly, &offx, &offy, trans);
1706
nlx = (dlx-dhx+offx)/2; nhx = offx - nlx;
1707
nly = (dly-dhy+offy)/2; nhy = offy - nly;
1709
if (cla_modifynodeinst(ni, nlx, nly, nhx, nhy, 0, 0, TRUE)) forcedlook = TRUE;
1714
/* now change the arcs in the nodes in this facet that changed */
1719
for(ni = start->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1721
if ((ni->userbits & TOUCHN) == 0) continue;
1722
ni->userbits &= ~TOUCHN;
1723
if (cla_modnodearcs(ni, 0, 0)) forcedlook = TRUE;
1728
/* now change the size of this facet */
1729
db_boundfacet(start, &nlx,&nhx, &nly,&nhy);
1731
/* quit if it has not changed */
1732
if (start->lowx == nlx && start->highx == nhx && start->lowy == nly &&
1733
start->highy == nhy && !forcedlook)
1735
start->userbits |= FACETNOMOD;
1739
/* update the facet size */
1740
start->changeaddr = (char *)db_change((INTBIG)start, NODEPROTOMOD,
1741
start->lowx, start->highx, start->lowy, start->highy, 0, 0);
1742
start->lowx = nlx; start->highx = nhx;
1743
start->lowy = nly; start->highy = nhy;