1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: rout.c
6 * Routines for the wire routing tool
7 * Written by: Steven M. Rubin, Static Free Software
8 *
9 * Copyright (c) 2000 Static Free Software.
10 *
11 * Electric(tm) is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Electric(tm) is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Electric(tm); see the file COPYING. If not, write to
23 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24 * Boston, Mass 02111-1307, USA.
25 *
26 * Static Free Software
27 * 4119 Alpine Road
28 * Portola Valley, California 94028
29 * info@staticfreesoft.com
30 */
31
32 #include "config.h"
33 #if ROUTTOOL
34
35 #include "global.h"
36 #include "rout.h"
37 #include "usr.h"
38 #include "tecschem.h"
39 #include "tecgen.h"
40 #include "edialogs.h"
41 #include "efunction.h"
42
43 /* the ROUTER tool table */
44 static COMCOMP routercellp = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
45 INPUTOPT, x_(" \t"), M_("Cell to stitch"), 0};
46 static COMCOMP routerarcp = {NOKEYWORD, topofarcs, nextarcs, NOPARAMS,
47 INPUTOPT, x_(" \t"), M_("Arc prototype to use in stitching (* to reset)"), 0};
48 static KEYWORD routerautoopt[] =
49 {
50 {x_("stitch-now"), 1,{&routercellp,NOKEY,NOKEY,NOKEY,NOKEY}},
51 {x_("highlighted-stitch-now"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
52 TERMKEY
53 };
54 static COMCOMP routerautop = {routerautoopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
55 INPUTOPT, x_(" \t"), M_("Auto-stitching action"), 0};
56 static KEYWORD routermimicopt[] =
57 {
58 {x_("do-now"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
59 {x_("mimic-selected"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
60 {x_("enable"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
61 {x_("stitch-and-unstitch"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
62 {x_("stitch-only"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
63 {x_("port-general"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
64 {x_("port-specific"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
65 {x_("any-arc-count"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
66 {x_("same-arc-count"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
67 TERMKEY
68 };
69 static COMCOMP routermimicp = {routermimicopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
70 INPUTOPT, x_(" \t"), M_("Mimic-stitching action"), 0};
71 static COMCOMP routerriverp = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
72 INPUTOPT, x_(" \t"), M_("Cell to river-route"), 0};
73 static COMCOMP routermazesetboundaryp = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
74 0, x_(" \t"), M_("routing boundary"), 0};
75 static COMCOMP routermazesetgridxp = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
76 0, x_(" \t"), M_("routing grid x"), 0};
77 static COMCOMP routermazesetgridyp = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
78 0, x_(" \t"), M_("routing grid y"), 0};
79 static COMCOMP routermazesetoffsetxp = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
80 0, x_(" \t"), M_("routing offset x"), 0};
81 static COMCOMP routermazesetoffsetyp = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
82 0, x_(" \t"), M_("routing offset y"), 0};
83 static KEYWORD routermazesetopt[] =
84 {
85 {x_("boundary"), 1,{&routermazesetboundaryp,NOKEY,NOKEY,NOKEY,NOKEY}},
86 {x_("grid"), 2,{&routermazesetgridxp,&routermazesetgridyp,NOKEY,NOKEY,NOKEY}},
87 {x_("offset"), 2,{&routermazesetoffsetxp,&routermazesetoffsetyp,NOKEY,NOKEY,NOKEY}},
88 TERMKEY
89 };
90 static COMCOMP routermazesetp = {routermazesetopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
91 0, x_(" \t"), M_("set operation"), 0 };
92 static KEYWORD routermazerouteopt[] =
93 {
94 {x_("cell"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
95 {x_("selected"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
96 TERMKEY
97 };
98 static COMCOMP routermazeroutep = {routermazerouteopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
99 0, x_(" \t"), M_("routing operation"), 0 };
100 static KEYWORD routermazeopt[] =
101 {
102 {x_("set"), 1, {&routermazesetp,NOKEY,NOKEY,NOKEY,NOKEY}},
103 {x_("route"), 1, {&routermazeroutep,NOKEY,NOKEY,NOKEY,NOKEY}},
104 TERMKEY
105 };
106 static COMCOMP routermazep = {routermazeopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
107 0, x_(" \t"), M_("Maze routing operation"), 0 };
108 static KEYWORD routernopt[] =
109 {
110 {x_("select"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
111 TERMKEY
112 };
113 static COMCOMP routernp = {routernopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
114 INPUTOPT, x_(" \t"), M_("Negating action"), 0};
115 static KEYWORD routeropt[] =
116 {
117 {x_("auto-stitch"), 1,{&routerautop,NOKEY,NOKEY,NOKEY,NOKEY}},
118 {x_("mimic-stitch"), 1,{&routermimicp,NOKEY,NOKEY,NOKEY,NOKEY}},
119 {x_("river-route"), 1,{&routerriverp,NOKEY,NOKEY,NOKEY,NOKEY}},
120 {x_("maze-route"), 1,{&routermazep,NOKEY,NOKEY,NOKEY,NOKEY}},
121 {x_("use-arc"), 1,{&routerarcp,NOKEY,NOKEY,NOKEY,NOKEY}},
122 {x_("select"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
123 {x_("no-stitch"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
124 {x_("unroute"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
125 {x_("copy-topology"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
126 {x_("paste-topology"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
127 {x_("not"), 1,{&routernp,NOKEY,NOKEY,NOKEY,NOKEY}},
128 TERMKEY
129 };
130 COMCOMP ro_routerp = {routeropt, NOTOPLIST, NONEXTLIST, NOPARAMS,
131 0, x_(" \t"), M_("Routing action"), 0};
132
133 RCHECK *ro_firstrcheck;
134 static RCHECK *ro_rcheckfree;
135
136 static TOOL *ro_source; /* source of batch of changes */
137 INTBIG ro_statekey; /* variable key for "ROUT_state" */
138 INTBIG ro_state; /* cached value for "ROUT_state" */
139 static INTBIG ro_optionskey; /* variable key for "ROUT_options" */
140 INTBIG ro_preferedkey; /* variable key for "ROUT_prefered_arc" */
141 NODEPROTO *ro_copiedtopocell; /* cell whose topology is being copied */
142 TOOL *ro_tool; /* the Router tool object */
143 POLYLIST *ro_autostitchplist; /* for auto-stitching */
144
145 static ROUTACTIVITY ro_curroutactivity; /* routing activity in the current slice */
146 ROUTACTIVITY ro_lastactivity; /* last routing activity */
147 NODEINST *ro_deletednodes[2]; /* nodes at end of last deleted arc */
148 PORTPROTO *ro_deletedports[2]; /* ports on nodes at end of last deleted arc */
149
150 /* working memory for "ro_findnetends()" */
151 static INTBIG ro_findnetlisttotal = 0;
152 static NODEINST **ro_findnetlistni;
153 static PORTPROTO **ro_findnetlistpp;
154 static INTBIG *ro_findnetlistx;
155 static INTBIG *ro_findnetlisty;
156
157 /* prototypes for local routines */
158 static RCHECK *ro_allocrcheck(void);
159 static void ro_queuercheck(NODEINST*);
160 static void ro_unroutecurrent(void);
161 static BOOLEAN ro_unroutenet(NETWORK *net);
162 static void ro_optionsdlog(void);
163 static void ro_pastetopology(NODEPROTO *np);
164 static int ro_sortinstspatially(const void *e1, const void *e2);
165 static BOOLEAN ro_makeunroutedconnection(NODEINST *fni, PORTPROTO *fpp, NODEINST *tni, PORTPROTO *tpp);
166
167 /*
168 * routine to allocate a new check module from the pool (if any) or memory
169 */
ro_allocrcheck(void)170 RCHECK *ro_allocrcheck(void)
171 {
172 REGISTER RCHECK *r;
173
174 if (ro_rcheckfree == NORCHECK)
175 {
176 r = (RCHECK *)emalloc(sizeof (RCHECK), ro_tool->cluster);
177 if (r == 0) return(NORCHECK);
178 } else
179 {
180 r = ro_rcheckfree;
181 ro_rcheckfree = (RCHECK *)r->nextcheck;
182 }
183 return(r);
184 }
185
186 /*
187 * routine to return check module "r" to the pool of free modules
188 */
ro_freercheck(RCHECK * r)189 void ro_freercheck(RCHECK *r)
190 {
191 r->nextcheck = ro_rcheckfree;
192 ro_rcheckfree = r;
193 }
194
195 /*
196 * routine to queue nodeinst "ni" to be checked during the next slice of
197 * the router
198 */
ro_queuercheck(NODEINST * ni)199 void ro_queuercheck(NODEINST *ni)
200 {
201 REGISTER RCHECK *r;
202
203 r = ro_allocrcheck();
204 if (r == NORCHECK)
205 {
206 ttyputnomemory();
207 return;
208 }
209 r->entity = ni;
210 r->nextcheck = ro_firstrcheck;
211 ro_firstrcheck = r;
212 }
213
ro_init(INTBIG * argc,CHAR1 * argv[],TOOL * thistool)214 void ro_init(INTBIG *argc, CHAR1 *argv[], TOOL *thistool)
215 {
216 Q_UNUSED( argc );
217 Q_UNUSED( argv );
218
219 if (thistool == 0)
220 {
221 /* pass 3: nothing to do */
222 /* EMPTY */
223 } else if (thistool == NOTOOL)
224 {
225 /* pass 2: nothing to do */
226 /* EMPTY */
227 } else
228 {
229 /* pass 1: initialize */
230 ro_tool = thistool;
231
232 /* set default mode for router: cell stitching */
233 ro_statekey = makekey(x_("ROUT_state"));
234 ro_optionskey = makekey(x_("ROUT_options"));
235 ro_preferedkey = makekey(x_("ROUT_prefered_arc"));
236 nextchangequiet();
237 ro_state = NOSTITCH;
238 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_statekey, ro_state, VINTEGER|VDONTSAVE);
239
240 /* initialize the free lists */
241 ro_rcheckfree = NORCHECK;
242 ro_firstrcheck = NORCHECK;
243
244 /* no last activity to mimic */
245 ro_lastactivity.numcreatedarcs = ro_lastactivity.numcreatednodes = 0;
246 ro_lastactivity.numdeletedarcs = ro_lastactivity.numdeletednodes = 0;
247
248 /* no cell topology was copied */
249 ro_copiedtopocell = NONODEPROTO;
250
251 /* setup polylist */
252 ro_autostitchplist = allocpolylist(ro_tool->cluster);
253 if (ro_autostitchplist == 0) return;
254
255 /* delcare dialogs */
256 DiaDeclareHook(x_("routeopt"), &routerarcp, ro_optionsdlog);
257 }
258 }
259
ro_done(void)260 void ro_done(void)
261 {
262 #ifdef DEBUGMEMORY
263 RCHECK *r;
264
265 /* free all check modules */
266 while (ro_firstrcheck != NORCHECK)
267 {
268 r = ro_firstrcheck;
269 ro_firstrcheck = ro_firstrcheck->nextcheck;
270 ro_freercheck(r);
271 }
272 while (ro_rcheckfree != NORCHECK)
273 {
274 r = ro_rcheckfree;
275 ro_rcheckfree = ro_rcheckfree->nextcheck;
276 efree((CHAR *)r);
277 }
278
279 if (ro_findnetlisttotal > 0)
280 {
281 efree((CHAR *)ro_findnetlistni);
282 efree((CHAR *)ro_findnetlistpp);
283 efree((CHAR *)ro_findnetlistx);
284 efree((CHAR *)ro_findnetlisty);
285 }
286
287 freepolylist(ro_autostitchplist);
288 ro_freeautomemory();
289 ro_freemimicmemory();
290 ro_freerivermemory();
291 ro_freemazememory();
292 #endif
293 }
294
ro_set(INTBIG count,CHAR * par[])295 void ro_set(INTBIG count, CHAR *par[])
296 {
297 REGISTER INTBIG l, savestate;
298 REGISTER NODEPROTO *np;
299 REGISTER ARCPROTO *ap;
300 REGISTER ARCINST *ai;
301 REGISTER NODEINST *ni;
302 REGISTER CHAR *pp;
303 REGISTER GEOM **list;
304 REGISTER VARIABLE *var;
305
306 if (count == 0)
307 {
308 switch (ro_state&STITCHMODE)
309 {
310 case NOSTITCH:
311 ttyputmsg(M_("No stitching being done")); break;
312 case AUTOSTITCH:
313 ttyputmsg(M_("Default is auto-stitch routing")); break;
314 case MIMICSTITCH:
315 ttyputmsg(M_("Default is mimic-stitch routing")); break;
316 }
317 var = getvalkey((INTBIG)ro_tool, VTOOL, VARCPROTO, ro_preferedkey);
318 if (var != NOVARIABLE)
319 ttyputmsg(M_("Default arc for river routing is %s"),
320 describearcproto(((ARCPROTO *)var->addr)));
321 return;
322 }
323
324 l = estrlen(pp = par[0]);
325
326 if (namesamen(pp, x_("no-stitch"), l) == 0)
327 {
328 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_statekey,
329 (ro_state & ~STITCHMODE) | NOSTITCH, VINTEGER|VDONTSAVE);
330 return;
331 }
332
333 if (namesamen(pp, x_("auto-stitch"), l) == 0)
334 {
335 if (count <= 1) return;
336 l = estrlen(pp = par[1]);
337 if (namesamen(pp, x_("enable"), l) == 0)
338 {
339 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_statekey,
340 (ro_state & ~STITCHMODE) | AUTOSTITCH, VINTEGER|VDONTSAVE);
341 return;
342 }
343 if (namesamen(pp, x_("stitch-now"), l) == 0)
344 {
345 if (count >= 3)
346 {
347 np = getnodeproto(par[2]);
348 if (np == NONODEPROTO)
349 {
350 ttyputerr(_("No cell named %s"), par[2]);
351 return;
352 }
353 if (np->primindex != 0)
354 {
355 ttyputerr(M_("Can only stitch cells, not primitives"));
356 return;
357 }
358 if (np->lib != el_curlib)
359 {
360 ttyputerr(_("Can only stitch cells in the current library"));
361 return;
362 }
363 } else
364 {
365 np = getcurcell();
366 if (np == NONODEPROTO)
367 {
368 ttyputerr(_("No current cell"));
369 return;
370 }
371 }
372
373 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
374 {
375 /* ignore recursive references (showing icon in contents) */
376 if (isiconof(ni->proto, np)) continue;
377 ro_queuercheck(ni);
378 }
379
380 /* fake enabling of auto-stitching */
381 savestate = ro_state;
382 ro_state |= AUTOSTITCH;
383
384 /* do the stitching */
385 ro_slice();
386
387 /* restore routing state */
388 ro_state = savestate;
389 ttyputverbose(M_("Cell %s stitched"), describenodeproto(np));
390 return;
391 }
392 if (namesamen(pp, x_("highlighted-stitch-now"), l) == 0)
393 {
394 list = (GEOM **)asktool(us_tool, x_("get-all-nodes"));
395 if (list[0] == NOGEOM)
396 {
397 ttyputerr(_("Select an area to be stitched"));
398 return;
399 }
400 for(l=0; list[l] != NOGEOM; l++)
401 ro_queuercheck(list[l]->entryaddr.ni);
402
403 /* fake enabling of auto-stitching */
404 savestate = ro_state;
405 ro_state |= AUTOSTITCH;
406
407 /* do the stitching */
408 ro_slice();
409
410 /* restore routing state */
411 ro_state = savestate;
412 ttyputverbose(M_("Stitching complete"));
413 return;
414 }
415 ttyputbadusage(x_("telltool routing auto-stitch"));
416 return;
417 }
418
419 if (namesamen(pp, x_("mimic-stitch"), l) == 0 && l > 1)
420 {
421 if (count < 2)
422 {
423 ttyputusage(x_("telltool routing mimic-stitch OPTION"));
424 return;
425 }
426 l = estrlen(pp = par[1]);
427 if (namesamen(pp, x_("do-now"), l) == 0)
428 {
429 ro_mimicstitch(TRUE);
430 return;
431 }
432 if (namesamen(pp, x_("mimic-selected"), l) == 0)
433 {
434 ai = (ARCINST *)us_getobject(VARCINST, FALSE);
435 if (ai == NOARCINST) return;
436 ro_lastactivity.numdeletedarcs = 0;
437 ro_lastactivity.numcreatedarcs = 1;
438 ro_lastactivity.createdarcs[0] = ai;
439
440 ro_mimicstitch(TRUE);
441 return;
442 }
443 if (namesamen(pp, x_("enable"), l) == 0)
444 {
445 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_statekey,
446 (ro_state & ~STITCHMODE) | MIMICSTITCH, VINTEGER|VDONTSAVE);
447 return;
448 }
449 if (namesamen(pp, x_("stitch-and-unstitch"), l) == 0 && l >= 8)
450 {
451 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_optionskey,
452 ro_getoptions() | MIMICUNROUTES, VINTEGER);
453 ttyputverbose(M_("Mimic stitcher will route and unroute"));
454 return;
455 }
456 if (namesamen(pp, x_("stitch-only"), l) == 0 && l >= 8)
457 {
458 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_optionskey,
459 ro_getoptions() & ~MIMICUNROUTES, VINTEGER);
460 ttyputverbose(M_("Mimic stitcher will only route, not unroute"));
461 return;
462 }
463 if (namesamen(pp, x_("port-general"), l) == 0 && l >= 8)
464 {
465 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_optionskey,
466 ro_getoptions() | MIMICIGNOREPORTS, VINTEGER);
467 ttyputverbose(M_("Mimic stitcher will route to any port"));
468 return;
469 }
470 if (namesamen(pp, x_("port-specific"), l) == 0 && l >= 8)
471 {
472 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_optionskey,
473 ro_getoptions() & ~MIMICIGNOREPORTS, VINTEGER);
474 ttyputverbose(M_("Mimic stitcher will rout only to similar ports"));
475 return;
476 }
477 if (namesamen(pp, x_("any-arc-count"), l) == 0 && l >= 8)
478 {
479 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_optionskey,
480 ro_getoptions() & ~MIMICONSIDERARCCOUNT, VINTEGER);
481 ttyputverbose(M_("Mimic stitcher will route without regard to arc count"));
482 return;
483 }
484 if (namesamen(pp, x_("same-arc-count"), l) == 0 && l >= 8)
485 {
486 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_optionskey,
487 ro_getoptions() | MIMICONSIDERARCCOUNT, VINTEGER);
488 ttyputverbose(M_("Mimic stitcher will rout only where arc counts are the same"));
489 return;
490 }
491 ttyputbadusage(x_("telltool routing mimic-stitching"));
492 return;
493 }
494
495 if (namesamen(pp, x_("river-route"), l) == 0)
496 {
497 if (count >= 2)
498 {
499 np = getnodeproto(par[1]);
500 if (np == NONODEPROTO)
501 {
502 ttyputerr(_("No cell named %s"), par[1]);
503 return;
504 }
505 if (np->primindex != 0)
506 {
507 ttyputerr(M_("Can only route cells, not primitives"));
508 return;
509 }
510 } else
511 {
512 np = getcurcell();
513 if (np == NONODEPROTO)
514 {
515 ttyputerr(_("No current cell"));
516 return;
517 }
518 }
519
520 if (ro_river(np)) ttyputverbose(M_("Cell %s river-routed"), describenodeproto(np)); else
521 ttyputmsg(_("Routing not successful"));
522 return;
523 }
524
525 if (namesamen(pp, x_("maze-route"), l) == 0 && l > 1)
526 {
527 l = estrlen(pp = par[1]);
528 if (namesamen(pp, x_("route"), l) == 0)
529 {
530 if (count <= 2) return;
531 l = estrlen(pp = par[2]);
532 if (namesamen(pp, x_("cell"), l) == 0)
533 {
534 ro_mazeroutecell();
535 return;
536 }
537 if (namesamen(pp, x_("selected"), l) == 0)
538 {
539 ro_mazerouteselected();
540 return;
541 }
542 ttyputbadusage(x_("telltool routing maze-route"));
543 return;
544 }
545 if (namesamen(pp, x_("set"), l) == 0)
546 {
547 if (count <= 2)
548 {
549 ttyputmsg(M_("Routing grid: %sx%s"), latoa(ro_mazegridx, 0), latoa(ro_mazegridy, 0));
550 ttyputmsg(M_("Routing offset: (%s,%s)"), latoa(ro_mazeoffsetx, 0), latoa(ro_mazeoffsety, 0));
551 ttyputmsg(M_("Routing boundary: %s"), latoa(ro_mazeboundary, 0));
552 return;
553 }
554
555 l = estrlen(pp = par[2]);
556 if (namesamen(pp, x_("grid"), l) == 0)
557 {
558 ro_mazegridx = atola(par[3], 0);
559 ro_mazegridy = atola(par[4], 0);
560 ttyputmsg(M_("Routing grid: %sx%s"), latoa(ro_mazegridx, 0), latoa(ro_mazegridy, 0));
561 return;
562 }
563 if (namesamen(pp, x_("offset"), l) == 0)
564 {
565 ro_mazeoffsetx = atola(par[3], 0);
566 ro_mazeoffsety = atola(par[4], 0);
567 ttyputmsg(M_("Routing offset: (%s,%s)"), latoa(ro_mazeoffsetx, 0), latoa(ro_mazeoffsety, 0));
568 return;
569 }
570 if (namesamen(pp, x_("boundary"), l) == 0)
571 {
572 ro_mazeboundary = atola(par[3], 0);
573 ttyputmsg(M_("Routing boundary: %s"), latoa(ro_mazeboundary, 0));
574 return;
575 }
576
577 ttyputbadusage(x_("telltool routing maze-route set"));
578 return;
579 }
580 }
581
582 if (namesamen(pp, x_("copy-topology"), l) == 0)
583 {
584 np = getcurcell();
585 if (np == NONODEPROTO)
586 {
587 ttyputerr(_("No current cell"));
588 return;
589 }
590 ro_copiedtopocell = np;
591 return;
592 }
593 if (namesamen(pp, x_("paste-topology"), l) == 0 && l >= 3)
594 {
595 np = getcurcell();
596 if (np == NONODEPROTO)
597 {
598 ttyputerr(_("No current cell"));
599 return;
600 }
601 ro_pastetopology(np);
602 return;
603 }
604
605 if (namesamen(pp, x_("use-arc"), l) == 0)
606 {
607 if (count < 2)
608 {
609 ttyputusage(x_("telltool routing use-arc ARCPROTO"));
610 return;
611 }
612 if (estrcmp(par[1], x_("*")) == 0)
613 {
614 if (getvalkey((INTBIG)ro_tool, VTOOL, VARCPROTO, ro_preferedkey) != NOVARIABLE)
615 (void)delvalkey((INTBIG)ro_tool, VTOOL, ro_preferedkey);
616 ttyputverbose(M_("No arc will be presumed for stitching"));
617 return;
618 }
619 ap = getarcproto(par[1]);
620 if (ap == NOARCPROTO)
621 {
622 ttyputerr(M_("No arc prototype called %s"), par[1]);
623 return;
624 }
625 ttyputverbose(M_("Default stitching arc will be %s"), describearcproto(ap));
626 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_preferedkey, (INTBIG)ap, VARCPROTO);
627 return;
628 }
629
630 if (namesamen(pp, x_("unroute"), l) == 0)
631 {
632 ro_unroutecurrent();
633 return;
634 }
635
636 if (namesamen(pp, x_("not"), l) == 0)
637 {
638 if (count <= 1)
639 {
640 ttyputusage(x_("telltool routing not OPTION"));
641 return;
642 }
643 l = estrlen(pp = par[1]);
644 if (namesamen(pp, x_("select"), l) == 0)
645 {
646 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_statekey,
647 ro_state & ~SELECT, VINTEGER|VDONTSAVE);
648 ttyputverbose(M_("Wire placement not subject to approval"));
649 return;
650 }
651 ttyputbadusage(x_("telltool routing not"));
652 return;
653 }
654
655 if (namesamen(pp, x_("select"), l) == 0)
656 {
657 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_statekey,
658 ro_state | SELECT, VINTEGER|VDONTSAVE);
659 ttyputverbose(M_("Wire placement subject to approval"));
660 return;
661 }
662
663 ttyputbadusage(x_("telltool routing"));
664 }
665
ro_slice(void)666 void ro_slice(void)
667 {
668 if ((ro_state&(SELSKIP|SELDONE)) != 0)
669 {
670 ro_state &= ~(SELSKIP|SELDONE);
671 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_statekey, ro_state, VINTEGER|VDONTSAVE);
672 }
673
674 switch (ro_state&STITCHMODE)
675 {
676 case AUTOSTITCH:
677 ro_autostitch();
678 setactivity(_("Cells stitched"));
679 break;
680 case MIMICSTITCH:
681 ro_mimicstitch(FALSE);
682 setactivity(_("Cells stitched"));
683 break;
684 }
685 }
686
687 /******************** DATABASE CHANGES ********************/
688
ro_startbatch(TOOL * source,BOOLEAN undoredo)689 void ro_startbatch(TOOL *source, BOOLEAN undoredo)
690 {
691 Q_UNUSED( undoredo );
692
693 /* code cannot be called by multiple procesors: uses globals */
694 NOT_REENTRANT;
695
696 ro_source = source;
697
698 /* clear the record of routing activity in this batch */
699 ro_curroutactivity.numcreatedarcs = ro_curroutactivity.numcreatednodes = 0;
700 ro_curroutactivity.numdeletedarcs = ro_curroutactivity.numdeletednodes = 0;
701 }
702
ro_endbatch(void)703 void ro_endbatch(void)
704 {
705 REGISTER INTBIG i;
706
707 /* if there was any routing activity not by this tool, set this to the last one */
708 if (ro_curroutactivity.numcreatedarcs != 0 || ro_curroutactivity.numcreatednodes != 0 ||
709 ro_curroutactivity.numdeletedarcs != 0 || ro_curroutactivity.numdeletednodes != 0)
710 {
711 ro_lastactivity.numcreatedarcs = ro_curroutactivity.numcreatedarcs;
712 for(i=0; i<ro_lastactivity.numcreatedarcs; i++)
713 ro_lastactivity.createdarcs[i] = ro_curroutactivity.createdarcs[i];
714 ro_lastactivity.numcreatednodes = ro_curroutactivity.numcreatednodes;
715 for(i=0; i<ro_lastactivity.numcreatednodes; i++)
716 ro_lastactivity.creatednodes[i] = ro_curroutactivity.creatednodes[i];
717 ro_lastactivity.numdeletedarcs = ro_curroutactivity.numdeletedarcs;
718 for(i=0; i<ro_lastactivity.numdeletedarcs; i++)
719 ro_lastactivity.deletedarcs[i] = ro_curroutactivity.deletedarcs[i];
720 ro_lastactivity.numdeletednodes = ro_curroutactivity.numdeletednodes;
721 for(i=0; i<ro_lastactivity.numdeletednodes; i++)
722 ro_lastactivity.deletednodes[i] = ro_curroutactivity.deletednodes[i];
723 }
724 }
725
ro_modifynodeinst(NODEINST * ni,INTBIG oldlx,INTBIG oldly,INTBIG oldhx,INTBIG oldhy,INTBIG oldrot,INTBIG oldtran)726 void ro_modifynodeinst(NODEINST *ni, INTBIG oldlx, INTBIG oldly, INTBIG oldhx,
727 INTBIG oldhy, INTBIG oldrot, INTBIG oldtran)
728 {
729 Q_UNUSED( oldlx );
730 Q_UNUSED( oldly );
731 Q_UNUSED( oldhx );
732 Q_UNUSED( oldhy );
733 Q_UNUSED( oldrot );
734 Q_UNUSED( oldtran );
735
736 if ((ro_state&STITCHMODE) == AUTOSTITCH)
737 {
738 if (ro_source != ro_tool) ro_queuercheck(ni);
739 }
740 }
741
ro_modifyarcinst(ARCINST * ai,INTBIG oldxA,INTBIG oldyA,INTBIG oldxB,INTBIG oldyB,INTBIG oldwid,INTBIG oldlen)742 void ro_modifyarcinst(ARCINST *ai, INTBIG oldxA, INTBIG oldyA, INTBIG oldxB,
743 INTBIG oldyB, INTBIG oldwid, INTBIG oldlen)
744 {
745 Q_UNUSED( ai );
746 Q_UNUSED( oldxA );
747 Q_UNUSED( oldyA );
748 Q_UNUSED( oldxB );
749 Q_UNUSED( oldyB );
750 Q_UNUSED( oldwid );
751 Q_UNUSED( oldlen );
752 }
753
ro_modifyportproto(PORTPROTO * pp,NODEINST * oldsubni,PORTPROTO * oldsubpp)754 void ro_modifyportproto(PORTPROTO *pp, NODEINST *oldsubni, PORTPROTO *oldsubpp)
755 {
756 Q_UNUSED( pp );
757 Q_UNUSED( oldsubni );
758 Q_UNUSED( oldsubpp );
759 }
760
ro_newobject(INTBIG addr,INTBIG type)761 void ro_newobject(INTBIG addr, INTBIG type)
762 {
763 REGISTER NODEINST *ni;
764 REGISTER ARCINST *ai;
765
766 if (ro_source == ro_tool) return;
767 if ((type&VTYPE) == VNODEINST)
768 {
769 ni = (NODEINST *)addr;
770 if (ro_curroutactivity.numcreatednodes < 3)
771 ro_curroutactivity.creatednodes[ro_curroutactivity.numcreatednodes++] = ni;
772 if ((ro_state&STITCHMODE) == AUTOSTITCH)
773 ro_queuercheck(ni);
774 } else if ((type&VTYPE) == VARCINST)
775 {
776 ai = (ARCINST *)addr;
777 if (ro_curroutactivity.numcreatedarcs < 3)
778 ro_curroutactivity.createdarcs[ro_curroutactivity.numcreatedarcs++] = ai;
779 }
780 }
781
ro_killobject(INTBIG addr,INTBIG type)782 void ro_killobject(INTBIG addr, INTBIG type)
783 {
784 REGISTER NODEINST *ni;
785 REGISTER ARCINST *ai;
786
787 if (ro_source == ro_tool) return;
788 if ((type&VTYPE) == VNODEINST)
789 {
790 ni = (NODEINST *)addr;
791 if (ro_curroutactivity.numdeletednodes < 3)
792 ro_curroutactivity.deletednodes[ro_curroutactivity.numdeletednodes++] = ni;
793 } else if ((type&VTYPE) == VARCINST)
794 {
795 ai = (ARCINST *)addr;
796 if (ro_curroutactivity.numdeletedarcs < 2)
797 ro_curroutactivity.deletedarcs[ro_curroutactivity.numdeletedarcs++] = ai;
798
799 ro_deletednodes[0] = ai->end[0].nodeinst;
800 ro_deletednodes[1] = ai->end[1].nodeinst;
801 ro_deletedports[0] = ai->end[0].portarcinst->proto;
802 ro_deletedports[1] = ai->end[1].portarcinst->proto;
803 }
804 }
805
ro_newvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG newtype)806 void ro_newvariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG newtype)
807 {
808 REGISTER VARIABLE *var;
809
810 if ((newtype&VCREF) != 0) return;
811 if (key == ro_statekey)
812 {
813 var = getvalkey(addr, type, VINTEGER, key);
814 if (var != NOVARIABLE) ro_state = var->addr;
815 return;
816 }
817 }
818
819 /*********************** CODE TO UNROUTE (CONVERT TO UNROUTED WIRE) ***********************/
820
821 /* Routine to convert the current network(s) to an unrouted wire */
ro_unroutecurrent(void)822 void ro_unroutecurrent(void)
823 {
824 GEOM **list;
825 REGISTER NETWORK *net;
826 REGISTER NODEPROTO *np;
827 REGISTER ARCINST *ai;
828 REGISTER INTBIG i, selectcount;
829 REGISTER BOOLEAN found;
830
831 /* see what is highlighted */
832 list = us_gethighlighted(WANTARCINST, 0, 0);
833 for(selectcount=0; list[selectcount] != NOGEOM; selectcount++) ;
834 if (selectcount == 0)
835 {
836 ttyputerr(_("Must select arcs to unroute"));
837 return;
838 }
839 np = geomparent(list[0]);
840
841 /* convert requested nets */
842 us_clearhighlightcount();
843 found = TRUE;
844 while (found)
845 {
846 /* no net found yet */
847 found = FALSE;
848
849 /* find a net to be routed */
850 for(net = np->firstnetwork; net != NONETWORK;
851 net = net->nextnetwork)
852 {
853 /* is the net included in the selection list? */
854 for(i=0; i<selectcount; i++)
855 {
856 if (list[i] == NOGEOM) continue;
857 if (list[i]->entryisnode) continue;
858 ai = list[i]->entryaddr.ai;
859 if (ai->network == net) break;
860 }
861 if (i >= selectcount) continue;
862
863 /* yes: remove all arcs that have this net from the selection */
864 for(i=0; i<selectcount; i++)
865 {
866 if (list[i] == NOGEOM) continue;
867 if (list[i]->entryisnode) continue;
868 ai = list[i]->entryaddr.ai;
869 if (ai->network == net) list[i] = NOGEOM;
870 }
871
872 /* now unroute the net */
873 if (ro_unroutenet(net)) return;
874 found = TRUE;
875 break;
876 }
877 }
878 }
879
ro_unroutenet(NETWORK * net)880 BOOLEAN ro_unroutenet(NETWORK *net)
881 {
882 INTBIG *xlist, *ylist, count;
883 NODEINST **nilist;
884 PORTPROTO **pplist;
885 REGISTER ARCINST *ai, *nextai;
886 REGISTER NODEINST *ni, *nextni;
887 REGISTER NODEPROTO *np;
888 REGISTER INTBIG bits, wid, i, j, dist, bestdist, first, found, besti, bestj;
889 REGISTER INTBIG *covered;
890
891 /* convert this net and mark arcs and nodes on it */
892 count = ro_findnetends(net, &nilist, &pplist, &xlist, &ylist);
893
894 /* remove marked nodes and arcs */
895 np = net->parent;
896 for(ai = np->firstarcinst; ai != NOARCINST; ai = nextai)
897 {
898 nextai = ai->nextarcinst;
899 if (ai->temp1 == 0) continue;
900 startobjectchange((INTBIG)ai, VARCINST);
901 if (killarcinst(ai))
902 {
903 ttyputerr(_("Error deleting arc"));
904 return(TRUE);
905 }
906 }
907 for(ni = np->firstnodeinst; ni != NONODEINST; ni = nextni)
908 {
909 nextni = ni->nextnodeinst;
910 if (ni->temp1 == 0) continue;
911 startobjectchange((INTBIG)ni, VNODEINST);
912 if (killnodeinst(ni))
913 {
914 ttyputerr(_("Error deleting intermediate node"));
915 return(TRUE);
916 }
917 }
918
919 /* now create the new unrouted wires */
920 bits = us_makearcuserbits(gen_unroutedarc);
921 wid = defaultarcwidth(gen_unroutedarc);
922 covered = (INTBIG *)emalloc(count * SIZEOFINTBIG, el_tempcluster);
923 if (covered == 0) return(FALSE);
924 for(i=0; i<count; i++) covered[i] = 0;
925 for(first=0; ; first++)
926 {
927 found = 1;
928 bestdist = besti = bestj = 0;
929 for(i=0; i<count; i++)
930 {
931 for(j=i+1; j<count; j++)
932 {
933 if (first != 0)
934 {
935 if (covered[i] + covered[j] != 1) continue;
936 }
937 dist = computedistance(xlist[i], ylist[i], xlist[j], ylist[j]);
938
939 /* LINTED "bestdist" used in proper order */
940 if (found == 0 && dist >= bestdist) continue;
941 found = 0;
942 bestdist = dist;
943 besti = i;
944 bestj = j;
945 }
946 }
947 if (found != 0) break;
948
949 covered[besti] = covered[bestj] = 1;
950 ai = newarcinst(gen_unroutedarc, wid, bits,
951 nilist[besti], pplist[besti], xlist[besti], ylist[besti],
952 nilist[bestj], pplist[bestj], xlist[bestj], ylist[bestj], np);
953 if (ai == NOARCINST)
954 {
955 ttyputerr(_("Could not create unrouted arc"));
956 return(TRUE);
957 }
958 endobjectchange((INTBIG)ai, VARCINST);
959 (void)asktool(us_tool, x_("show-object"), (INTBIG)ai->geom);
960 }
961 return(FALSE);
962 }
963
964 /*
965 * Routine to find the endpoints of network "net" and store them in the array
966 * "ni/pp/xp/yp". Returns the number of nodes in the array.
967 * As a side effect, sets "temp1" on nodes and arcs to nonzero if they are part
968 * of the network.
969 */
ro_findnetends(NETWORK * net,NODEINST *** nilist,PORTPROTO *** pplist,INTBIG ** xplist,INTBIG ** yplist)970 INTBIG ro_findnetends(NETWORK *net, NODEINST ***nilist, PORTPROTO ***pplist,
971 INTBIG **xplist, INTBIG **yplist)
972 {
973 REGISTER NODEPROTO *np;
974 REGISTER NODEINST *ni;
975 REGISTER ARCINST *ai;
976 REGISTER PORTARCINST *pi, *thispi;
977 REGISTER BOOLEAN term;
978 INTBIG listcount, newtotal, i, j;
979 NODEINST **newlistni;
980 PORTPROTO **newlistpp;
981 INTBIG *newlistx;
982 INTBIG *newlisty;
983
984 /* initialize */
985 np = net->parent;
986 listcount = 0;
987 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst) ai->temp1 = 0;
988 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst) ni->temp1 = 0;
989
990 /* look at every arc and see if it is part of the network */
991 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
992 {
993 if (ai->network != net) continue;
994 ai->temp1 = 1;
995
996 /* see if an end of the arc is a network "end" */
997 for(i=0; i<2; i++)
998 {
999 ni = ai->end[i].nodeinst;
1000 thispi = ai->end[i].portarcinst;
1001 term = FALSE;
1002 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1003 if (pi != thispi && pi->conarcinst->network == net) break;
1004 if (pi == NOPORTARCINST) term = TRUE;
1005 if (ni->firstportexpinst != NOPORTEXPINST) term = TRUE;
1006 if (ni->proto->primindex == 0) term = TRUE;
1007 if (term)
1008 {
1009 /* valid network end: see if it is in the list */
1010 for(j=0; j<listcount; j++)
1011 if (ni == ro_findnetlistni[j] && thispi->proto == ro_findnetlistpp[j])
1012 break;
1013 if (j < listcount) continue;
1014
1015 /* add it to the list */
1016 if (listcount >= ro_findnetlisttotal)
1017 {
1018 newtotal = listcount * 2;
1019 if (newtotal == 0) newtotal = 10;
1020 newlistni = (NODEINST **)emalloc(newtotal * (sizeof (NODEINST *)),
1021 ro_tool->cluster);
1022 newlistpp = (PORTPROTO **)emalloc(newtotal * (sizeof (PORTPROTO *)),
1023 ro_tool->cluster);
1024 newlistx = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG,
1025 ro_tool->cluster);
1026 newlisty = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG,
1027 ro_tool->cluster);
1028 for(j=0; j<listcount; j++)
1029 {
1030 newlistni[j] = ro_findnetlistni[j];
1031 newlistpp[j] = ro_findnetlistpp[j];
1032 newlistx[j] = ro_findnetlistx[j];
1033 newlisty[j] = ro_findnetlisty[j];
1034 }
1035 if (ro_findnetlisttotal > 0)
1036 {
1037 efree((CHAR *)ro_findnetlistni);
1038 efree((CHAR *)ro_findnetlistpp);
1039 efree((CHAR *)ro_findnetlistx);
1040 efree((CHAR *)ro_findnetlisty);
1041 }
1042 ro_findnetlistni = newlistni;
1043 ro_findnetlistpp = newlistpp;
1044 ro_findnetlistx = newlistx;
1045 ro_findnetlisty = newlisty;
1046 ro_findnetlisttotal = newtotal;
1047 }
1048 ro_findnetlistni[listcount] = ni;
1049 ro_findnetlistpp[listcount] = thispi->proto;
1050 ro_findnetlistx[listcount] = ai->end[i].xpos;
1051 ro_findnetlisty[listcount] = ai->end[i].ypos;
1052 listcount++;
1053 } else
1054 {
1055 /* not a network end: mark the node for removal */
1056 ni->temp1 = 1;
1057 }
1058 }
1059 }
1060 *nilist = ro_findnetlistni;
1061 *pplist = ro_findnetlistpp;
1062 *xplist = ro_findnetlistx;
1063 *yplist = ro_findnetlisty;
1064 return(listcount);
1065 }
1066
ro_getoptions(void)1067 INTBIG ro_getoptions(void)
1068 {
1069 REGISTER VARIABLE *var;
1070
1071 var = getvalkey((INTBIG)ro_tool, VTOOL, VINTEGER, ro_optionskey);
1072 if (var != NOVARIABLE) return(var->addr);
1073 return(0);
1074 }
1075
1076 /****************************** TOPOLOGY COPYING ******************************/
1077
1078 /*
1079 * Routine to copy the topology of cell "ro_copiedtopocell" to cell "tonp".
1080 */
ro_pastetopology(NODEPROTO * tonp)1081 void ro_pastetopology(NODEPROTO *tonp)
1082 {
1083 REGISTER LIBRARY *lib;
1084 REGISTER NODEPROTO *np;
1085 REGISTER NODEINST *ni, *oni, *tni, *otni, *fni, *ofni, **fromlist, **tolist;
1086 REGISTER ARCINST *ai, *oai;
1087 REGISTER PORTPROTO *tpp, *otpp, *fpp;
1088 REGISTER PORTARCINST *fpi, *ofpi;
1089 REGISTER NETWORK *net;
1090 REGISTER INTBIG fromcount, tocount, i, j, fun, ofun;
1091 REGISTER CHAR *matchname;
1092 REGISTER VARIABLE *var, *ovar;
1093
1094 if (ro_copiedtopocell == NONODEPROTO)
1095 {
1096 ttyputerr(_("Must copy topology before pasting it"));
1097 return;
1098 }
1099
1100 /* first validate the source cell */
1101 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1102 {
1103 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1104 if (np == ro_copiedtopocell) break;
1105 if (np != NONODEPROTO) break;
1106 }
1107 if (lib == NOLIBRARY)
1108 {
1109 ttyputerr(_("Copied cell is no longer valid"));
1110 return;
1111 }
1112
1113 /* make sure copy goes to a different cell */
1114 if (ro_copiedtopocell == tonp)
1115 {
1116 ttyputerr(_("Topology must be copied to a different cell"));
1117 return;
1118 }
1119
1120 /* reset association pointers in the destination cell */
1121 for(ni = tonp->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1122 ni->temp1 = 0;
1123
1124 /* look for associations */
1125 for(ni = tonp->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1126 {
1127 if (ni->temp1 != 0) continue;
1128
1129 /* ignore connecting nodes */
1130 fun = NPUNKNOWN;
1131 if (ni->proto->primindex != 0)
1132 {
1133 fun = nodefunction(ni);
1134 if (fun == NPUNKNOWN || fun == NPPIN || fun == NPCONTACT ||
1135 fun == NPNODE) continue;
1136 }
1137
1138 /* count the number of this type of node in the two cells */
1139 fromcount = 0;
1140 for(oni = ro_copiedtopocell->firstnodeinst; oni != NONODEINST; oni = oni->nextnodeinst)
1141 {
1142 if (ni->proto->primindex == 0)
1143 {
1144 if (insamecellgrp(oni->proto, ni->proto)) fromcount++;
1145 } else
1146 {
1147 ofun = nodefunction(oni);
1148 if (ofun == fun) fromcount++;
1149 }
1150 }
1151 tocount = 0;
1152 for(oni = tonp->firstnodeinst; oni != NONODEINST; oni = oni->nextnodeinst)
1153 {
1154 if (ni->proto->primindex == 0)
1155 {
1156 if (oni->proto == ni->proto) tocount++;
1157 } else
1158 {
1159 ofun = nodefunction(oni);
1160 if (ofun == fun) tocount++;
1161 }
1162 }
1163
1164 /* problem if the numbers don't match */
1165 if (tocount != fromcount)
1166 {
1167 if (fromcount == 0) continue;
1168 ttyputerr(_("Warning: %s has %ld of %s but cell %s has %ld"),
1169 describenodeproto(ro_copiedtopocell), fromcount, describenodeproto(ni->proto),
1170 describenodeproto(tonp), tocount);
1171 return;
1172 }
1173
1174 /* gather all of the instances */
1175 fromlist = (NODEINST **)emalloc(fromcount * (sizeof (NODEINST *)), ro_tool->cluster);
1176 if (fromlist == 0) return;
1177 fromcount = 0;
1178 for(oni = ro_copiedtopocell->firstnodeinst; oni != NONODEINST; oni = oni->nextnodeinst)
1179 {
1180 if (ni->proto->primindex == 0)
1181 {
1182 if (insamecellgrp(oni->proto, ni->proto)) fromlist[fromcount++] = oni;
1183 } else
1184 {
1185 ofun = nodefunction(oni);
1186 if (ofun == fun) fromlist[fromcount++] = oni;
1187 }
1188 }
1189 tolist = (NODEINST **)emalloc(tocount * (sizeof (NODEINST *)), ro_tool->cluster);
1190 if (tolist == 0) return;
1191 tocount = 0;
1192 for(oni = tonp->firstnodeinst; oni != NONODEINST; oni = oni->nextnodeinst)
1193 {
1194 if (ni->proto->primindex == 0)
1195 {
1196 if (oni->proto == ni->proto) tolist[tocount++] = oni;
1197 } else
1198 {
1199 ofun = nodefunction(oni);
1200 if (ofun == fun) tolist[tocount++] = oni;
1201 }
1202 }
1203
1204 /* look for name matches */
1205 for(i=0; i<fromcount; i++)
1206 {
1207 var = getvalkey((INTBIG)fromlist[i], VNODEINST, VSTRING, el_node_name_key);
1208 if (var == NOVARIABLE) continue;
1209 for(j=0; j<tocount; j++)
1210 {
1211 if (tolist[j] == NONODEINST) continue;
1212 ovar = getvalkey((INTBIG)tolist[j], VNODEINST, VSTRING, el_node_name_key);
1213 if (ovar == NOVARIABLE) continue;
1214 if (namesame((CHAR *)var->addr, (CHAR *)ovar->addr) == 0) break;
1215 }
1216 if (j < tocount)
1217 {
1218 /* name match found: set the association */
1219 tolist[j]->temp1 = (INTBIG)fromlist[i];
1220 fromlist[i] = NONODEINST;
1221 }
1222 }
1223
1224 /* remove the matched instances */
1225 j = 0;
1226 for(i=0; i<fromcount; i++)
1227 if (fromlist[i] != NONODEINST) fromlist[j++] = fromlist[i];
1228 fromcount = j;
1229 j = 0;
1230 for(i=0; i<tocount; i++)
1231 if (tolist[i]->temp1 == 0) tolist[j++] = tolist[i];
1232 tocount = j;
1233 if (fromcount != tocount)
1234 {
1235 ttyputerr(_("Error: after name match, there are %ld instances of %s in source and %ld in destination"),
1236 fromcount, describenodeproto(ni->proto), tocount);
1237 return;
1238 }
1239
1240 /* sort the rest by position and force matches based on that */
1241 if (fromcount == 0) continue;
1242 esort(fromlist, fromcount, sizeof (NODEINST *), ro_sortinstspatially);
1243 esort(tolist, tocount, sizeof (NODEINST *), ro_sortinstspatially);
1244 for(i=0; i<tocount; i++)
1245 tolist[i]->temp1 = (INTBIG)fromlist[i];
1246
1247 /* free the arrays */
1248 efree((CHAR *)fromlist);
1249 efree((CHAR *)tolist);
1250 }
1251
1252 /* association made, now copy the topology */
1253 for(tni = tonp->firstnodeinst; tni != NONODEINST; tni = tni->nextnodeinst)
1254 {
1255 if (tni->temp1 == 0) continue;
1256 fni = (NODEINST *)tni->temp1;
1257
1258 /* look for another node that may match */
1259 for(otni = tonp->firstnodeinst; otni != NONODEINST; otni = otni->nextnodeinst)
1260 {
1261 if (tni == otni) continue;
1262 if (otni->temp1 == 0) continue;
1263 ofni = (NODEINST *)otni->temp1;
1264
1265 /* see if they share a connection in the original */
1266 ofpi = NOPORTARCINST;
1267 for(fpi = fni->firstportarcinst; fpi != NOPORTARCINST; fpi = fpi->nextportarcinst)
1268 {
1269 ai = fpi->conarcinst;
1270 for(ofpi = ofni->firstportarcinst; ofpi != NOPORTARCINST; ofpi = ofpi->nextportarcinst)
1271 {
1272 oai = ofpi->conarcinst;
1273 if (oai->network == ai->network) break;
1274 }
1275 if (ofpi != NOPORTARCINST) break;
1276 }
1277 if (fpi == NOPORTARCINST) continue;
1278
1279 /* this connection should be repeated in the other cell */
1280 for(tpp = tni->proto->firstportproto; tpp != NOPORTPROTO; tpp = tpp->nextportproto)
1281 if (namesame(tpp->protoname, fpi->proto->protoname) == 0) break;
1282 if (tpp == NOPORTPROTO) continue;
1283 for(otpp = tni->proto->firstportproto; otpp != NOPORTPROTO; otpp = otpp->nextportproto)
1284 if (namesame(otpp->protoname, ofpi->proto->protoname) == 0) break;
1285 if (otpp == NOPORTPROTO) continue;
1286
1287 /* make the connection from "tni", port "tpp" to "otni" port "otpp" */
1288 if (ro_makeunroutedconnection(tni, tpp, otni, otpp)) return;
1289 }
1290 }
1291
1292 /* add in any exported but unconnected pins */
1293 for(tni = tonp->firstnodeinst; tni != NONODEINST; tni = tni->nextnodeinst)
1294 {
1295 if (tni->temp1 != 0) continue;
1296 if (tni->proto->primindex == 0) continue;
1297 if (tni->firstportexpinst == NOPORTEXPINST) continue;
1298 fun = nodefunction(tni);
1299 if (fun != NPPIN && fun != NPCONTACT) continue;
1300
1301 /* find that export in the source cell */
1302 tpp = tni->proto->firstportproto;
1303 matchname = tni->firstportexpinst->exportproto->protoname;
1304 net = NONETWORK;
1305 for(fpp = ro_copiedtopocell->firstportproto; fpp != NOPORTPROTO; fpp = fpp->nextportproto)
1306 {
1307 net = fpp->network;
1308 if (fpp->network->buswidth > 1)
1309 {
1310 for(i=0; i<fpp->network->buswidth; i++)
1311 {
1312 net = fpp->network->networklist[i];
1313 if (net->namecount <= 0) continue;
1314 if (namesame(networkname(net, 0), matchname) == 0) break;
1315 }
1316 if (i < fpp->network->buswidth) break;
1317 } else
1318 {
1319 if (namesame(fpp->protoname, matchname) == 0) break;
1320 }
1321 }
1322 if (fpp == NOPORTPROTO) continue;
1323
1324 /* check to see if this is connected elsewhere in the "to" cell */
1325 ofpi = NOPORTARCINST;
1326 for(otni = tonp->firstnodeinst; otni != NONODEINST; otni = otni->nextnodeinst)
1327 {
1328 if (otni->temp1 == 0) continue;
1329 ofni = (NODEINST *)otni->temp1;
1330
1331 /* see if they share a connection in the original */
1332 for(ofpi = ofni->firstportarcinst; ofpi != NOPORTARCINST; ofpi = ofpi->nextportarcinst)
1333 {
1334 ai = ofpi->conarcinst;
1335 if (ai->network == net) break;
1336 }
1337 if (ofpi != NOPORTARCINST) break;
1338 }
1339 if (otni != NONODEINST)
1340 {
1341 /* find the proper port in this cell */
1342 for(otpp = otni->proto->firstportproto; otpp != NOPORTPROTO; otpp = otpp->nextportproto)
1343 if (namesame(otpp->protoname, ofpi->proto->protoname) == 0) break;
1344 if (otpp == NOPORTPROTO) continue;
1345
1346 /* make the connection from "tni", port "tpp" to "otni" port "otpp" */
1347 if (ro_makeunroutedconnection(tni, tpp, otni, otpp)) return;
1348 }
1349 }
1350 }
1351
1352 /*
1353 * Helper routine to run an unrouted wire between node "fni", port "fpp" and node "tni", port
1354 * "tpp". If the connection is already there, the routine doesn't make another.
1355 * Returns true on error.
1356 */
ro_makeunroutedconnection(NODEINST * fni,PORTPROTO * fpp,NODEINST * tni,PORTPROTO * tpp)1357 BOOLEAN ro_makeunroutedconnection(NODEINST *fni, PORTPROTO *fpp, NODEINST *tni, PORTPROTO *tpp)
1358 {
1359 REGISTER PORTARCINST *fpi, *tpi;
1360 REGISTER ARCINST *fai, *tai, *ai;
1361 INTBIG fx, fy, tx, ty;
1362 REGISTER INTBIG wid, bits;
1363 REGISTER NODEPROTO *np;
1364
1365 /* see if they are already connected */
1366 for(fpi = fni->firstportarcinst; fpi != NOPORTARCINST; fpi = fpi->nextportarcinst)
1367 if (fpi->proto == fpp) break;
1368 for(tpi = tni->firstportarcinst; tpi != NOPORTARCINST; tpi = tpi->nextportarcinst)
1369 if (tpi->proto == tpp) break;
1370 if (fpi != NOPORTARCINST && tpi != NOPORTARCINST)
1371 {
1372 fai = fpi->conarcinst;
1373 tai = tpi->conarcinst;
1374 if (fai->network == tai->network) return(FALSE);
1375 }
1376
1377 /* make the connection from "tni", port "tpp" to "otni" port "otpp" */
1378 portposition(fni, fpp, &fx, &fy);
1379 portposition(tni, tpp, &tx, &ty);
1380 bits = us_makearcuserbits(gen_unroutedarc);
1381 wid = defaultarcwidth(gen_unroutedarc);
1382 np = fni->parent;
1383 ai = newarcinst(gen_unroutedarc, wid, bits, fni, fpp, fx, fy, tni, tpp, tx, ty, np);
1384 if (ai == NOARCINST) return(TRUE);
1385 endobjectchange((INTBIG)ai, VARCINST);
1386 return(FALSE);
1387 }
1388
1389 /*
1390 * Helper routine for sorting instances spatially
1391 */
ro_sortinstspatially(const void * e1,const void * e2)1392 int ro_sortinstspatially(const void *e1, const void *e2)
1393 {
1394 REGISTER NODEINST *n1, *n2;
1395 REGISTER INTBIG x1, y1, x2, y2;
1396
1397 n1 = *((NODEINST **)e1);
1398 n2 = *((NODEINST **)e2);
1399 x1 = (n1->lowx + n1->highx) / 2;
1400 y1 = (n1->lowy + n1->highy) / 2;
1401 x2 = (n2->lowx + n2->highx) / 2;
1402 y2 = (n2->lowy + n2->highy) / 2;
1403 if (y1 == y2) return(x1 - x2);
1404 return(y1 - y2);
1405 }
1406
1407 /****************************** ROUTING OPTIONS DIALOG ******************************/
1408
1409 /* Routing Options */
1410 static DIALOGITEM ro_optionsdialogitems[] =
1411 {
1412 /* 1 */ {0, {264,264,288,328}, BUTTON, N_("OK")},
1413 /* 2 */ {0, {264,12,288,76}, BUTTON, N_("Cancel")},
1414 /* 3 */ {0, {32,88,48,272}, POPUP, x_("")},
1415 /* 4 */ {0, {32,8,48,88}, MESSAGE, N_("Currently:")},
1416 /* 5 */ {0, {8,8,24,220}, MESSAGE, N_("Arc to use in stitching routers:")},
1417 /* 6 */ {0, {68,8,84,268}, CHECK, N_("Mimic stitching can unstitch")},
1418 /* 7 */ {0, {116,24,132,348}, CHECK, N_("Ports must match")},
1419 /* 8 */ {0, {236,8,252,268}, CHECK, N_("Mimic stitching runs interactively")},
1420 /* 9 */ {0, {92,8,108,268}, MESSAGE, N_("Mimic stitching restrictions:")},
1421 /* 10 */ {0, {188,24,204,348}, CHECK, N_("Node types must match")},
1422 /* 11 */ {0, {164,24,180,348}, CHECK, N_("Nodes sizes must match")},
1423 /* 12 */ {0, {140,24,156,348}, CHECK, N_("Number of existing arcs must match")},
1424 /* 13 */ {0, {212,24,228,348}, CHECK, N_("Cannot have other arcs in the same direction")}
1425 };
1426 static DIALOG ro_optionsdialog = {{50,75,347,433}, N_("Routing Options"), 0, 13, ro_optionsdialogitems, 0, 0};
1427
1428 /* special items for the "Routing Options" dialog: */
1429 #define DROO_ARCLIST 3 /* Arc list (popup) */
1430 #define DROO_MUNSTITCH 6 /* Mimic can unstitch (check) */
1431 #define DROO_MPORTSPECIFIC 7 /* Mimic port-specific (check) */
1432 #define DROO_MINTERACTIVE 8 /* Mimic is interactive (check) */
1433 #define DROO_MNODEPSECIFIC 10 /* Mimic node-specific (check) */
1434 #define DROO_MNODESIZESPEC 11 /* Mimic node-size-specific (check) */
1435 #define DROO_MARCCOUNTSPEC 12 /* Mimic arc-count-specific (check) */
1436 #define DROO_MOTHARCDIRSPEC 13 /* Mimic other-arc-in-this-direction-specific (check) */
1437
ro_optionsdlog(void)1438 void ro_optionsdlog(void)
1439 {
1440 INTBIG itemHit, numarcnames, initialindex, i, options, oldoptions;
1441 REGISTER VARIABLE *var;
1442 REGISTER ARCPROTO *ap, **arcs, *oldap;
1443 CHAR **arcnames, *paramstart[3];
1444 REGISTER void *dia;
1445
1446 /* gather list of arcs */
1447 var = getvalkey((INTBIG)ro_tool, VTOOL, VARCPROTO, ro_preferedkey);
1448 if (var == NOVARIABLE) oldap = NOARCPROTO; else
1449 oldap = (ARCPROTO *)var->addr;
1450 numarcnames = 0;
1451 for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1452 numarcnames++;
1453 arcs = (ARCPROTO **)emalloc((numarcnames+1) * (sizeof (ARCPROTO *)), el_tempcluster);
1454 arcnames = (CHAR **)emalloc((numarcnames+1) * (sizeof (CHAR *)), el_tempcluster);
1455 if (arcs == 0 || arcnames == 0) return;
1456 arcs[0] = NOARCPROTO;
1457 arcnames[0] = x_("DEFAULT ARC");
1458 numarcnames = 1;
1459 initialindex = 0;
1460 for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1461 {
1462 arcs[numarcnames] = ap;
1463 arcnames[numarcnames] = ap->protoname;
1464 if (ap == oldap) initialindex = numarcnames;
1465 numarcnames++;
1466 }
1467
1468 /* display the router arc dialog box */
1469 dia = DiaInitDialog(&ro_optionsdialog);
1470 if (dia == 0) return;
1471 DiaSetPopup(dia, DROO_ARCLIST, numarcnames, arcnames);
1472 DiaSetPopupEntry(dia, DROO_ARCLIST, initialindex);
1473 efree((CHAR *)arcnames);
1474 ap = arcs[initialindex];
1475 oldoptions = options = ro_getoptions();
1476 if ((options&MIMICUNROUTES) != 0) DiaSetControl(dia, DROO_MUNSTITCH, 1);
1477 if ((options&MIMICIGNOREPORTS) == 0) DiaSetControl(dia, DROO_MPORTSPECIFIC, 1);
1478 if ((options&MIMICONSIDERARCCOUNT) != 0) DiaSetControl(dia, DROO_MARCCOUNTSPEC, 1);
1479 if ((options&MIMICIGNORENODETYPE) == 0) DiaSetControl(dia, DROO_MNODEPSECIFIC, 1);
1480 if ((options&MIMICOTHARCTHISDIR) == 0) DiaSetControl(dia, DROO_MOTHARCDIRSPEC, 1);
1481 if ((options&MIMICINTERACTIVE) != 0) DiaSetControl(dia, DROO_MINTERACTIVE, 1);
1482
1483 /* loop until done */
1484 for(;;)
1485 {
1486 itemHit = DiaNextHit(dia);
1487 if (itemHit == OK || itemHit == CANCEL) break;
1488 if (itemHit == DROO_MUNSTITCH || itemHit == DROO_MPORTSPECIFIC ||
1489 itemHit == DROO_MINTERACTIVE || itemHit == DROO_MNODEPSECIFIC ||
1490 itemHit == DROO_MNODESIZESPEC || itemHit == DROO_MARCCOUNTSPEC ||
1491 itemHit == DROO_MOTHARCDIRSPEC)
1492 {
1493 DiaSetControl(dia, itemHit, 1 - DiaGetControl(dia, itemHit));
1494 continue;
1495 }
1496 if (itemHit == DROO_ARCLIST)
1497 {
1498 /* find this arc */
1499 i = DiaGetPopupEntry(dia, DROO_ARCLIST);
1500 ap = arcs[i];
1501 }
1502 }
1503
1504 if (itemHit != CANCEL)
1505 {
1506 if (DiaGetControl(dia, DROO_MUNSTITCH) != 0) options |= MIMICUNROUTES; else
1507 options &= ~MIMICUNROUTES;
1508 if (DiaGetControl(dia, DROO_MPORTSPECIFIC) == 0) options |= MIMICIGNOREPORTS; else
1509 options &= ~MIMICIGNOREPORTS;
1510 if (DiaGetControl(dia, DROO_MARCCOUNTSPEC) != 0) options |= MIMICONSIDERARCCOUNT; else
1511 options &= ~MIMICONSIDERARCCOUNT;
1512 if (DiaGetControl(dia, DROO_MNODEPSECIFIC) == 0) options |= MIMICIGNORENODETYPE; else
1513 options &= ~MIMICIGNORENODETYPE;
1514 if (DiaGetControl(dia, DROO_MOTHARCDIRSPEC) == 0) options |= MIMICOTHARCTHISDIR; else
1515 options &= ~MIMICOTHARCTHISDIR;
1516 if (DiaGetControl(dia, DROO_MNODESIZESPEC) == 0) options |= MIMICIGNORENODESIZE; else
1517 options &= ~MIMICIGNORENODESIZE;
1518 if (DiaGetControl(dia, DROO_MINTERACTIVE) != 0) options |= MIMICINTERACTIVE; else
1519 options &= ~MIMICINTERACTIVE;
1520 if (options != oldoptions)
1521 (void)setvalkey((INTBIG)ro_tool, VTOOL, ro_optionskey, options, VINTEGER);
1522 paramstart[0] = x_("use-arc");
1523 if (ap != oldap)
1524 {
1525 if (ap == NOARCPROTO) paramstart[1] = x_("*"); else
1526 paramstart[1] = ap->protoname;
1527 telltool(ro_tool, 2, paramstart);
1528 }
1529 }
1530 DiaDoneDialog(dia);
1531 efree((CHAR *)arcs);
1532 }
1533
1534 #endif /* ROUTTOOL - at top */
1535