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