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