1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: routriver.c
6  * Routines for the river-routing option of the routing tool
7  * Written by: Telle Whitney, Schlumberger Palo Alto Research
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 /*
33  *	River Route - takes two sets of parallel points (connectors, ports, etc) and routes wires
34  *        between them.  All wires are routed in a single layer with non intersecting lines.
35  *
36  *
37  *                       p1        p2         p3      p4
38  *                        |        |           |       |  /\ cell_off2
39  *                       _|        |           |   ____|  \/
40  *                      |          |           |  |
41  *                    __|    ______|           |  |
42  *                   |      |                  |  |
43  *                   |   ___|      ____________|  |
44  *                   |  |         | /\ pitch      |
45  *                 __|  |      ___| \/____________|
46  *  cell_off1 /\  |     |     |    <>|
47  *            \/  |     |     |      |
48  *               a1    a2    a3     a4
49  *
50  * Restrictions
51  *   (1)     The distance between the ports (p1..pn) and (a1..an) is >= pitch
52  *   (2)     The parameter "width" specifies the width of all wires
53  *           The parameter "space" specifies the distance between wires
54  *           pitch = 2*(width/2) + space = space + width
55  *
56  * Extension - allow routing to and from the two sides
57  *
58  *                        SIDE3
59  *       ________________________________________
60  *       |  route  |                  |  route  |
61  *     S |  right  |                  |  left   | S
62  *     I | (last)  |   normal right   | (last)  | I
63  *     D |_________|  and left route  |_________| D
64  *     E |  route  |     (middle)     |  route  | E
65  *     4 |  left   |                  |  right  | 2
66  *       | (first) |                  | (first) |
67  *       |_________|__________________|_________|
68  *                        SIDE1
69  */
70 
71 #include "config.h"
72 #if ROUTTOOL
73 
74 #include "global.h"
75 #include "rout.h"
76 #include "tecgen.h"
77 
78 #define ROUTEINX      1
79 #define ROUTEINY      2
80 #define ILLEGALROUTE -1
81 
82 #define BOTTOP        1					/* bottom to top  -- side 1 to side 3 */
83 #define FROMSIDE      2					/* side   to top  -- side 2 or side 4 to side 3 */
84 #define TOSIDE        3					/* bottom to side -- side 1 to side 3 or side 2 */
85 
86 /******** RPOINT ********/
87 
88 #define NOSIDE -1
89 #define SIDE1   1
90 #define SIDE2   2
91 #define SIDE3   3
92 #define SIDE4   4
93 
94 #define NULLRPOINT ((RPOINT *)0)
95 
96 typedef struct rivpoint
97 {
98 	INTBIG           side;				/* the side this point is on */
99 	INTBIG           x, y;				/* points coordinates */
100 	INTBIG           first, second;		/* nonrotated coordinates */
101 	struct rivpoint *next;				/* next one in the list */
102 } RPOINT;
103 
104 /******** RDESC ********/
105 
106 #define NULLRDESC ((RDESC *)0)
107 
108 typedef struct routedesc
109 {
110 	RPOINT           *from;
111 	RPOINT           *to;
112 	INTBIG            sortval;
113 	ARCINST          *unroutedwire1;
114 	ARCINST          *unroutedwire2;
115 	INTBIG            unroutedend1;
116 	INTBIG            unroutedend2;
117 	struct rpath     *path;
118 	struct routedesc *next;
119 } RDESC;
120 
121 /******** RPATH ********/
122 
123 #define NULLRPATH ((RPATH *)0)
124 
125 typedef struct rpath
126 {
127 	INTBIG           width;				/* the width of this path */
128 	ARCPROTO        *pathtype;			/* the paty type for this wire */
129 	INTBIG           routetype;			/* how the wire needs to be routed - as above */
130 	RPOINT          *pathdesc;			/* the path */
131 	RPOINT          *lastp;				/* the last point on the path */
132 	struct rpath    *next;
133 } RPATH;
134 
135 /******** TRANSFORM ********/
136 
137 #define NULLTRANSFORM ((TRANSFORM *)0)
138 
139 typedef struct itran
140 {
141 	INTBIG t11, t12;					/* graphics transformation */
142 	INTBIG t21, t22;
143 	INTBIG tx, ty;
144 } TRANSFORM;
145 
146 /******** RCOORD ********/
147 
148 #define NULLCOORD ((RCOORD *)0)
149 
150 typedef struct coord
151 {
152 	INTBIG        val;					/* the coordinate */
153 	INTBIG        total;				/* number of wires voting for this coordinate */
154 	struct coord *next;
155 } RCOORD;
156 
157 /******** VARIABLES ********/
158 
159 typedef struct
160 {
161 	NODEINST  *topcell;
162 	BOOLEAN    cellvalid;
163 } MOVECELL;
164 
165 static MOVECELL ro_rrmovecell;
166 
167 typedef struct
168 {
169 	TRANSFORM    *origmatrix, *invmatrix;
170 	RDESC        *rightp, *leftp;
171 	INTBIG        fromline;				/* the initial coordinate of the route */
172 	INTBIG        toline;				/* final coordinate of the route */
173 	INTBIG        startright;			/* where to start wires on the right */
174 	INTBIG        startleft;			/* where to start wires on the left */
175 	INTBIG        height;
176 	INTBIG        llx, lly, urx, ury;
177 	INTBIG        xx;					/*  ROUTEINX route in X direction,
178 											ROUTEINY route in Y direction */
179 	RCOORD       *xaxis, *yaxis;		/* linked list of possible routing coordinates */
180 } ROUTEINFO;
181 
182 static ROUTEINFO ro_rrinfo;
183 static BOOLEAN   ro_initialized = FALSE;
184 
185 static TRANSFORM ro_rrnorot     = { 1,  0,	/* X increasing, y2>y1                */
186 									0,  1,
187                                     0,  0};
188 static TRANSFORM ro_rrrot90     = { 0,  1,	/* Y decreasing, x2>x1                */
189 								   -1,  0,
190                                     0,  0};
191 static TRANSFORM ro_rrrot180    = {-1,  0,	/* X decreasing, y2<y1                */
192 									0, -1,
193                                     0,  0};
194 static TRANSFORM ro_rrrot270    = { 0, -1,	/* Y increasing, x2<x1                */
195 									1,  0,	/* or rot -90                         */
196 									0,  0};
197 static TRANSFORM ro_rrmirrorx   = {-1,  0,	/* X decreasing, y2>y1                */
198 								    0,  1,	/* mirror X coordinate, around Y axis */
199 								    0,  0};
200 static TRANSFORM ro_rrrot90mirx = { 0,  1,	/* Y increasing, x2>x1                */
201 									1,  0,	/* rot90 and mirror X                 */
202 									0,  0};
203 static TRANSFORM ro_rrmirrory   = { 1,  0,	/* X increasing, y2<y1                */
204 									0, -1,	/* mirror Y coordinate, around X axis */
205 									0,  0};
206 static TRANSFORM ro_rrmirxr90   = { 0, -1,	/* Y decreasing, x2<x1                */
207 								   -1,  0,	/* mirror X, rot90                    */
208 									0,  0};
209 											/*    original		inverse   */
210 static TRANSFORM ro_rrinverse   = { 1,  0,	/*   [ cos0  sin0] [ cos0  -sin0] */
211 									0,  1,	/*   [-sin0  cos0] [ sin0   cos0] */
212 									0,  0};	/*	tx,ty			  */
213 
214 static INTBIG ro_rrbx, ro_rrby, ro_rrex, ro_rrey;
215 
216 /* the parsing structure for interactive routing options */
217 static KEYWORD ro_riveropt[] =
218 {
219 	{x_("route"),      0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
220 	{x_("move-cell"),  0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
221 	{x_("abort"),      0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
222 	TERMKEY
223 };
224 static COMCOMP ro_riverp = {ro_riveropt, NOTOPLIST, NONEXTLIST, NOPARAMS,
225 	0, x_(" \t"), M_("River-routing action"), 0};
226 
227 /******** prototypes for local routines ********/
228 
229 static RPATH *ro_newrpath(INTBIG, ARCPROTO*, INTBIG);
230 static void ro_freerpath(RPATH*);
231 static RPOINT *ro_newrivpoint(RPATH*, INTBIG, INTBIG, RPOINT*);
232 static RPOINT *ro_newrvpoint(INTBIG, INTBIG, INTBIG);
233 static void ro_freerivpoint(RPOINT*);
234 static RCOORD *ro_newcoord(INTBIG);
235 static RDESC *ro_newroutedesc(INTBIG, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG, ARCINST*, INTBIG, ARCINST*, INTBIG, RDESC*);
236 static void ro_freeroutedesc(RDESC*);
237 static RDESC **ro_newrdarray(INTBIG);
238 static void ro_freerdarray(RDESC**);
239 static void ro_initialize(void);
240 static void ro_clipwire(RPOINT*, INTBIG, INTBIG);
241 static BOOLEAN ro_check_points(RDESC*, INTBIG, INTBIG);
242 static RDESC *ro_addright(RDESC*, RDESC*);
243 static RDESC *ro_addleft(RDESC*, RDESC*);
244 static void ro_structure_points(RDESC*);
245 static BOOLEAN ro_check_structured_points(RDESC*, RDESC*, INTBIG, INTBIG, INTBIG);
246 static RDESC *ro_reverse(RDESC*);
247 static void ro_cleanup(void);
248 static INTBIG ro_routepathtype(RPOINT*, RPOINT*);
249 static RPATH *ro_makeorigpath(INTBIG, ARCPROTO*, INTBIG, RPOINT*, RPOINT*);
250 static RPATH *ro_addpath(RPATH*, INTBIG, ARCPROTO*, RPOINT*, RPOINT*, INTBIG, INTBIG, INTBIG);
251 static RPATH *ro_makesideorigpath(INTBIG, ARCPROTO*, INTBIG, RPOINT*, RPOINT*);
252 static RPATH *ro_sideaddpath(RPATH*, INTBIG, ARCPROTO*, RPOINT*, RPOINT*, INTBIG, INTBIG, INTBIG);
253 static BOOLEAN ro_process_right(INTBIG, ARCPROTO*, RDESC*, INTBIG, INTBIG, INTBIG);
254 static BOOLEAN ro_process_left(INTBIG, ARCPROTO*, RDESC*, INTBIG, INTBIG, INTBIG);
255 static void ro_remap_points(RPOINT*, TRANSFORM*);
256 static INTBIG ro_remap_second(INTBIG, TRANSFORM*);
257 static INTBIG ro_height_coordinate(INTBIG);
258 static BOOLEAN ro_calculate_height_and_process(RDESC*, RDESC*, INTBIG, INTBIG, INTBIG, INTBIG*);
259 static void ro_calculate_bb(INTBIG*, INTBIG*, INTBIG*, INTBIG*, RDESC*, RDESC*);
260 static BOOLEAN ro_sorted_rivrot(ARCPROTO*, RDESC*, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG);
261 static RDESC *ro_quicksort(RDESC*);
262 static BOOLEAN ro_unsorted_rivrot(ARCPROTO*, RDESC*, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG);
263 static void ro_checkthecell(NODEINST*);
264 static void ro_pseudomake(RDESC*, NODEPROTO*);
265 static void ro_makepseudogeometry(NODEPROTO*);
266 static NODEINST *ro_thenode(RDESC*, NODEPROTO*, RPOINT*, NODEPROTO*);
267 static PORTPROTO *ro_theport(PORTPROTO*, RDESC*, RPOINT*);
268 static void ro_makegeometry(RDESC*, NODEPROTO*);
269 static void ro_clear_flags(NODEPROTO*);
270 static BOOLEAN ro_isunroutedpin(NODEINST*);
271 static BOOLEAN ro_is_interesting_arc(ARCINST*);
272 static void ro_set_flags(ARCINST*);
273 static void ro_mark_tobedeleted(ARCINST*);
274 static BOOLEAN ro_delnodeinst(NODEINST*);
275 static void ro_kill_wires(NODEPROTO*);
276 static void ro_makethegeometry(NODEPROTO*);
277 static RCOORD *ro_tallyvote(RCOORD*, INTBIG);
278 static void ro_vote(INTBIG, INTBIG, INTBIG, INTBIG);
279 static INTBIG ro_simplefigxx(RCOORD*, RCOORD*, RCOORD*, RCOORD*, INTBIG, RCOORD**, RCOORD**);
280 static RCOORD *ro_largest(RCOORD*);
281 static RCOORD *ro_next_largest(RCOORD*, RCOORD*);
282 static void ro_figureoutrails(INTBIG);
283 static INTBIG ro_point_val(RPOINT*, INTBIG);
284 static void ro_swap_points(RDESC*);
285 static void ro_set_wires_to_rails(RDESC*);
286 static RDESC *ro_addwire(RDESC*, ARCINST*, BOOLEAN*);
287 static RDESC *ro_findhighlightedwires(NODEPROTO*, INTBIG*);
288 static RDESC *ro_findnormalwires(NODEPROTO*, INTBIG*);
289 static BOOLEAN ro_findwires(NODEPROTO*);
290 static BOOLEAN ro_move_instance(void);
291 static BOOLEAN ro_query_user(void);
292 static void ro_sumup(PORTARCINST*);
293 static int ro_rivpointascending(const void*, const void*);
294 
295 /******************** MEMORY MANAGEMENT ROUTINES ****************************/
296 
ro_newrpath(INTBIG width,ARCPROTO * ptype,INTBIG routetype)297 RPATH *ro_newrpath(INTBIG width, ARCPROTO *ptype, INTBIG routetype)
298 {
299 	RPATH *rp;
300 
301 	rp = (RPATH *)emalloc(sizeof(RPATH), ro_tool->cluster);
302 	if (rp == 0) return(0);
303 	rp->width = width;   rp->pathtype = ptype;   rp->routetype = routetype;
304 	rp->pathdesc = NULLRPOINT;   rp->lastp = NULLRPOINT;
305 	rp->next = NULLRPATH;
306 	return(rp);
307 }
308 
ro_freerpath(RPATH * rp)309 void ro_freerpath(RPATH *rp)
310 {
311 	RPOINT *rvp, *rvpnext;
312 
313 	for(rvp = rp->pathdesc, rvpnext = (rvp ?rvp->next:NULLRPOINT);
314 		rvp; rvp = rvpnext, rvpnext = (rvpnext?rvpnext->next:NULLRPOINT))
315 			ro_freerivpoint(rvp);
316 	efree((CHAR *)rp);
317 }
318 
ro_newrivpoint(RPATH * rp,INTBIG first,INTBIG sec,RPOINT * next)319 RPOINT *ro_newrivpoint(RPATH *rp, INTBIG first, INTBIG sec, RPOINT *next)
320 {
321 	RPOINT *rvp;
322 
323 	rvp = (RPOINT *)emalloc(sizeof(RPOINT), ro_tool->cluster);
324 	if (rvp == 0) return(0);
325 	rvp->first = first;   rvp->second = sec;   rvp->x = 0;   rvp->y = 0;
326 	rvp->side = NOSIDE;
327 	rvp->next = next;
328 	if (rvp->next != 0) return(rvp);
329 	rp->lastp = rvp;
330 	return(rvp);
331 }
332 
333 /* called to set up the route */
ro_newrvpoint(INTBIG x,INTBIG y,INTBIG side)334 RPOINT *ro_newrvpoint(INTBIG x, INTBIG y, INTBIG side)
335 {
336 	RPOINT *rvp;
337 
338 	rvp = (RPOINT *)emalloc(sizeof(RPOINT), ro_tool->cluster);
339 	if (rvp == 0) return(0);
340 	rvp->x = x;   rvp->y = y;   rvp->first = 0;   rvp->second = 0;
341 	rvp->side = side;
342 	rvp->next = NULLRPOINT;
343 	return(rvp);
344 }
345 
ro_freerivpoint(RPOINT * rvp)346 void ro_freerivpoint(RPOINT *rvp)
347 {
348 	efree((CHAR *)rvp);
349 }
350 
ro_newcoord(INTBIG c)351 RCOORD *ro_newcoord(INTBIG c)
352 {
353 	RCOORD *cc;
354 
355 	cc = (RCOORD *)emalloc(sizeof(RCOORD), ro_tool->cluster);
356 	if (cc == 0) return(0);
357 	cc->val = c;   cc->total = 0;
358 	cc->next = NULLCOORD;
359 	return(cc);
360 }
361 
ro_newroutedesc(INTBIG fx,INTBIG fy,INTBIG fside,INTBIG sx,INTBIG sy,INTBIG sside,ARCINST * ai1,INTBIG ae1,ARCINST * ai2,INTBIG ae2,RDESC * next)362 RDESC *ro_newroutedesc(INTBIG fx, INTBIG fy, INTBIG fside, INTBIG sx, INTBIG sy,
363 	INTBIG sside, ARCINST *ai1, INTBIG ae1, ARCINST *ai2, INTBIG ae2, RDESC *next)
364 {
365 	RDESC *rd;
366 
367 	rd = (RDESC *)emalloc(sizeof(RDESC), ro_tool->cluster);
368 	if (rd == 0) return(0);
369 	rd->from = ro_newrvpoint(fx, fy, fside);
370 	if (rd->from == 0) return(0);
371 	rd->to = ro_newrvpoint(sx, sy, sside);
372 	if (rd->to == 0) return(0);
373 	rd->sortval = -MAXINTBIG;
374 	rd->unroutedwire1 = ai1;   rd->unroutedend1 = ae1;
375 	rd->unroutedwire2 = ai2;   rd->unroutedend2 = ae2;
376 	rd->path = NULLRPATH;
377 	rd->next = next;
378 	return(rd);
379 }
380 
ro_freeroutedesc(RDESC * rd)381 void ro_freeroutedesc(RDESC *rd)
382 {
383 	ro_freerivpoint(rd->from);   ro_freerivpoint(rd->to);
384 	efree((CHAR *)rd);
385 }
386 
ro_newrdarray(INTBIG size)387 RDESC **ro_newrdarray(INTBIG size)
388 {
389 	RDESC **r;
390 	INTBIG i;
391 
392 	r = (RDESC **)emalloc(((size+1)*sizeof(RDESC *)), ro_tool->cluster);
393 	if (r == 0) return(0);
394 	for(i=0; i<=size; i++) r[i] = NULLRDESC;
395 	return(r);
396 }
397 
ro_freerdarray(RDESC ** r)398 void ro_freerdarray(RDESC **r)
399 {
400 	efree((CHAR *)r);
401 }
402 
ro_initialize(void)403 void ro_initialize(void)
404 {
405 	RCOORD *c;
406 
407 	ro_rrinfo.rightp = NULLRDESC;   ro_rrinfo.leftp = NULLRDESC;
408 	ro_rrinfo.origmatrix = NULLTRANSFORM;
409 	ro_rrinfo.invmatrix = NULLTRANSFORM;
410 	ro_rrinfo.fromline = ro_rrinfo.toline = -MAXINTBIG;
411 	ro_rrinfo.startright = -MAXINTBIG;   ro_rrinfo.startleft = -MAXINTBIG;
412 	ro_rrinfo.height = -MAXINTBIG;   ro_rrinfo.xx = ILLEGALROUTE;
413 
414 	if (!ro_initialized)
415 	{
416 		ro_initialized = TRUE;
417 		ro_rrinfo.xaxis = 0;
418 		ro_rrinfo.yaxis = 0;
419 	}
420 	for(c = ro_rrinfo.xaxis; c; c = c->next) c->total = -1;
421 	for(c = ro_rrinfo.yaxis; c; c = c->next) c->total = -1;
422 	ro_rrmovecell.topcell = NONODEINST;   ro_rrmovecell.cellvalid = TRUE;
423 }
424 
ro_freerivermemory(void)425 void ro_freerivermemory(void)
426 {
427 	RCOORD *c;
428 
429 	while (ro_rrinfo.xaxis != 0)
430 	{
431 		c = ro_rrinfo.xaxis;
432 		ro_rrinfo.xaxis = ro_rrinfo.xaxis->next;
433 		efree((CHAR *)c);
434 	}
435 	while (ro_rrinfo.yaxis != 0)
436 	{
437 		c = ro_rrinfo.yaxis;
438 		ro_rrinfo.yaxis = ro_rrinfo.yaxis->next;
439 		efree((CHAR *)c);
440 	}
441 }
442 
443 /************************************************************************/
444 /*	Point validation - ensure that the paths are valid		*/
445 /*		havoc occurs when the data is not what the program	*/
446 /*		expects.  It does something but wires get shorted	*/
447 /*		together and terminals don't connect			*/
448 /************************************************************************/
449 
ro_clipwire(RPOINT * p,INTBIG b1,INTBIG b2)450 void ro_clipwire(RPOINT *p, INTBIG b1, INTBIG b2)
451 {
452 	INTBIG diff1, diff2;
453 
454 	diff1 = abs(b1 - p->first);   diff2 = abs(b2 - p->first);
455 	if (diff1 < diff2)
456 	{
457 		p->first = b1;   p->side = SIDE4;
458 	} else
459 	{
460 		p->first = b2;   p->side = SIDE2;
461 	}
462 }
463 
ro_check_points(RDESC * listp,INTBIG width,INTBIG space)464 BOOLEAN ro_check_points(RDESC *listp, INTBIG width, INTBIG space)
465 {
466 	RDESC *llist, *listlast;
467 	RPOINT *lastfrom, *lastto;
468 	TRANSFORM *tmatrix;
469 	INTBIG val1, val2;
470 	INTBIG diff1, diff2;
471 	INTBIG bound1, bound2;
472 	INTBIG temp;
473 
474 	if (listp == NULLRDESC)
475 	{
476 		/* need at least one point */
477 		ttyputerr(_("River router: Not enought points"));
478 		return(FALSE);
479 	}
480 
481 	listlast = NULLRDESC;
482 	for(llist = listp; llist; llist=llist->next) listlast = llist;
483 	if (!listlast->from || !listlast->to)
484 	{
485 		ttyputerr(_("River router: Not the same number of points"));
486 		return(FALSE);	/* not the same number of points */
487 	}
488 
489 	/*  decide route orientation */
490 	if (ro_rrinfo.xx == ROUTEINX)
491 	{
492 		/* route in x direction */
493 		if (listp->to->x >= listp->from->x)
494 		{						/* x2>x1 */
495 			if (listlast->from->y >= listp->from->y)
496 				tmatrix = &ro_rrrot90mirx;			/* Y increasing */
497 					else tmatrix = &ro_rrrot90;		/* Y decreasing */
498 		} else
499 		{						/* x2<x1 */
500 			if (listlast->from->y >= listp->from->y)
501 				tmatrix = &ro_rrrot270;				/* Y increasing */
502 					else tmatrix = &ro_rrmirxr90;	/* Y decreasing */
503 		}
504 		val1 = ro_rrinfo.fromline = ro_rrinfo.fromline*tmatrix->t12;
505 		val2 = ro_rrinfo.toline = ro_rrinfo.toline*tmatrix->t12;
506 	} else if (ro_rrinfo.xx == ROUTEINY)
507 	{
508 		/* route in y direction */
509 		if (listp->to->y >= listp->from->y)
510 		{						/* y2>y1 */
511 			if (listlast->from->x >= listp->from->x)
512 				tmatrix = &ro_rrnorot;				/* X increasing */
513 					else tmatrix = &ro_rrmirrorx;	/* X decreasing */
514 		} else
515 		{						/* y2<y1 */
516 			if (listlast->from->x >= listp->from->x)
517 				tmatrix = &ro_rrmirrory;				/* X increasing */
518 					else tmatrix = &ro_rrrot180;		/* X decreasing */
519 		}
520 		val1 = ro_rrinfo.fromline = ro_rrinfo.fromline*tmatrix->t22;
521 		val2 = ro_rrinfo.toline = ro_rrinfo.toline*tmatrix->t22;
522 	} else
523 	{
524 		ttyputerr(_("River router: Not between two parallel lines"));
525 		return(FALSE);		/* not on manhattan parallel lines */
526 	}
527 
528 	/* check ordering of coordinates */
529 	for (llist = listp; llist != NULLRDESC; llist = llist->next)
530 	{
531 		/* do not check the last point */
532 		if (llist->next == NULLRDESC) continue;
533 
534 		/* make sure there are no crossings */
535 		if (ro_rrinfo.xx == ROUTEINY)
536 		{
537 			if ((llist->from->x > llist->next->from->x && llist->to->x < llist->next->to->x) ||
538 				(llist->from->x < llist->next->from->x && llist->to->x > llist->next->to->x))
539 			{
540 				ttyputerr(_("River router: Connections may not cross"));
541 				return(FALSE);
542 			}
543 		} else
544 		{
545 			if ((llist->from->y > llist->next->from->y && llist->to->y < llist->next->to->y) ||
546 				(llist->from->y < llist->next->from->y && llist->to->y > llist->next->to->y))
547 			{
548 				ttyputerr(_("River router: Connections may not cross"));
549 				return(FALSE);
550 			}
551 		}
552 	}
553 
554 	bound1 = ro_rrinfo.llx*tmatrix->t11 + ro_rrinfo.lly*tmatrix->t21;
555 	bound2 = ro_rrinfo.urx*tmatrix->t11 + ro_rrinfo.ury*tmatrix->t21;
556 	if (bound2 < bound1)
557 	{
558 		temp = bound2;   bound2 = bound1;   bound1 = temp;
559 	}
560 	lastfrom = NULLRPOINT;   lastto = NULLRPOINT;
561 
562 	/* transform points and clip to boundary */
563 	for(llist = listp; llist; llist = llist->next)
564 	{
565 		llist->from->first = (llist->from->x*tmatrix->t11) + (llist->from->y*tmatrix->t21);
566 		llist->from->second = (llist->from->x*tmatrix->t12) + (llist->from->y*tmatrix->t22);
567 		llist->to->first = (llist->to->x*tmatrix->t11) + (llist->to->y*tmatrix->t21);
568 		llist->to->second = (llist->to->x*tmatrix->t12) + (llist->to->y*tmatrix->t22);
569 		if (llist->from->second != val1) ro_clipwire(llist->from, bound1, bound2);
570 		if (llist->to->second != val2)  ro_clipwire(llist->to, bound1, bound2);
571 
572 		if (lastfrom && llist->from->side == SIDE1)
573 		{
574 			diff1 = abs(lastfrom->first - llist->from->first);
575 			if (diff1 < width+space)
576 			{
577 				ttyputerr(_("River router: Ports not design rule distance apart"));
578 				return(FALSE);
579 			}
580 		}
581 		if (lastto && llist->to->side == SIDE3)
582 		{
583 			diff2 = abs(lastto->first - llist->to->first);
584 			if (diff2 < width+space)
585 			{
586 				ttyputerr(_("River router: Ports not design rule distance apart"));
587 				return(FALSE);
588 			}
589 		}		/* not far enough apart */
590 		lastfrom = ((llist->from->side == SIDE1) ? llist->from : NULLRPOINT);
591 		lastto = ((llist->to->side == SIDE3) ? llist->to : NULLRPOINT);
592 	}
593 
594 	/* matrix to take route back to original coordinate system */
595 	ro_rrinverse.t11 = tmatrix->t11;   ro_rrinverse.t12 = tmatrix->t21;
596 	ro_rrinverse.t21 = tmatrix->t12;   ro_rrinverse.t22 = tmatrix->t22;
597 	ro_rrinverse.tx = listp->from->first; ro_rrinverse.ty = listp->from->second;
598 								/* right now these last terms are not used */
599 	ro_rrinfo.origmatrix = tmatrix;   ro_rrinfo.invmatrix = &ro_rrinverse;
600 	ro_rrinfo.fromline = val1;   ro_rrinfo.toline = val2;
601 	return(TRUE);
602 }
603 
ro_addright(RDESC * r,RDESC * npb)604 RDESC *ro_addright(RDESC *r, RDESC *npb)
605 {
606 	if (r) r->next = npb;
607 		else ro_rrinfo.rightp = npb;
608 	return(npb);
609 }
610 
ro_addleft(RDESC * l,RDESC * npb)611 RDESC *ro_addleft(RDESC *l, RDESC *npb)
612 {
613 	if (l) l->next = npb;
614 		else ro_rrinfo.leftp = npb;
615 	return(npb);
616 }
617 
618 
ro_structure_points(RDESC * listr)619 void ro_structure_points(RDESC *listr)
620 {
621 	RDESC *rd, *llist, *rlist;
622 
623 	rlist = NULLRDESC; llist = NULLRDESC;
624 	for(rd = listr; rd; rd = rd->next)
625 	{
626 		if (rd->to->first >= rd->from->first) rlist = ro_addright(rlist, rd);
627 			else llist = ro_addleft(llist, rd);
628 	}
629 	if (rlist) rlist->next = NULLRDESC;
630 	if (llist) llist->next = NULLRDESC;
631 }
632 
ro_check_structured_points(RDESC * right,RDESC * left,INTBIG co1,INTBIG width,INTBIG space)633 BOOLEAN ro_check_structured_points(RDESC *right, RDESC *left, INTBIG co1, INTBIG width, INTBIG space)
634 {
635 	RDESC *r, *l;
636 	INTBIG fromside1, toside2, fromside2, toside3, toside4;
637 	INTBIG botoffs2, botoffs4;
638 
639 	fromside1 = FALSE;   toside2 = FALSE;   botoffs2 = 0;
640 
641 	/* ensure ordering is correct */
642 	for(r = right; r; r = r->next)
643 	{
644 		switch (r->from->side)
645 		{
646 			case SIDE1:
647 				fromside1 = TRUE;
648 				break;
649 			default:
650 			case SIDE2:
651 			case SIDE3:
652 				ttyputerr(_("River router: Improper sides for bottom right ports"));
653 				return(FALSE);
654 			case SIDE4:
655 				if (fromside1)
656 				{
657 					ttyputerr(_("River router: Improper ordering of bottom right ports"));
658 					return(FALSE);
659 				}
660 				break;
661 		}
662 		switch (r->to->side)
663 		{
664 			case SIDE1:
665 			case SIDE4:
666 			default:
667 				ttyputerr(_("River router: Improper sides for top right ports"));
668 				return(FALSE);
669 			case SIDE2:
670 				if (!toside2) botoffs2 = ro_rrinfo.fromline+co1+(width/2);
671 					else botoffs2 += space+width;
672 				toside2 = TRUE;
673 				break;
674 			case SIDE3:
675 				if (toside2)
676 				{
677 					ttyputerr(_("River router: Improper ordering of top right ports"));
678 					return(FALSE);
679 				}
680 				break;
681 		}
682 	}
683 
684 	fromside2 = FALSE;   toside3 = FALSE;   toside4 = FALSE;   botoffs4 = 0;
685 	for(l = left; l; l = l->next)
686 	{
687 		switch (l->from->side)
688 		{
689 			case SIDE1:
690 				if (fromside2)
691 				{
692 					ttyputerr(_("River router: Improper Ordering of Bottom Left Ports"));
693 					return(FALSE);
694 				}
695 				break;
696 			case SIDE2:
697 				fromside2 = TRUE;
698 				break;
699 			case SIDE3:
700 			case SIDE4:
701 			default:
702 				ttyputerr(_("River router: Improper sides for Bottom Left Ports"));
703 				return(FALSE);
704 		}
705 		switch (l->to->side)
706 		{
707 			case SIDE1:
708 			case SIDE2:
709 			default:
710 				ttyputerr(_("River router: Improper sides for Top Left Ports"));
711 				return(FALSE);
712 			case SIDE3:
713 				toside3 = TRUE;
714 				break;
715 			case SIDE4:
716 				if (!toside3)
717 				{
718 					if (!toside4) botoffs4 = ro_rrinfo.fromline+co1+(width/2);
719 						else botoffs4 += space+width;
720 				} else
721 				{
722 					ttyputerr(_("River router: Improper Ordering of Top Left Ports"));
723 					return(FALSE);
724 				}
725 				toside4 = TRUE;
726 				break;
727 		}
728 	}
729 	if (botoffs2 == 0) ro_rrinfo.startright = ro_rrinfo.fromline+co1+(width/2);
730 		else	       ro_rrinfo.startright = botoffs2+space+width;
731 
732 	if (botoffs4 == 0) ro_rrinfo.startleft = ro_rrinfo.fromline+co1+(width/2);
733 		else	       ro_rrinfo.startleft = botoffs4+space+width;
734 	return(TRUE);
735 }
736 
ro_reverse(RDESC * p)737 RDESC *ro_reverse(RDESC *p)
738 {
739 	RDESC *q, *r;
740 
741 	if (!p) return(NULLRDESC);
742 	if (!p->next) return(p);
743 
744 	q = p;   p = p->next;   q->next = NULLRDESC;
745 	while (p) { r = p->next;   p->next = q;   q = p;   p = r;}
746 	return(q);
747 }
748 
ro_cleanup(void)749 void ro_cleanup(void)
750 {
751 	RDESC *rd, *rdnext;
752 
753 	for(rd = ro_rrinfo.rightp, rdnext = (rd ?rd->next:NULLRDESC);
754 		rd; rd = rdnext, rdnext = (rdnext?rdnext->next:NULLRDESC))
755 	{
756 		if (rd->path) ro_freerpath(rd->path);
757 		ro_freeroutedesc(rd);
758 	}
759 
760 	for(rd = ro_rrinfo.leftp, rdnext = (rd ?rd->next:NULLRDESC);
761 		rd; rd = rdnext, rdnext = (rdnext?rdnext->next:NULLRDESC))
762 	{
763 		if (rd->path) ro_freerpath(rd->path);
764 		ro_freeroutedesc(rd);
765 	}
766 }
767 
768 /*********************** ACTUALLY DO THE ROUTE *******************************/
769 
770 /*
771  * the type of route for this wire: side to top, bottom to side, bottom to top
772  */
ro_routepathtype(RPOINT * b,RPOINT * t)773 INTBIG ro_routepathtype(RPOINT *b, RPOINT *t)
774 {
775 	if (b && t)
776 	{
777 		if (b->side != SIDE1) return(FROMSIDE);
778 		if (b->side != SIDE3) return(TOSIDE);
779 	}
780 	return(BOTTOP);
781 }
782 
ro_makeorigpath(INTBIG width,ARCPROTO * ptype,INTBIG co1,RPOINT * b,RPOINT * t)783 RPATH *ro_makeorigpath(INTBIG width, ARCPROTO *ptype, INTBIG co1, RPOINT *b, RPOINT *t)
784 {
785 	RPATH *rp;
786 	RPOINT *i1, *i2;
787 
788 	rp = ro_newrpath(width, ptype, ro_routepathtype(b, t));
789 	if (rp == 0) return(0);
790 
791 	i1 = ro_newrivpoint(rp, t->first, b->second+(width/2)+co1, NULLRPOINT);
792 	if (i1 == 0) return(0);
793 	i2 = ro_newrivpoint(rp, b->first, b->second+(width/2)+co1, i1);
794 	if (i2 == 0) return(0);
795 	rp->pathdesc = ro_newrivpoint(rp, b->first, b->second, i2);
796 	if (rp->pathdesc == 0) return(0);
797 	rp->lastp->side = t->side;
798 	return(rp);
799 }
800 
ro_addpath(RPATH * path,INTBIG width,ARCPROTO * ptype,RPOINT * b,RPOINT * t,INTBIG space,INTBIG co1,INTBIG dir)801 RPATH *ro_addpath(RPATH *path, INTBIG width, ARCPROTO *ptype, RPOINT *b, RPOINT *t,
802 	INTBIG space, INTBIG co1,INTBIG dir)
803 {
804 	RPATH *rp;
805 	INTBIG newfirst, minfirst, maxfirst;
806 	RPOINT *lp, *lastp, *i1;
807 
808 	rp = ro_newrpath(width, ptype, ro_routepathtype(b, t));
809 	if (rp == 0) return(0);
810 	i1 = ro_newrivpoint(rp, b->first, b->second+(rp->width/2)+co1, NULLRPOINT);
811 	if (i1 == 0) return(0);
812 	rp->pathdesc = ro_newrivpoint(rp, b->first, b->second, i1);
813 	if (rp->pathdesc == 0) return(0);
814 	minfirst = mini(b->first, t->first);
815 	maxfirst = maxi(b->first, t->first);
816 	lp = path->pathdesc;
817 
818 	lastp = rp->lastp;
819 
820 	newfirst = lp->first+dir*(space+rp->width);
821 	while (lp && minfirst <= newfirst && newfirst <= maxfirst)
822 	{
823 		/* if first point then inconsistent second(y) offset */
824 		if (lp == path->pathdesc)
825 			lastp->next = ro_newrivpoint(rp, newfirst, lastp->second, NULLRPOINT); else
826 				lastp->next = ro_newrivpoint(rp, newfirst, lp->second+space+rp->width, NULLRPOINT);
827 		if (lastp->next == 0) return(0);
828 		lastp = lastp->next;   lp = lp->next;
829 		if (lp) newfirst = lp->first+dir*(space+rp->width);
830 	}
831 	lastp->next = ro_newrivpoint(rp, t->first, lastp->second, NULLRPOINT);
832 	if (lastp->next == 0) return(0);
833 	rp->lastp->side = t->side;
834 	return(rp);
835 }
836 
ro_makesideorigpath(INTBIG width,ARCPROTO * ptype,INTBIG startoff,RPOINT * b,RPOINT * t)837 RPATH *ro_makesideorigpath(INTBIG width, ARCPROTO *ptype, INTBIG startoff, RPOINT *b, RPOINT *t)
838 {
839 	RPATH *rp;
840 	RPOINT *i1;
841 
842 	rp = ro_newrpath(width, ptype, ro_routepathtype(b, t));
843 	if (rp == 0) return(0);
844 	i1 = ro_newrivpoint(rp, t->first, startoff, NULLRPOINT);
845 	if (i1 == 0) return(0);
846 	rp->pathdesc = ro_newrivpoint(rp, b->first, startoff, i1);
847 	if (rp->pathdesc == 0) return(0);
848 	rp->lastp->side = t->side;
849 	return(rp);
850 }
851 
ro_sideaddpath(RPATH * path,INTBIG width,ARCPROTO * ptype,RPOINT * b,RPOINT * t,INTBIG space,INTBIG offset,INTBIG dir)852 RPATH *ro_sideaddpath(RPATH *path, INTBIG  width, ARCPROTO *ptype, RPOINT *b, RPOINT *t,
853 	INTBIG space, INTBIG offset, INTBIG dir)
854 {
855 	RPATH *rp;
856 	INTBIG newfirst, minfirst, maxfirst;
857 	RPOINT *lp, *lastp;
858 
859 	rp = ro_newrpath(width, ptype, ro_routepathtype(b, t));
860 	if (rp == 0) return(0);
861 	rp->pathdesc = ro_newrivpoint(rp, b->first, offset, NULLRPOINT);
862 	if (rp->pathdesc == 0) return(0);
863 
864 	minfirst = mini(b->first, t->first);
865 	maxfirst = maxi(b->first, t->first);
866 	lp = path->pathdesc;
867 
868 	lastp = rp->lastp;
869 
870 	newfirst = lp->first+dir*(space+rp->width);
871 	while (lp && minfirst <= newfirst && newfirst <= maxfirst)
872 	{
873 		/* if first point then inconsistent second(y) offset */
874 		if (lp == path->pathdesc)
875 			lastp->next = ro_newrivpoint(rp, newfirst, maxi(lastp->second, offset), NULLRPOINT);
876 		else
877 			lastp->next = ro_newrivpoint(rp, newfirst, maxi(lp->second+space+rp->width, offset),
878 				NULLRPOINT);
879 		if (lastp->next == 0) return(0);
880 		lastp = lastp->next;   lp = lp->next;
881 		if (lp) newfirst = lp->first+dir*(space+rp->width);
882 	}
883 	lastp->next = ro_newrivpoint(rp, t->first, lastp->second, NULLRPOINT);
884 	if (lastp->next == 0) return(0);
885 	rp->lastp->side = t->side;
886 	return(rp);
887 }
888 
ro_process_right(INTBIG width,ARCPROTO * ptype,RDESC * rout,INTBIG co1,INTBIG space,INTBIG dir)889 BOOLEAN ro_process_right(INTBIG width, ARCPROTO *ptype, RDESC *rout, INTBIG co1, INTBIG space,
890 	INTBIG dir)
891 {
892 	BOOLEAN firsttime;
893 	RDESC *reversedrd, *rd;
894 	RPATH *lastp;
895 	INTBIG offset;
896 
897 	firsttime = TRUE;   lastp = NULLRPATH;   offset = ro_rrinfo.startleft;
898 
899 	for(rd = reversedrd = ro_reverse(rout); rd; rd = rd->next)
900 	{
901 		if (rd->from->side != SIDE4)
902 		{
903 			/* starting from bottom (side1) */
904 			if (firsttime)
905 			{
906 				rd->path = ro_makeorigpath(width, ptype, co1, rd->from, rd->to);
907 				if (rd->path == 0) return(TRUE);
908 				firsttime = FALSE;
909 			} else
910 				rd->path = ro_addpath(lastp, width, ptype, rd->from, rd->to, space, co1, dir);
911 			if (rd->path == 0) return(TRUE);
912 		} else
913 		{
914 			if (firsttime)
915 			{
916 				rd->path = ro_makesideorigpath(width, ptype, offset, rd->from, rd->to);
917 				if (rd->path == 0) return(TRUE);
918 				firsttime = FALSE;
919 			} else
920 			{
921 				rd->path = ro_sideaddpath(lastp, width, ptype, rd->from, rd->to, space, offset, dir);
922 				if (rd->path == 0) return(TRUE);
923 			}
924 			offset += space+width;
925 		}
926 		lastp = rd->path;
927 	}
928 	(void)ro_reverse(reversedrd);  /* return to normal */
929 	return(FALSE);
930 }
931 
ro_process_left(INTBIG width,ARCPROTO * ptype,RDESC * rout,INTBIG co1,INTBIG space,INTBIG dir)932 BOOLEAN ro_process_left(INTBIG width, ARCPROTO *ptype, RDESC *rout, INTBIG co1, INTBIG space,
933 	INTBIG dir)
934 {
935 	BOOLEAN firsttime;
936 	RPATH *lastp;
937 	INTBIG offset;
938 
939 	firsttime = TRUE; lastp = NULLRPATH; offset = ro_rrinfo.startright;
940 	for(; rout; rout = rout->next)
941 	{
942 		if (rout->from->side != SIDE2)
943 		{
944 			if (firsttime)
945 			{
946 				rout->path = ro_makeorigpath(width, ptype, co1, rout->from, rout->to);
947 				if (rout->path == 0) return(TRUE);
948 				firsttime = FALSE;
949 			} else
950 			rout->path = ro_addpath(lastp, width, ptype, rout->from, rout->to, space, co1, dir);
951 			if (rout->path == 0) return(TRUE);
952 		} else
953 		{
954 			if (firsttime)
955 			{
956 				rout->path = ro_makesideorigpath(width, ptype, offset, rout->from, rout->to);
957 				if (rout->path == 0) return(TRUE);
958 				firsttime = FALSE;
959 			} else
960 			{
961 				rout->path = ro_sideaddpath(lastp, width, ptype, rout->from, rout->to, space,
962 					offset, dir);
963 				if (rout->path == 0) return(TRUE);
964 			}
965 			offset += space+width;
966 		}
967 		lastp = rout->path;
968 	}
969 	return(FALSE);
970 }
971 
972 /*
973  * calculate the height of the channel, and remap the points back into the
974  * original coordinate system
975  */
ro_remap_points(RPOINT * rp,TRANSFORM * matrix)976 void ro_remap_points(RPOINT *rp, TRANSFORM *matrix)
977 {
978 	for(; rp; rp = rp->next)
979 	{
980 		rp->x = (rp->first*matrix->t11) + (rp->second*matrix->t21);
981 		rp->y = (rp->first*matrix->t12) + (rp->second*matrix->t22);
982 	}
983 }
984 
ro_remap_second(INTBIG sec,TRANSFORM * matrix)985 INTBIG ro_remap_second(INTBIG sec, TRANSFORM *matrix)
986 {
987 	if (ro_rrinfo.xx == ROUTEINY) return(sec*matrix->t22);
988 	return(sec*matrix->t12);
989 }
990 
991 /*
992  * put it into the propoer coordinate system
993  */
ro_height_coordinate(INTBIG h)994 INTBIG ro_height_coordinate(INTBIG h)
995 {
996 	return(h+ro_rrinfo.fromline);
997 }
998 
ro_calculate_height_and_process(RDESC * right,RDESC * left,INTBIG width,INTBIG co2,INTBIG minheight,INTBIG * height)999 BOOLEAN ro_calculate_height_and_process(RDESC *right, RDESC *left, INTBIG width, INTBIG co2,
1000 	INTBIG minheight, INTBIG *height)
1001 {
1002 	INTBIG maxheight;
1003 	RDESC *rright, *lleft;
1004 	RPOINT *lastp;
1005 
1006 	maxheight = -MAXINTBIG;
1007 	for(rright = right; rright; rright = rright->next)
1008 		maxheight = maxi(maxheight, rright->path->lastp->second);
1009 
1010 	for(lleft = left; lleft; lleft = lleft->next)
1011 		maxheight = maxi(maxheight, lleft->path->lastp->second);
1012 
1013 	if (minheight != 0) maxheight = maxi(minheight, maxheight+(width/2)+co2);
1014 		else maxheight = maxheight+(width/2)+co2;
1015 	maxheight = maxi(maxheight, ro_rrinfo.toline);
1016 
1017 	/* make sure its at least where the coordinates are */
1018 	for(rright = right; rright; rright = rright->next)
1019 	{
1020 		lastp =	rright->path->lastp;
1021 		if (lastp->side != SIDE2)
1022 		{
1023 			lastp->next = ro_newrivpoint(rright->path, lastp->first, maxheight, NULLRPOINT);
1024 			if (lastp->next == 0) return(FALSE);
1025 		}
1026 		ro_remap_points(rright->path->pathdesc, ro_rrinfo.invmatrix);
1027 	}
1028 	for(lleft = left; lleft; lleft = lleft->next)
1029 	{
1030 		lastp = lleft->path->lastp;
1031 		if (lastp->side != SIDE4)
1032 		{
1033 			lastp->next = ro_newrivpoint(lleft->path, lastp->first, maxheight, NULLRPOINT);
1034 			if (lastp->next == 0) return(FALSE);
1035 		}
1036 		ro_remap_points(lleft->path->pathdesc, ro_rrinfo.invmatrix);
1037 	}
1038 	ro_rrinfo.toline = ro_remap_second(ro_rrinfo.toline, ro_rrinfo.invmatrix);
1039 	ro_rrinfo.fromline = ro_remap_second(ro_rrinfo.fromline, ro_rrinfo.invmatrix);
1040 	*height = ro_remap_second(maxheight,ro_rrinfo.invmatrix);
1041 	return(TRUE);
1042 }
1043 
ro_calculate_bb(INTBIG * llx,INTBIG * lly,INTBIG * urx,INTBIG * ury,RDESC * right,RDESC * left)1044 void ro_calculate_bb(INTBIG *llx, INTBIG *lly, INTBIG *urx, INTBIG *ury, RDESC *right, RDESC *left)
1045 {
1046 	RDESC *rright, *lleft;
1047 	RPOINT *rvp;
1048 	INTBIG lx, ly, ux, uy;
1049 
1050 	lx = ly = MAXINTBIG; ux = uy = -MAXINTBIG;
1051 	for(rright = right; rright; rright = rright->next)
1052 	{
1053 		for(rvp = rright->path->pathdesc; rvp; rvp = rvp->next)
1054 		{
1055 			lx = mini(lx, rvp->x);
1056 			ly = mini(ly, rvp->y);
1057 			ux = maxi(ux, rvp->x);
1058 			uy = maxi(uy, rvp->y);
1059 		}
1060 	}
1061 	for(lleft = left; lleft; lleft = lleft->next)
1062 	{
1063 		for(rvp = lleft->path->pathdesc; rvp; rvp = rvp->next)
1064 		{
1065 			lx = mini(lx, rvp->x);
1066 			ly = mini(ly, rvp->y);
1067 			ux = maxi(ux, rvp->x);
1068 			uy = maxi(uy, rvp->y);
1069 		}
1070 	}
1071 	*llx = lx;   *lly = ly;   *urx = ux;   *ury = uy;
1072 }
1073 
1074 /*
1075  * takes two sorted list of ports and routes between them
1076  * warning - if the width is not even, there will be round off problems
1077  */
ro_sorted_rivrot(ARCPROTO * layerdesc,RDESC * listr,INTBIG width,INTBIG space,INTBIG celloff1,INTBIG celloff2,INTBIG fixedheight)1078 BOOLEAN ro_sorted_rivrot(ARCPROTO *layerdesc, RDESC *listr, INTBIG width,
1079 	INTBIG space, INTBIG celloff1, INTBIG celloff2, INTBIG fixedheight)
1080 {
1081 	INTBIG height;
1082 
1083 	/* ports invalid */
1084 	if (!ro_check_points(listr, width, space)) return(FALSE);
1085 	ro_structure_points(listr);				/* put in left/right */
1086 	if (!ro_check_structured_points(ro_rrinfo.rightp, ro_rrinfo.leftp, celloff1, width, space))
1087 		return(FALSE);
1088 	if (ro_process_right(width, layerdesc, ro_rrinfo.rightp, celloff1, space, -1)) return(FALSE);
1089 	if (ro_process_left(width, layerdesc, ro_rrinfo.leftp, celloff1, space, 1)) return(FALSE);
1090 	if (fixedheight != 0) fixedheight = ro_height_coordinate(fixedheight);
1091 	if (!ro_calculate_height_and_process(ro_rrinfo.rightp, ro_rrinfo.leftp, width, celloff2,
1092 		fixedheight, &height)) return(FALSE);
1093 	if (fixedheight > 0 && height > fixedheight)
1094 	{
1095 		/* can't make it in fixed height */
1096 		ttyputerr(_("River router: Unable to route in %s wide channel, need %s"), latoa(fixedheight, 0),
1097 			latoa(height, 0));
1098 		return(FALSE);
1099 	}
1100 	ro_calculate_bb(&ro_rrinfo.llx, &ro_rrinfo.lly, &ro_rrinfo.urx, &ro_rrinfo.ury,
1101 		ro_rrinfo.rightp, ro_rrinfo.leftp);
1102 	ro_rrinfo.height = height;
1103 	return(TRUE);
1104 }
1105 
1106 /*
1107  * Helper routine for "esort" that makes river points go in ascending order.
1108  * Used from "ro_quicksort()".
1109  */
ro_rivpointascending(const void * e1,const void * e2)1110 int ro_rivpointascending(const void *e1, const void *e2)
1111 {
1112 	REGISTER RDESC *c1, *c2;
1113 
1114 	c1 = *((RDESC **)e1);
1115 	c2 = *((RDESC **)e2);
1116 	return(c1->sortval - c2->sortval);
1117 }
1118 
1119 /* Quicksorts the rivpoints */
ro_quicksort(RDESC * rd)1120 RDESC *ro_quicksort(RDESC *rd)
1121 {
1122 	RDESC **thearray, *r;
1123 	INTBIG xdir, i, len;
1124 
1125 	for(len = 0, r = rd; r; len++, r = r->next)
1126 		;
1127 	if (len == 0) return(NULLRDESC);
1128 	thearray = ro_newrdarray(len);
1129 	if (thearray == 0) return(NULLRDESC);
1130 	xdir = (ro_rrinfo.xx == ROUTEINX ? FALSE : TRUE);
1131 
1132 	for(i=0; rd; i++, rd = rd->next)
1133 	{
1134 		thearray[i] = rd;
1135 		rd->sortval = (xdir ? rd->from->x : rd->from->y);
1136 	}
1137 
1138 	/* instead of "ro_sortquick(0, len-1, len-1, thearray)"... */
1139 	esort(thearray, len, sizeof (RDESC *), ro_rivpointascending);
1140 	for(i=0; i<len; i++) thearray[i]->next = thearray[i+1];
1141 	r = *thearray;   ro_freerdarray(thearray);
1142 	return(r);
1143 }
1144 
1145 /*
1146  * takes two unsorted list of ports and routes between them
1147  * warning - if the width is not even, there will be round off problems
1148  */
ro_unsorted_rivrot(ARCPROTO * layerdesc,RDESC * lists,INTBIG width,INTBIG space,INTBIG celloff1,INTBIG celloff2,INTBIG fixedheight)1149 BOOLEAN ro_unsorted_rivrot(ARCPROTO *layerdesc, RDESC *lists, INTBIG width,
1150 	INTBIG space, INTBIG celloff1, INTBIG celloff2, INTBIG fixedheight)
1151 {
1152 	return(ro_sorted_rivrot(layerdesc, ro_quicksort(lists), width, space,
1153 		celloff1, celloff2, fixedheight));
1154 }
1155 
1156 /*
1157  * once the route occurs, make some geometry and move some cells around
1158  */
ro_checkthecell(NODEINST * ni)1159 void ro_checkthecell(NODEINST *ni)
1160 {
1161 	if (ni->proto->primindex == 0)
1162 	{
1163 		/* the node is nonprimitive */
1164 		if (!ro_rrmovecell.cellvalid) return;
1165 		if (ro_rrmovecell.topcell == NONODEINST)  /* first one */
1166 			ro_rrmovecell.topcell = ni;
1167 		else if (ro_rrmovecell.topcell != ni) ro_rrmovecell.cellvalid = FALSE;
1168 	}
1169 }
1170 
ro_pseudomake(RDESC * rd,NODEPROTO * cell)1171 void ro_pseudomake(RDESC *rd, NODEPROTO *cell)
1172 {
1173 	RPATH *path;
1174 	REGISTER RPOINT *rp, *prev;
1175 
1176 	path = rd->path;
1177 
1178 	prev = path->pathdesc;
1179 	for(rp = prev->next; rp != NULLRPOINT; rp = rp->next)
1180 	{
1181 		if (rp->next)
1182 		{
1183 			if (prev->x == rp->x && rp->x == rp->next->x) continue;
1184 			if (prev->y == rp->y && rp->y == rp->next->y) continue;
1185 		}
1186 		(void)asktool(us_tool, x_("show-line"), prev->x, prev->y, rp->x, rp->y, cell);
1187 		prev = rp;
1188 	}
1189 	ro_checkthecell(rd->unroutedwire2->end[rd->unroutedend2].nodeinst);
1190 }
1191 
1192 /*
1193  * draw lines on the screen denoting what the route would look
1194  * like if it was done
1195  */
ro_makepseudogeometry(NODEPROTO * cell)1196 void ro_makepseudogeometry(NODEPROTO *cell)
1197 {
1198 	RDESC *q;
1199 	INTBIG lambda;
1200 
1201 	lambda = lambdaofcell(cell);
1202 	ttyputmsg(_("Routing bounds %s <= X <= %s   %s <= Y <= %s"), latoa(ro_rrinfo.llx, lambda),
1203 		latoa(ro_rrinfo.urx, lambda), latoa(ro_rrinfo.lly, lambda), latoa(ro_rrinfo.ury, lambda));
1204 
1205 	/* remove highlighting */
1206 	(void)asktool(us_tool, x_("clear"));
1207 
1208 	for(q = ro_rrinfo.rightp; q != NULLRDESC; q = q->next) ro_pseudomake(q, cell);
1209 	for(q = ro_rrinfo.leftp; q != NULLRDESC; q = q->next) ro_pseudomake(q, cell);
1210 }
1211 
ro_thenode(RDESC * rd,NODEPROTO * dn,RPOINT * p,NODEPROTO * np)1212 NODEINST *ro_thenode(RDESC *rd, NODEPROTO *dn, RPOINT *p, NODEPROTO *np)
1213 {
1214 	REGISTER NODEINST *ni;
1215 	INTBIG wdiv2, hdiv2, xs, ys;
1216 
1217 	if (p->x == ro_rrbx && p->y == ro_rrby)
1218 		return(rd->unroutedwire1->end[rd->unroutedend1].nodeinst);
1219 
1220 	if (p->x == ro_rrex && p->y == ro_rrey)
1221 		return(rd->unroutedwire2->end[rd->unroutedend2].nodeinst);
1222 
1223 	defaultnodesize(dn, &xs, &ys);
1224 	wdiv2 = xs / 2;
1225 	hdiv2 = ys / 2;
1226 	ni = newnodeinst(dn, p->x - wdiv2, p->x + wdiv2, p->y - hdiv2, p->y + hdiv2, 0, 0, np);
1227 	if (ni != NONODEINST) endobjectchange((INTBIG)ni, VNODEINST);
1228 	return(ni);
1229 }
1230 
ro_theport(PORTPROTO * dp,RDESC * rd,RPOINT * p)1231 PORTPROTO *ro_theport(PORTPROTO *dp, RDESC *rd, RPOINT *p)
1232 {
1233 	if (p->x == ro_rrbx && p->y == ro_rrby)
1234 		return(rd->unroutedwire1->end[rd->unroutedend1].portarcinst->proto);
1235 
1236 	if (p->x == ro_rrex && p->y == ro_rrey)
1237 		return(rd->unroutedwire2->end[rd->unroutedend2].portarcinst->proto);
1238 
1239 	return(dp);
1240 }
1241 
1242 /*
1243  * make electric geometry
1244  */
ro_makegeometry(RDESC * rd,NODEPROTO * np)1245 void ro_makegeometry(RDESC *rd, NODEPROTO *np)
1246 {
1247 	RPATH *path;
1248 	REGISTER RPOINT *rp, *prev;
1249 	NODEINST *prevnodeinst, *rpnodeinst;
1250 	NODEPROTO *defnode;
1251 	PORTPROTO *defport, *prevport, *rpport;
1252 	REGISTER ARCINST *ai;
1253 
1254 	path = rd->path;
1255 
1256 	portposition(rd->unroutedwire1->end[rd->unroutedend1].nodeinst,
1257 				 rd->unroutedwire1->end[rd->unroutedend1].portarcinst->proto, &ro_rrbx, &ro_rrby);
1258 	portposition(rd->unroutedwire2->end[rd->unroutedend2].nodeinst,
1259 				rd->unroutedwire2->end[rd->unroutedend2].portarcinst->proto, &ro_rrex, &ro_rrey);
1260 
1261 	defnode = getpinproto(path->pathtype);
1262 	defport = defnode->firstportproto; /* there is always only one */
1263 
1264 	prev = path->pathdesc;
1265 	prevnodeinst = ro_thenode(rd, defnode, prev, np);
1266 	prevport = ro_theport(defport, rd, prev);
1267 
1268 	for(rp = prev->next; rp != NULLRPOINT; rp = rp->next)
1269 	{
1270 		if (rp->next)
1271 		{
1272 			if (prev->x == rp->x && rp->x == rp->next->x) continue;
1273 			if (prev->y == rp->y && rp->y == rp->next->y) continue;
1274 		}
1275 		rpnodeinst = ro_thenode(rd, defnode, rp, np);
1276 		rpport = ro_theport(defport, rd, rp);
1277 
1278 		ai = newarcinst(path->pathtype, path->width, FIXANG,
1279 			prevnodeinst, prevport, prev->x, prev->y, rpnodeinst, rpport, rp->x, rp->y, np);
1280 		if (ai != NOARCINST) endobjectchange((INTBIG)ai, VARCINST);
1281 		prev = rp;   prevnodeinst = rpnodeinst;   prevport = rpport;
1282 	}
1283 }
1284 
ro_clear_flags(NODEPROTO * np)1285 void ro_clear_flags(NODEPROTO *np)
1286 {
1287 	ARCINST *ai;
1288 
1289 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1290 	{
1291 		ai->temp1 = 0;
1292 		ai->end[0].nodeinst->temp1 = 0;
1293 		ai->end[1].nodeinst->temp1 = 0;
1294 	}
1295 }
1296 
1297 /*
1298  * routine to return true if nodeinst "ni" is an unrouted pin
1299  */
ro_isunroutedpin(NODEINST * ni)1300 BOOLEAN ro_isunroutedpin(NODEINST *ni)
1301 {
1302 	/* only want the unrouted pin */
1303 	if (ni->proto != gen_unroutedpinprim && ni->proto != gen_univpinprim) return(FALSE);
1304 
1305 	/* found one */
1306 	return(TRUE);
1307 }
1308 
ro_is_interesting_arc(ARCINST * ai)1309 BOOLEAN ro_is_interesting_arc(ARCINST *ai)
1310 {
1311 	/* skip arcs already considered */
1312 	if (ai->temp1 != 0) return(FALSE);
1313 
1314 	/* only want "unrouted" arc in generic technology */
1315 	if (ai->proto != gen_unroutedarc) return(FALSE);
1316 
1317 	return(TRUE);
1318 }
1319 
ro_set_flags(ARCINST * ai)1320 void ro_set_flags(ARCINST *ai)
1321 {
1322 	ai->temp1++;
1323 	if (ro_isunroutedpin(ai->end[0].nodeinst)) ai->end[0].nodeinst->temp1++;
1324 	if (ro_isunroutedpin(ai->end[1].nodeinst)) ai->end[1].nodeinst->temp1++;
1325 }
1326 
ro_mark_tobedeleted(ARCINST * ai)1327 void ro_mark_tobedeleted(ARCINST *ai)
1328 {
1329 	PORTARCINST *pi;
1330 	ARCINST *oai, *ae;
1331 	INTBIG e;
1332 
1333 	if (!ro_is_interesting_arc(ai)) return;
1334 
1335 	ro_set_flags(ai);
1336 	ae = ai;  e = 0;
1337 	for(;;)
1338 	{
1339 		if (!ro_isunroutedpin(ae->end[e].nodeinst)) break;
1340 		for(pi = ae->end[e].nodeinst->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1341 		{
1342 			oai = pi->conarcinst;
1343 			if (oai->temp1 == 0) break;
1344 		}
1345 		if (pi == NOPORTARCINST) break;
1346 		ro_set_flags(oai);
1347 		if (oai->end[0].nodeinst == ae->end[e].nodeinst) e = 1; else e = 0;
1348 		ae = oai;
1349 	}
1350 	ae = ai;  e = 1;
1351 	for(;;)
1352 	{
1353 		if (!ro_isunroutedpin(ae->end[e].nodeinst)) break;
1354 		for(pi = ae->end[e].nodeinst->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1355 		{
1356 			oai = pi->conarcinst;
1357 			if (oai->temp1 == 0) break;
1358 		}
1359 		if (pi == NOPORTARCINST) break;
1360 		ro_set_flags(oai);
1361 		if (oai->end[0].nodeinst == ae->end[e].nodeinst) e = 1; else e = 0;
1362 		ae = oai;
1363 	}
1364 }
1365 
ro_delnodeinst(NODEINST * ni)1366 BOOLEAN ro_delnodeinst(NODEINST *ni)
1367 {
1368 	REGISTER PORTARCINST *pi;
1369 
1370 	/* see if any arcs connect to this node */
1371 	for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1372 	{
1373 		if (pi->conarcinst != NOARCINST) return(FALSE);
1374 	}
1375 
1376 	/* see if this nodeinst is a portinst of the cell */
1377 	if (ni->firstportexpinst != NOPORTEXPINST) return(FALSE);
1378 
1379 	/* now erase the nodeinst */
1380 	startobjectchange((INTBIG)ni, VNODEINST);
1381 	return(killnodeinst(ni));
1382 }
1383 
ro_kill_wires(NODEPROTO * np)1384 void ro_kill_wires(NODEPROTO *np)
1385 {
1386 	ARCINST *ai;
1387 	NODEINST *ni;
1388 
1389 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1390 	{
1391 		if (ai->temp1 != 0)
1392 		{
1393 			startobjectchange((INTBIG)ai, VARCINST);
1394 			if (killarcinst(ai))
1395 				ttyputmsg(_("River router: Error occured while killing arc"));
1396 		}
1397 	}
1398 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1399 	{
1400 		if (ni->temp1 != 0 && ro_isunroutedpin(ni))
1401 		{
1402 			if (ro_delnodeinst(ni))
1403 				ttyputmsg(_("River router: Error occured while killing node"));
1404 		}
1405 	}
1406 }
1407 
ro_makethegeometry(NODEPROTO * np)1408 void ro_makethegeometry(NODEPROTO *np)
1409 {
1410 	RDESC *q;
1411 
1412 	(void)asktool(us_tool, x_("clear"));
1413 	ro_clear_flags(np);
1414 	for(q = ro_rrinfo.rightp; q != NULLRDESC; q = q->next)
1415 	{
1416 		ro_makegeometry(q, np);   ro_mark_tobedeleted(q->unroutedwire1);
1417 		if (q->unroutedwire1 != q->unroutedwire2) ro_mark_tobedeleted(q->unroutedwire2);
1418 	}
1419 	for(q = ro_rrinfo.leftp; q != NULLRDESC; q = q->next)
1420 	{
1421 		ro_makegeometry(q, np);   ro_mark_tobedeleted(q->unroutedwire2);
1422 		if (q->unroutedwire1 != q->unroutedwire2) ro_mark_tobedeleted(q->unroutedwire2);
1423 	}
1424 	ro_kill_wires(np);
1425 
1426 }
1427 
1428 /*
1429  * Figure out which way to route (x and y) and the top coordinate and
1430  * bottom coordinate
1431  */
ro_tallyvote(RCOORD * cc,INTBIG c)1432 RCOORD *ro_tallyvote(RCOORD *cc, INTBIG c)
1433 {
1434 	RCOORD *cclast, *ccinit;
1435 
1436 	if (cc == NULLCOORD)
1437 	{
1438 		cc = ro_newcoord(c);
1439 		if (cc == 0) return(0);
1440 		cc->total = 1;
1441 		return(cc);
1442 	}
1443 
1444 	ccinit = cc;
1445 	for(cclast = NULLCOORD; (cc && cc->total >= 0 && cc->val != c); cclast = cc, cc = cc->next) ;
1446 	if (cc == NULLCOORD)
1447 	{
1448 		cc = ro_newcoord(c);
1449 		if (cc == 0) return(0);
1450 		cclast->next = cc;
1451 		cc->total = 1;
1452 		return(ccinit);
1453 	} else
1454 	{
1455 		if (cc->total <0)
1456 		{
1457 			cc->val = c; cc->total = 1;
1458 		} else cc->total++;
1459 	}
1460 	return(ccinit);
1461 }
1462 
ro_vote(INTBIG ffx,INTBIG ffy,INTBIG ttx,INTBIG tty)1463 void ro_vote(INTBIG ffx, INTBIG ffy, INTBIG ttx, INTBIG tty)
1464 {
1465 	ro_rrinfo.xaxis = ro_tallyvote(ro_rrinfo.xaxis, ffx);
1466 	if (ro_rrinfo.xaxis == 0) return;
1467 	ro_rrinfo.yaxis = ro_tallyvote(ro_rrinfo.yaxis, ffy);
1468 	if (ro_rrinfo.yaxis == 0) return;
1469 	ro_rrinfo.xaxis = ro_tallyvote(ro_rrinfo.xaxis, ttx);
1470 	if (ro_rrinfo.xaxis == 0) return;
1471 	ro_rrinfo.yaxis = ro_tallyvote(ro_rrinfo.yaxis, tty);
1472 }
1473 
ro_simplefigxx(RCOORD * x1,RCOORD * x2,RCOORD * y1,RCOORD * y2,INTBIG total,RCOORD ** from,RCOORD ** to)1474 INTBIG ro_simplefigxx(RCOORD *x1, RCOORD *x2, RCOORD *y1, RCOORD *y2, INTBIG total, RCOORD **from,
1475 	RCOORD **to)
1476 {
1477 	*from = NULLCOORD;   *to = NULLCOORD;
1478 	if (x1 && x2 && x1->total == total && x2->total == total)
1479 	{
1480 		*from = x1;   *to = x2;
1481 		return(ROUTEINX);
1482 	}
1483 	if (y1 && y2 && y1->total == total && y2->total == total)
1484 	{
1485 		*from = y1;   *to = y2;
1486 		return(ROUTEINY);
1487 	}
1488 	if (x1 && x1->total == (2*total))
1489 	{
1490 		*from = *to = x1;
1491 		return(ROUTEINX);
1492 	}
1493 	if (y1 && y1->total == (2*total))
1494 	{
1495 		*from = *to = y1;
1496 		return(ROUTEINY);
1497 	}
1498 	return(ILLEGALROUTE);
1499 }
1500 
ro_largest(RCOORD * cc)1501 RCOORD *ro_largest(RCOORD *cc)
1502 {
1503 	RCOORD *largest;
1504 
1505 	for(largest = cc, cc = cc->next; cc; cc =cc->next)
1506 	{
1507 		if (cc->total > largest->total) largest = cc;
1508 	}
1509 	return(largest);
1510 }
1511 
ro_next_largest(RCOORD * cc,RCOORD * largest)1512 RCOORD *ro_next_largest(RCOORD *cc, RCOORD *largest)
1513 {
1514 	RCOORD *nlargest;
1515 
1516 	for(nlargest = NULLCOORD; cc; cc =cc->next)
1517 	{
1518 		if ((!nlargest) && (cc != largest)) nlargest = cc; else
1519 			if (nlargest && cc != largest && cc->total > nlargest->total) nlargest = cc;
1520 	}
1521 	return(nlargest);
1522 }
1523 
ro_figureoutrails(INTBIG total)1524 void ro_figureoutrails(INTBIG total)
1525 {
1526 	INTBIG fxx;
1527 	RCOORD *lx, *ly, *nlx, *nly, *from, *to, *tmp;
1528 
1529 	from = to = NULLCOORD;
1530 	lx = ro_largest(ro_rrinfo.xaxis);   ly = ro_largest(ro_rrinfo.yaxis);
1531 	fxx = ro_simplefigxx(lx, (nlx = ro_next_largest(ro_rrinfo.xaxis, lx)),
1532 		ly, (nly = ro_next_largest(ro_rrinfo.yaxis, ly)), total, &from, &to);
1533 	if (fxx == ILLEGALROUTE)
1534 	{
1535 		if (lx->total >= total)
1536 		{
1537 			/* lx->total == total --- the other one an unusual case */
1538 			/* lx->total > total  --- both go to the same line */
1539 			fxx = ROUTEINX;   from = lx;
1540 			to = (lx->total > total ? lx : nlx);
1541 		} else if (ly->total >= total)
1542 		{
1543 			/* ly->total == total --- the other one an unusual case */
1544 			/* ly->total > total  --- both go to the same line */
1545 			fxx = ROUTEINY;   from = ly;
1546 			to = (ly->total > total ? ly : nly);
1547 		} else
1548 		{
1549 			fxx = (((ly->total+nly->total)>=(lx->total+nlx->total)) ? ROUTEINY : ROUTEINX);
1550 			from = (fxx == ROUTEINY ? ly : lx);
1551 			to = (fxx == ROUTEINY ? nly : nlx);
1552 		}
1553 	}
1554 
1555 	if (to->val < from->val)
1556 	{
1557 		tmp = from;   from = to;   to = tmp;
1558 	}
1559 
1560 	ro_rrinfo.xx = fxx;
1561 	ro_rrinfo.fromline = from->val;   ro_rrinfo.toline = to->val;
1562 }
1563 
ro_point_val(RPOINT * rp,INTBIG xx)1564 INTBIG ro_point_val(RPOINT *rp, INTBIG xx)
1565 {
1566 	return(xx == ROUTEINX ? rp->x : rp->y);
1567 }
1568 
ro_swap_points(RDESC * r)1569 void ro_swap_points(RDESC *r)
1570 {
1571 	RPOINT *tmp;
1572 	ARCINST *tmpwire;
1573 	INTBIG tmpe;
1574 
1575 	if (r->from->side != SIDE1 || r->to->side != SIDE3)
1576 		ttyputerr(_("River router: Unexpected side designation"));
1577 
1578 	tmp = r->from;   r->from = r->to;
1579 	r->to = tmp;
1580 
1581 	r->from->side = SIDE1;   r->to->side = SIDE3;
1582 	tmpwire = r->unroutedwire1;   tmpe = r->unroutedend1;
1583 	r->unroutedwire1 = r->unroutedwire2;   r->unroutedend1 = r->unroutedend2;
1584 	r->unroutedwire2 = tmpwire;   r->unroutedend2 = tmpe;
1585 }
1586 
ro_set_wires_to_rails(RDESC * lists)1587 void ro_set_wires_to_rails(RDESC *lists)
1588 {
1589 	RDESC *r;
1590 	INTBIG fval, tval;
1591 
1592 	for(r = lists; r; r = r->next)
1593 	{
1594 		fval = ro_point_val(r->from, ro_rrinfo.xx);
1595 		tval = ro_point_val(r->to, ro_rrinfo.xx);
1596 		if ((fval != ro_rrinfo.fromline && tval == ro_rrinfo.fromline) ||
1597 			(tval != ro_rrinfo.toline && fval == ro_rrinfo.toline))
1598 				ro_swap_points(r);
1599 	}
1600 }
1601 
1602 /*
1603  * figure out the wires to route at all
1604  */
ro_addwire(RDESC * list,ARCINST * ai,BOOLEAN * wireadded)1605 RDESC *ro_addwire(RDESC *list, ARCINST *ai, BOOLEAN *wireadded)
1606 {
1607 	PORTARCINST *pi;
1608 	ARCINST *oai, *ae1, *ae2;
1609 	INTBIG e1, e2;
1610 	INTBIG bx, by, ex, ey;
1611 
1612 	if (!ro_is_interesting_arc(ai))
1613 	{
1614 		*wireadded = FALSE;
1615 		return(list);
1616 	}
1617 	*wireadded = TRUE;
1618 
1619 	ai->temp1++;
1620 	ae1 = ai;   e1 = 0;
1621 	for(;;)
1622 	{
1623 		if (!ro_isunroutedpin(ae1->end[e1].nodeinst)) break;
1624 		for(pi = ae1->end[e1].nodeinst->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1625 		{
1626 			oai = pi->conarcinst;
1627 			if (oai->temp1 == 0) break;
1628 		}
1629 		if (pi == NOPORTARCINST) break;
1630 		oai->temp1++;
1631 		if (oai->end[0].nodeinst == ae1->end[e1].nodeinst) e1 = 1; else e1 = 0;
1632 		ae1 = oai;
1633 	}
1634 	ae2 = ai;   e2 = 1;
1635 	for(;;)
1636 	{
1637 		if (!ro_isunroutedpin(ae2->end[e2].nodeinst)) break;
1638 		for(pi = ae2->end[e2].nodeinst->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1639 		{
1640 			oai = pi->conarcinst;
1641 			if (oai->temp1 == 0) break;
1642 		}
1643 		if (pi == NOPORTARCINST) break;
1644 		oai->temp1++;
1645 		if (oai->end[0].nodeinst == ae2->end[e2].nodeinst) e2 = 1; else e2 = 0;
1646 		ae2 = oai;
1647 	}
1648 
1649 	portposition(ae1->end[e1].nodeinst, ae1->end[e1].portarcinst->proto, &bx, &by);
1650 	portposition(ae2->end[e2].nodeinst, ae2->end[e2].portarcinst->proto, &ex, &ey);
1651 	list = ro_newroutedesc(bx, by, SIDE1, ex, ey, SIDE3, ae1, e1, ae2, e2, list);
1652 	if (list == 0) return(0);
1653 	ro_vote(list->from->x, list->from->y, list->to->x, list->to->y);
1654 	ro_sumup(ae1->end[e1].portarcinst);
1655 	ro_sumup(ae2->end[e2].portarcinst);
1656 	return(list);
1657 }
1658 
ro_findhighlightedwires(NODEPROTO * np,INTBIG * tot)1659 RDESC *ro_findhighlightedwires(NODEPROTO *np, INTBIG *tot)
1660 {
1661 	RDESC *thelist;
1662 	GEOM **list;
1663 	ARCINST *ai;
1664 	INTBIG i, total;
1665 	BOOLEAN wireadded;
1666 
1667 	/* get list of all highlighted arcs */
1668 	list = (GEOM **)asktool(us_tool, x_("get-all-arcs"));
1669 	if (list[0] == NOGEOM)
1670 	{
1671 		total = 0;   tot = &total;
1672 		return(NULLRDESC);
1673 	}
1674 
1675 	/* get boundary of highlight */
1676 	(void)asktool(us_tool, x_("get-highlighted-area"), (INTBIG)&ro_rrinfo.llx,
1677 		(INTBIG)&ro_rrinfo.urx, (INTBIG)&ro_rrinfo.lly, (INTBIG)&ro_rrinfo.ury);
1678 
1679 	/* reset flags on all arcs in this cell */
1680 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst) ai->temp1 = 0;
1681 
1682 	thelist = NULLRDESC;
1683 	total = 0;
1684 
1685 	/* search the list */
1686 	for(i = 0; list[i] != NOGEOM; i++)
1687 	{
1688 		ai = list[i]->entryaddr.ai;
1689 		thelist = ro_addwire(thelist, ai, &wireadded);
1690 		if (thelist == 0) return(NULLRDESC);
1691 		if (wireadded) total++;
1692 	}
1693 
1694 	*tot = total;
1695 	return(thelist);
1696 }
1697 
ro_findnormalwires(NODEPROTO * np,INTBIG * tot)1698 RDESC *ro_findnormalwires(NODEPROTO *np, INTBIG *tot)
1699 {
1700 	REGISTER ARCINST *ai;
1701 	REGISTER INTBIG total;
1702 	RDESC *thelist;
1703 	INTBIG llx, lly, urx, ury;
1704 	BOOLEAN wireadded;
1705 
1706 	thelist = NULLRDESC;   llx = lly = MAXINTBIG;   urx = ury = -MAXINTBIG;
1707 	total = 0;
1708 
1709 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst) ai->temp1 = 0;
1710 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1711 	{
1712 		thelist = ro_addwire(thelist, ai, &wireadded);
1713 		if (thelist == 0) return(NULLRDESC);
1714 		if (wireadded)
1715 		{
1716 			total++;
1717 			llx = mini(mini(llx, thelist->from->x), thelist->to->x);
1718 			lly = mini(mini(lly, thelist->from->y), thelist->to->y);
1719 			urx = maxi(maxi(urx, thelist->from->x), thelist->to->x);
1720 			ury = maxi(maxi(ury, thelist->from->y), thelist->to->y);
1721 		}
1722 	}
1723 	ro_rrinfo.llx = llx;   ro_rrinfo.lly = lly;
1724 	ro_rrinfo.urx = urx;   ro_rrinfo.ury = ury;
1725 	*tot = total;
1726 	return(thelist);
1727 }
1728 
ro_findwires(NODEPROTO * np)1729 BOOLEAN ro_findwires(NODEPROTO *np)
1730 {
1731 	REGISTER ARCPROTO *ap, *wantap;
1732 	REGISTER TECHNOLOGY *tech, *curtech;
1733 	REGISTER INTBIG amt;
1734 	static POLYGON *poly = NOPOLYGON;
1735 	REGISTER ARCINST *ai;
1736 	ARCINST arc;
1737 	INTBIG total;
1738 	INTBIG edge;
1739 	RDESC *thelist;
1740 	REGISTER VARIABLE *var;
1741 
1742 	ro_initialize();
1743 	if (np->primindex != 0)
1744 	{
1745 		ttyputerr(_("River router cannot route primitives"));
1746 		return(FALSE);
1747 	}
1748 
1749 	curtech = np->tech;
1750 
1751 	/* initialize the list of possible arc prototypes for routing */
1752 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
1753 		for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1754 			ap->temp1 = 0;
1755 
1756 	/* look for all unrouted arcs */
1757 	if (!(thelist = ro_findhighlightedwires(np, &total)))
1758 		thelist = ro_findnormalwires(np, &total);
1759 
1760 	if (!thelist) return(FALSE);
1761 
1762 	/* first look for the current arcproto */
1763 	wantap = NOARCPROTO;
1764 	var = getval((INTBIG)us_tool, VTOOL, VARCPROTO, x_("USER_current_arc"));
1765 	if (var != NOVARIABLE)
1766 	{
1767 		ap = (ARCPROTO *)var->addr;
1768 		if (ap->tech->techindex != 0)
1769 			if (ap->temp1 == total*2) wantap = ap;
1770 	}
1771 
1772 	/* look in the current technology if not */
1773 	if (wantap == NOARCPROTO)
1774 	{
1775 		for(ap = curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1776 			if (ap->temp1 == total*2)
1777 		{
1778 			wantap = ap;
1779 			break;
1780 		}
1781 	}
1782 
1783 	/* look for ANY arc prototype */
1784 	if (wantap == NOARCPROTO)
1785 		for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
1786 	{
1787 		for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1788 			if (ap->temp1 == total*2)
1789 		{
1790 			wantap = ap;
1791 			break;
1792 		}
1793 	}
1794 
1795 	if (wantap == NOARCPROTO)
1796 	{
1797 		ttyputerr(_("River router: Cannot find arc that will connect"));
1798 		return(FALSE);
1799 	}
1800 	ttyputmsg(_("River routing with %s arcs"), describearcproto(wantap));
1801 
1802 	ro_figureoutrails(total);   ro_set_wires_to_rails(thelist);
1803 
1804 	/* figure out the worst design rule spacing for this type of arc */
1805 	(void)needstaticpolygon(&poly, 4, ro_tool->cluster);
1806 	ai = &arc;   initdummyarc(ai);
1807 	ai->proto = wantap;
1808 	ai->width = defaultarcwidth(wantap);
1809 	ai->length = 10000;
1810 	(void)arcpolys(ai, NOWINDOWPART);
1811 	shapearcpoly(ai, 0, poly);
1812 	amt = drcmindistance(ai->proto->tech, np->lib, poly->layer, ai->width,
1813 		poly->layer, ai->width, FALSE, FALSE, &edge, 0);
1814 	if (amt < 0) amt = lambdaofarc(ai);
1815 	return(ro_unsorted_rivrot(wantap, thelist, ai->width, amt, amt, amt, 0));
1816 }
1817 
ro_move_instance(void)1818 BOOLEAN ro_move_instance(void)
1819 {
1820 	INTBIG lx, ly;
1821 	NODEINST *ni;
1822 
1823 	ni = ro_rrmovecell.topcell;
1824 	if (!ro_rrmovecell.cellvalid || ni == NONODEINST)
1825 	{
1826 		ttyputmsg(_("River router: Cannot determine cell to move"));
1827 		return(FALSE);
1828 	}
1829 
1830 	lx = (ro_rrinfo.xx == ROUTEINX ? ro_rrinfo.height + ni->lowx - ro_rrinfo.toline : ni->lowx);
1831 	ly = (ro_rrinfo.xx == ROUTEINY ? ro_rrinfo.height + ni->lowy - ro_rrinfo.toline : ni->lowy);
1832 	if (lx == ni->lowx && ly == ni->lowy) return(TRUE);
1833 	startobjectchange((INTBIG)ni, VNODEINST);
1834 	modifynodeinst(ni, lx - ni->lowx, ly - ni->lowy, lx - ni->lowx, ly - ni->lowy, 0, 0);
1835 	endobjectchange((INTBIG)ni, VNODEINST);
1836 	return(TRUE);
1837 }
1838 
ro_query_user(void)1839 BOOLEAN ro_query_user(void)
1840 {
1841 	CHAR *par[MAXPARS];
1842 	INTBIG count;
1843 
1844 	/* wait for user response */
1845 	for(;;)
1846 	{
1847 		count = ttygetparam(_("River-route option: "), &ro_riverp, MAXPARS, par);
1848 		if (count == 0) continue;
1849 		if (par[0][0] == 'r') break;
1850 		if (par[0][0] == 'm')
1851 		{
1852 			if (ro_move_instance()) return(TRUE);
1853 		}
1854 		if (par[0][0] == 'a') return(FALSE);
1855 	}
1856 	return(TRUE);
1857 }
1858 
ro_river(NODEPROTO * np)1859 BOOLEAN ro_river(NODEPROTO *np)
1860 {
1861 	BOOLEAN valid_route;
1862 	RDESC *q;
1863 
1864 	/* locate wires */
1865 	if (ro_findwires(np))
1866 	{
1867 		/* see if user selection is requested */
1868 		valid_route = TRUE;
1869 		if ((ro_state&SELECT) == 0)
1870 		{
1871 			/* make wires */
1872 			for(q = ro_rrinfo.rightp; q != NULLRDESC; q = q->next)
1873 				ro_checkthecell(q->unroutedwire2->end[q->unroutedend2].nodeinst);
1874 			for(q = ro_rrinfo.leftp; q != NULLRDESC; q = q->next)
1875 				ro_checkthecell(q->unroutedwire2->end[q->unroutedend2].nodeinst);
1876 
1877 			/* if there is motion to be done, do it */
1878 			if (ro_rrmovecell.cellvalid && ro_rrmovecell.topcell != NONODEINST)
1879 			{
1880 				if (ro_move_instance()) ro_makethegeometry(np); else
1881 					valid_route = FALSE;
1882 			} else ro_makethegeometry(np);
1883 		} else
1884 		{
1885 			/* show where wires will go and allow user confirmation */
1886 			ro_makepseudogeometry(np);
1887 			if (ro_query_user()) ro_makethegeometry(np); else
1888 				valid_route = FALSE;
1889 		}
1890 	} else valid_route = FALSE;
1891 	ro_cleanup();
1892 	return(valid_route);
1893 }
1894 
ro_sumup(PORTARCINST * pi)1895 void ro_sumup(PORTARCINST *pi)
1896 {
1897 	REGISTER INTBIG i;
1898 
1899 	/*
1900 	 * for every layer (or arcproto) that this PORT allows to connect to it,
1901 	 * increment the flag bits (temp1) IN the prototype thus indicating that
1902 	 * this river route point is allowed to connect to it
1903 	 */
1904 	for(i=0; pi->proto->connects[i] != NOARCPROTO; i++)
1905 		pi->proto->connects[i]->temp1++;
1906 }
1907 
1908 #endif  /* ROUTTOOL - at top */
1909