1 /************************************************************
3 ** COPYRIGHT (C) 1993 UNIVERSITY OF PITTSBURGH
4 ** COPYRIGHT (C) 1996 GANNON UNIVERSITY
7 ** This software is distributed on an as-is basis
8 ** with no warranty implied or intended. No author
9 ** or distributor takes responsibility to anyone
10 ** regarding its use of or suitability.
12 ** The software may be distributed and modified
13 ** freely for academic and other non-commercial
14 ** use but may NOT be utilized or included in whole
15 ** or part within any commercial product.
17 ** This copyright notice must remain on all copies
18 ** and modified versions of this software.
20 ************************************************************/
23 /* file terminals.c */
24 /* ------------------------------------------------------------------------
25 * Terminal Placement routines stf 1/91
26 * Implemented as part of the incremental routing solution for SPAR
27 * MS Thesis work, UPittsburgh School of Engineering.
28 * ------------------------------------------------------------------------
30 #include "terminals.h" /* The conn structures, used to link modules to net fragments */
33 /*---------------------------------------------------------------
34 * Forward Declarations
35 *---------------------------------------------------------------
38 static int startX
, endX
; /* globals , of sorts */
39 /*===================================================================================*/
43 return(sr
->q2
- sr
->q1
);
45 /*===================================================================================*/
49 /* Return TRUE if the given tile spans the x-range specified by the variables
50 <startX> and <endX>, and has an empty arc (no module contained). */
52 if ((t
->x_pos
<= startX
) &&
53 (t
->x_pos
+ t
->x_len
>= endX
) &&
54 (emptyp_for_arcs(t
) == TRUE
)) return(TRUE
);
57 /*===================================================================================*/
58 connect
*create_connect(m
, sr
, crl
)
63 term
*t
= m
->terms
->this;
65 connect
*cn
= (connect
*)calloc(1, sizeof(connect
));
66 cn
->exit
= sr
; /* Fill in later */
67 cn
->up
= m
->y_size
- t
->y_pos
;
74 /*===================================================================================*/
75 int spans_overlapped_p(s1
, s2
)
78 /* Returns TRUE if the two spans overlapp in the least. */
79 srange
*r1
= s1
->exit
, *r2
= s2
->exit
;
80 if ((r1
->q2
+ s1
->up
>= r2
->q1
- s2
->down
) &&
81 (r1
->q1
- s1
->down
<= r2
->q1
+ s2
->up
)) return(TRUE
);
84 /*------------------------------------------------------------------------------------*/
88 /* Paint all of the corners that are fixed in the y dimension to terminals to
89 be painted with the terminal to whom they are fixed. */
95 n
= m
->terms
->this->nt
;
96 for(cl
= (crnlist
*)n
->route
; cl
!= NULL
; cl
= cl
->next
)
98 if (cl
->this->t
!= NULL
)
101 fixedRange
= cl
->this->cy
;
102 for (cll
= (crnlist
*)n
->route
; cll
!= NULL
; cll
= cll
->next
)
104 if (cll
->this->cy
== fixedRange
) cll
->this->t
= t
;
109 /*------------------------------------------------------------------------------------*/
110 int terminal_point_to_save(sr
, corners
)
115 int cy
= TILE_SPACE_Y_POS
; /* big negative number */
117 for (cl
= corners
; cl
!= NULL
; cl
= cl
->next
)
119 if (cl
->this->t
!= NULL
)
121 sr
->orient
= cl
->this->cy
->sr
->orient
;
122 if ((overlapped_p(cl
->this->cy
->sr
, sr
) == TRUE
) &&
123 (cl
->this->cy
->sr
->q1
> cy
))
125 cy
= cl
->this->cy
->sr
->q1
; /* Get the highest corner in the range */
131 /*------------------------------------------------------------------------------------*/
132 int insert_gap_between_sranges(sr1
, sr2
, gap
, crl1
, crl2
)
133 srange
*sr1
, *sr2
; /* sranges associated with each net that overlap */
134 int gap
; /* How much of a gap goes between the two */
135 crnlist
*crl1
, *crl2
; /* The corners that produced these ranges */
137 /* This puts <sr1> to the right of (above) <sr2> by <gap> */
138 int midPoint
, c1
, c2
, c
;
139 int min1
= sr1
->q1
, min2
= sr2
->q1
;
140 int max1
= sr1
->q2
, max2
= sr2
->q2
;
142 if (min2
== max2
) /* Handle the point cases - these are the most common */
144 if (min1
>= min2
+ gap
) return(TRUE
); /* <sr2> to right of <sr1> */
145 else if (max1
<= min2
- gap
) return(TRUE
); /* <sr1> to right of <sr2> */
146 else if (min1
<= min2
- gap
) /* fit <sr1> to right of <sr2> */
148 sr1
->q2
= min2
- gap
;
151 else if (max1
>= max2
+ gap
) /* fit <sr1> to left of <sr2> */
153 sr1
->q1
= max2
+ gap
;
156 else return(FALSE
); /* <sr1> doesn't fit!!! */
159 if (min1
== max1
) /* Handle the point cases - these are the most common */
161 if (min2
>= min1
+ gap
) return(TRUE
); /* <sr1> to right of <sr2> */
162 else if (max2
<= min1
- gap
) return(TRUE
); /* <sr2> to right of <sr1> */
163 else if (min2
<= min1
- gap
) /* fit <sr2> to right of <sr1> */
165 sr2
->q2
= min1
- gap
;
168 else if (max2
>= max1
+ gap
) /* fit <sr2> to left of <sr1> */
170 sr2
->q1
= max1
+ gap
;
173 else return(FALSE
); /* <sr1> doesn't fit!!! */
177 /* Is there any overlap? */
178 if ((max1
+ gap
< min2
) || (max2
+ gap
< min1
)) return(TRUE
); /* Fits already */
179 else if (min2
+ max1
< gap
+ 2) return(FALSE
); /* Can't fit */
181 midPoint
= (max2
+ min1
) / 2;
183 /* Set the beginning/end points of the sranges: */
184 if (max1
< midPoint
) min1
= sr1
->q1
= sr1
->q2
= min1
;
185 else if (min2
> midPoint
) max2
= sr2
->q1
= sr2
->q2
= min2
;
187 else if ( (midPoint
>= min2
) || ((max1
- min1
) >= (max2
- min2
)) )
188 { /* <sr1> goes to the right of <sr2> */
189 sr1
->q1
= MIN(MAX(min1
, midPoint
), max1
);
190 sr2
->q2
= MAX(MIN(midPoint
, max2
), min2
);
193 { /* <sr2> goes to the right of <sr1> */
194 sr2
->q1
= MIN(MAX(min1
, midPoint
), max2
);
195 sr1
->q2
= MAX(MIN(midPoint
, max2
), min1
);
197 /* now figure out how to fit the <gap> in: (It should fit) */
198 min1
= sr1
->q1
; min2
= sr2
->q1
;
199 max1
= sr1
->q2
; max2
= sr2
->q2
;
201 c1
= terminal_point_to_save(sr1
, crl1
); /* maintain corners whenever possible */
202 c2
= terminal_point_to_save(sr2
, crl2
);
204 if (((c1
== TILE_SPACE_Y_POS
) && (c2
== TILE_SPACE_Y_POS
)) ||
205 ((c1
!= TILE_SPACE_Y_POS
) && (c2
!= TILE_SPACE_Y_POS
) &&
206 (MAX(c1
, c2
) - MIN(c1
, c2
) <= gap
)) )
208 /* Ignore corner inclusion: */
209 /* put <sr1> to left of <sr2> with the gap midway between them */
212 if ((min1
<= midPoint
- gap
/2) && (max2
>= midPoint
+ gap
/2))
214 sr1
->q2
= midPoint
- gap
/2;
215 sr2
->q1
= midPoint
+ gap
/2;
217 else if (max2
>= min2
+ gap
) sr2
->q1
+= gap
; /* clip 2 */
218 else if (min1
<= max1
- gap
) sr1
->q2
-= gap
; /* clip 1 */
221 gap
-= (max2
- min2
);
227 else /* put <sr2> to left of <sr1> with the gap midway between them */
229 if (min1
>= midPoint
- gap
/2)
231 sr2
->q2
= midPoint
- gap
/2;
232 sr1
->q1
= midPoint
+ gap
/2;
234 else if (min2
<= max2
- gap
) sr2
->q2
-= gap
; /* clip 2 */
235 else if (max1
>= min1
+ gap
) sr1
->q1
+= gap
; /* clip 1 */
238 sr2
->q1
= max2
- (max2
- gap
- min1
)/2;
239 sr1
->q2
= min1
+ (max2
- gap
- min1
)/2;
244 else if ((c1
!= TILE_SPACE_Y_POS
) && (c2
!= TILE_SPACE_Y_POS
))
246 /* Deal with both corners */
247 /* put <sr1> to left of <sr2> with the gap midway between them */
248 if ((min1
<= midPoint
- gap
/2) && (max2
>= midPoint
+ gap
/2))
251 if ((c1
<= midPoint
- gap
/2) && (c2
>= midPoint
+ gap
/2))
253 sr1
->q2
= midPoint
- gap
/2;
254 sr2
->q1
= midPoint
+ gap
/2;
258 /* put <sr2> to left of <sr1> with the gap midway between them */
259 else if (min1
>= midPoint
- gap
/2) /* Can't trim sr1 */
261 if (c2
- gap
>= max1
) sr2
->q1
= sr2
->q2
= c2
;
263 else if ((c1
<= min1
+ (max2
- min1
- gap
)/2) &&
264 ((c2
>= max2
- (max2
- min1
- gap
)/2)))
266 sr1
->q2
= min1
+ (max2
- min1
- gap
)/2;
267 sr2
->q1
= max2
- (max2
- min1
- gap
)/2;
271 else if (max2
<= midPoint
+ gap
/2) /* Can't trim sr2 */
273 if (c1
+ gap
<= min2
) sr1
->q1
= sr1
->q2
= c1
;
278 /* See if they both work: */
279 else if ((c1
< c2
) && (c1
+ gap
<= c2
))
281 sr1
->q1
= sr1
->q2
= c1
;
282 sr1
->q2
= sr1
->q2
= c2
;
289 else /* deal with one corner or less */
291 if ((c1
!= TILE_SPACE_Y_POS
) && (c1
- gap
> min2
))
292 { /* Put <sr1> to the right of <sr2>, fixing <sr1> at point <c1>: */
293 sr1
->q1
= sr1
->q2
= c1
;
294 sr2
->q2
= MAX(min2
, MIN(c1
- gap
, max2
));
296 else if ((c2
!= TILE_SPACE_Y_POS
) && (c2
- gap
< max1
))
297 { /* put <sr1> to the right of <sr2>, fixing <sr2> at point <c2>: */
298 sr2
->q1
= sr2
->q2
= c2
;
299 sr1
->q1
= MIN(max1
, MAX(c2
+ gap
, min1
));
303 /* put <sr1> to left of <sr2> with the gap midway between them */
304 else if ((min1
<= midPoint
- gap
/2) && (max2
>= midPoint
+ gap
/2))
306 sr1
->q2
= midPoint
- gap
/2;
307 sr2
->q1
= midPoint
+ gap
/2;
309 /* put <sr2> to left of <sr1> with the gap midway between them */
310 else if (min1
>= midPoint
- gap
/2)
312 sr1
->q2
= midPoint
+ gap
/2;
313 sr2
->q1
= midPoint
- gap
/2;
317 sr2
->q1
= max2
- (max2
- gap
- min1
)/2;
318 sr1
->q1
= min1
+ (max2
- gap
- min1
)/2;
324 /*===================================================================================*/
325 int separate_spans(s1
, s2
)
328 /* return TRUE and modify the two spans if some legal selections of <s1>->exit
329 and <s2>->exit can be chosen so as to avoid overlap between the two:
331 srange
*r1
= s1
->exit
, *r2
= s2
->exit
;
333 if (((r1
->q2
+ s1
->up
> r2
->q1
- s2
->down
) &&
334 (r1
->q1
- s1
->down
< r2
->q1
+ s2
->up
)) ||
335 ((r1
->q2
+ s1
->up
< r2
->q1
- s2
->down
) &&
336 (r1
->q1
- s1
->down
> r2
->q1
+ s2
->up
)))
339 if ((r1
->q1
< r2
->q1
) || /* Put <r1> below <r2> */
340 ((r1
->q1
== r2
->q1
) && (r1
->q2
< r2
->q2
)))
342 if (srange_width(r1
) == 0)
344 if (r2
->q2
>= r1
->q2
+ s1
->up
+ s2
->down
) /* Close shave */
346 r2
->q1
= r1
->q2
+ s1
->up
;
348 else return(FALSE
); /* No Go */
350 else if (r1
->q1
+ r2
->q2
<= s1
->up
+ s2
->down
+ 2)
352 return(FALSE
); /* No Go */
354 else /* Normal Case */
356 return(insert_gap_between_sranges(r2
, r1
, s2
->up
+ s1
->down
,
357 s1
->corners
, s2
->corners
));
360 else /* Put <r2> below <r1> */
362 if (srange_width(r1
) == 0)
364 if (r1
->q2
>= r2
->q2
+ s2
->up
+ s1
->down
) /* Close shave */
366 r1
->q1
= r2
->q2
+ s2
->up
;
370 return(FALSE
); /* No Go */
373 else if (r2
->q1
+ r1
->q2
<= s2
->up
+ s1
->down
+ 2)
375 return(FALSE
); /* No Go */
379 return(insert_gap_between_sranges(r1
, r2
, s1
->up
+ s2
->down
,
380 s1
->corners
, s2
->corners
));
384 if((srange_width(r2
) < 0) || (srange_width(r1
) < 0))
386 return(FALSE
); /* Somethin's screwed */
388 else return(TRUE
); /* No overlap problems. */
390 else return(TRUE
); /* No overlap problems. */
392 /*===================================================================================*/
393 int descending_order(sp1
, sp2
)
396 /* Return TRUE iff sp1 is less than sp2 */
397 if (sp1
->exit
->q2
<= sp2
->exit
->q1
) return(TRUE
);
400 /*===================================================================================*/
401 int ascending_order(sp1
, sp2
)
404 /* Return TRUE iff sp1 is less than sp2 */
405 if (sp1
->exit
->q2
<= sp2
->exit
->q1
) return(FALSE
);
408 /*===================================================================================*/
409 int check_spanset_p(span
, spanSet
)
413 /* Return TRUE iff the given <span> fits in the <spanset> Make no alterations. */
415 int min1
= span
->exit
->q1
, min2
, max1
= span
->exit
->q2
, max2
;
417 if (spanSet
== NULL
) return(TRUE
);
419 sort_list(spanSet
, descending_order
);
420 for (srl
= spanSet
; srl
!= NULL
; srl
= srl
->next
) /* <spanSet> is sorted */
422 min2
= srl
->this->exit
->q1
;
423 max2
= srl
->this->exit
->q2
;
424 if (separate_spans(span
, srl
->this) != TRUE
)
427 span
->exit
->q1
= min1
; srl
->this->exit
->q1
= min2
;
428 span
->exit
->q2
= max1
; srl
->this->exit
->q2
= max2
;
432 { /* Repair side effects */
433 srl
->this->exit
->q1
= min2
; srl
->this->exit
->q2
= max2
;
437 span
->exit
->q1
= min1
; span
->exit
->q2
= max1
;
440 /*===================================================================================*/
441 int fits_in_spanset_p(span
, spanSet
)
445 /* Return TRUE iff the given <span> fits in the <spanset> Make no alterations. */
447 int min1
= span
->exit
->q1
, min2
, max1
= span
->exit
->q2
, max2
;
449 if (spanSet
== NULL
) return(TRUE
);
451 sort_list(spanSet
, descending_order
);
452 for (srl
= spanSet
; srl
!= NULL
; srl
= srl
->next
) /* <spanSet> is sorted */
454 min2
= srl
->this->exit
->q1
;
455 max2
= srl
->this->exit
->q2
;
456 if (separate_spans(span
, srl
->this) != TRUE
)
459 span
->exit
->q1
= min1
; srl
->this->exit
->q1
= min2
;
460 span
->exit
->q2
= max1
; srl
->this->exit
->q2
= max2
;
463 if (span
->exit
->q2
< min2
) break;
467 /*===================================================================================*/
468 int unobstructed_p(vertSRange
, horzSRange
, span
, usedSpans
, exitSide
)
469 srange
*vertSRange
, *horzSRange
;
475 /* Return TRUE if the some of the given <vertSRange> casn be traced from <horzSRange>
476 to the given <exitSide> of the page. If it can, correct the <vertSRange> to the
477 part of the range that will connect. */
479 int yExtent
= srange_width(vertSRange
), xExtent
;
482 tile
*corn
, *lasTile
= NULL
;
483 tilist
*tl
, *marker
, *goodTiles
= NULL
;
485 /* Set up the local span variables. These are used to verify the usefulness
486 of a located <horzSRange> so that a good one is returned, if one exists. */
487 vSRange
.orient
= VERT
;
488 vSpan
.exit
= &vSRange
;
490 vSpan
.down
= span
->down
;
491 vSpan
.mod
= span
->mod
;
492 vSpan
.corners
= span
->corners
;
494 /* The <vertSRange>, <horzSRange> and the <exitSide> determine a rectangle that can
495 be searched to see if there is anything that spans the distance:
498 if (exitSide
== RIGHT
)
500 corn
= find_LRHC(routingRoot
[0][HORZ
]);
501 xExtent
= corn
->x_pos
+ corn
->x_len
- horzSRange
->q1
;
505 corn
= find_ULHC(routingRoot
[0][HORZ
]);
506 xExtent
= corn
->x_pos
- horzSRange
->q2
;
509 /* Set the span range for the filter function: */
510 startX
= MIN(horzSRange
->q1
, horzSRange
->q1
+ xExtent
);
511 endX
= MAX(horzSRange
->q1
, horzSRange
->q1
+ xExtent
);
513 area_enumerate(corn
, &goodTiles
, spans_range_p
,
514 horzSRange
->q1
, vertSRange
->q1
,xExtent
, yExtent
);
516 /* Something to deal with - form the real continuous span from this info: */
517 if (exitSide
== LEFT
)
518 sort_list(goodTiles
, most_up
); /* Start placing outputs to LL */
520 sort_list(goodTiles
, most_down
); /* Start placing inputs to UR */
522 /* Set up the loop stuff: */
524 while(marker
!= NULL
)
526 lasTile
= marker
->this;
527 vSRange
.q1
= lasTile
->y_pos
;
528 vSRange
.q2
= lasTile
->y_pos
+ lasTile
->y_len
;
531 /* Setup the next contiunous, unobstructed vertical srange: */
532 while ((tl
!= NULL
) && (adjacent_tiles_p(tl
->this, lasTile
) == TRUE
))
534 /* Now find the maximum y-span available. (Best-First) */
535 vSRange
.q1
= MIN(vSRange
.q1
, tl
->this->y_pos
);
536 vSRange
.q2
= MAX(vSRange
.q2
, tl
->this->y_pos
+ tl
->this->y_len
);
537 lasTile
= tl
->this; /* Advance the loop index */
540 marker
= tl
; /* Update the marker */
542 /* Check to see if this unobstructed range will work: */
543 if (fits_in_spanset_p(&vSpan
, usedSpans
) == TRUE
)
545 /* Reset the range to that which is unobstructed */
546 vertSRange
->q1
= vSRange
.q1
;
547 vertSRange
->q2
= vSRange
.q2
;
548 free_list(goodTiles
);
551 /* Otherwise, Loop again to see if there is another one that will work */
553 free_list(goodTiles
);
556 /*===================================================================================*/
557 crnlist
*find_next_closest_range(vertSRange
, horzSRange
, orderedCorners
)
558 srange
*vertSRange
, **horzSRange
;
559 crnlist
**orderedCorners
;
561 /* Given the list of <orderedCorners> to chose from, pop the next set of corners
562 that shares the same <horzSRange>. From this set of corners, fill in the superset
563 of xpositions into the <vertSRange> slots. Stuff the corner(s) used to create
564 this range into a list and return it.
566 LOTS OF SIDE EFFECTS!!!
569 crnlist
*cl
, *used
= NULL
;
571 if (*orderedCorners
!= NULL
)
573 xR
= (*orderedCorners
)->this->cx
;
574 vertSRange
->q1
= (*orderedCorners
)->this->cy
->sr
->q1
;
575 vertSRange
->q2
= (*orderedCorners
)->this->cy
->sr
->q2
;
577 for(cl
= *orderedCorners
; ((cl
!= NULL
) && (cl
->this->cx
== xR
));
578 cl
= *orderedCorners
)
580 /* Shorten <orderedCorners>, lengthen <used> & update the <vertSRange> : */
581 trans_item(cl
->this, orderedCorners
, &used
);
582 vertSRange
->q1
= MIN(vertSRange
->q1
, cl
->this->cy
->sr
->q1
);
583 vertSRange
->q2
= MAX(vertSRange
->q2
, cl
->this->cy
->sr
->q2
);
585 *horzSRange
= xR
->sr
;
589 else /* Given nothing to work with */
597 /*===================================================================================*/
598 term
*select_non_systerm(terms
, side
)
602 /* Return the first non-system terminal. */
605 term
*closest
= NULL
;
607 int mType
, base
, smallestDist
;
609 if (side
== RIGHT
) corn
= find_LRHC(routingRoot
[0][HORZ
]);
610 else corn
= find_ULHC(routingRoot
[0][HORZ
]);
611 base
= (side
== LEFT
) ? corn
->x_pos
: corn
->x_pos
+ corn
->x_len
;
614 for (tl
= terms
; tl
!= NULL
; tl
= tl
->next
)
616 mType
= validate(tl
->this->mod
->type
);
617 if ((mType
!= INPUT_SYM
) && (mType
!= OUTPUT_SYM
) &&
618 (mType
!= INOUT_SYM
))
621 if ((abs(base
- m
->x_pos
- tl
->this->x_pos
) <= smallestDist
) ||
622 (smallestDist
== -1));
625 smallestDist
= abs(base
- m
->x_pos
- closest
->x_pos
);
630 fprintf(stderr
, "error in select_non_systerm --> no terminal found!\n");
634 /*===================================================================================*/
636 srange
*locate_best_placement_range_for_systerm(span
, fromSide
, usedSpans
)
637 connect
*span
; /* The Span being built */
638 int fromSide
; /* LEFT or RIGHT */
641 /* This is a best-first algorithm; Other (collective) limitations are not
642 included (yet). Probably a running list of available ranges should be maintained
643 and checked against in the "unobstructed_p" function.
645 module
*systerm
= span
->mod
;
646 srange
*dummyVRange
, *dummyHRange
;
647 net
*n
= systerm
->terms
->this->nt
;
649 crnlist
*cl
, *AllCorners
, *used
;
653 if (fromSide
== RIGHT
)
655 AllCorners
= (crnlist
*)rcopy_list(sort_list(n
->route
, in_x_order
));
659 AllCorners
= (crnlist
*)copy_list(sort_list(n
->route
, in_x_order
));
662 if (AllCorners
== NULL
) /* There is only one terminal connected, so fake it : */
664 t
= select_non_systerm(n
->terms
, fromSide
);
665 refX
= t
->x_pos
+ t
->mod
->x_pos
;
666 refY
= t
->y_pos
+ t
->mod
->y_pos
;
667 c
= create_corner(create_range(create_srange(refX
, refX
, VERT
), n
),
668 create_range(create_srange(refY
, refY
, HORZ
), n
), NULL
, t
);
669 push(c
, &AllCorners
);
671 for (cl
= AllCorners
; cl
!= NULL
; cl
= cl
->next
)
673 /* Walk through the corner list, and find the left/right-most unobstructed
675 /* First, create the dummy range to fill: */
676 dummyVRange
= create_srange(0, 0, VERT
);
678 /* Next fill the range: */
679 used
= find_next_closest_range(dummyVRange
, &dummyHRange
, &AllCorners
);
681 while((AllCorners
!= NULL
) && (srange_width(dummyHRange
) > 0))
683 span
->corners
= used
;
684 if (unobstructed_p(dummyVRange
, dummyHRange
, span
, usedSpans
, fromSide
)
687 span
->exit
= dummyHRange
;
688 if (fits_in_spanset_p(span
, usedSpans
) == TRUE
)
690 /* If there is a corner in this span, pick the highest one and
691 fix the location to it: */
692 refY
= terminal_point_to_save(dummyVRange
, span
->corners
);
693 if (refY
!= TILE_SPACE_Y_POS
)
695 dummyVRange
->q1
= dummyVRange
->q2
= refY
;
697 span
->exit
= dummyVRange
;
702 used
= find_next_closest_range(dummyVRange
, &dummyHRange
, &AllCorners
);
705 span
->corners
= used
;
706 if (unobstructed_p(dummyVRange
, dummyHRange
, span
, usedSpans
, fromSide
) == TRUE
)
708 span
->exit
= dummyVRange
;
709 if (fits_in_spanset_p(span
, usedSpans
) == TRUE
)
711 refY
= terminal_point_to_save(dummyVRange
, span
->corners
);
712 if (refY
!= TILE_SPACE_Y_POS
)
714 dummyVRange
->q1
= dummyVRange
->q2
= refY
;
716 span
->exit
= dummyVRange
;
721 span
->exit
= dummyVRange
; /* Give it something to work with */
722 return(NULL
); /* Notify that this range doesn't fit */
724 /*===================================================================================*/
725 int falls_in_srange_p(x
, sr
)
729 if ((sr
->q1
<= x
) && (x
<= sr
->q2
)) return(TRUE
);
732 /*===================================================================================*/
733 int fits_in_before(sp
, fixedSpan
, side
, usedSpans
)
734 connect
*sp
, *fixedSpan
;
738 int p
= sp
->exit
->q1
;
740 srange dummyXRange
, dummyYRange
;
742 /* First see if a range can be found between <p> and <fixedSpan>->exit in which
744 if (p
> fixedSpan
->exit
->q1
)
746 dummyYRange
.q1
= fixedSpan
->exit
->q2
; dummyYRange
.q2
= p
;
750 dummyYRange
.q1
= p
; dummyYRange
.q2
= fixedSpan
->exit
->q1
;
753 /* find the nearest (horizontally) terminal to line up on. */
754 closesTerm
= select_non_systerm(sp
->mod
->terms
->this->nt
->terms
, side
);
755 dummyXRange
.q1
= dummyXRange
.q2
= closesTerm
->mod
->x_pos
+ closesTerm
->x_pos
;
757 if (unobstructed_p(&dummyYRange
, &dummyXRange
, sp
, usedSpans
, side
) == TRUE
)
759 sp
->exit
->q1
= dummyYRange
.q1
;
760 sp
->exit
->q2
= dummyYRange
.q2
;
761 if (fits_in_spanset_p(sp
, usedSpans
) == TRUE
) return(TRUE
);
764 /* Otherwise try fitting <sp> immediately before <fixedSpan> */
765 sp
->exit
->q2
= fixedSpan
->exit
->q1
- sp
->up
- fixedSpan
->down
;
766 sp
->exit
->q1
= sp
->exit
->q2
;
767 return (fits_in_spanset_p(sp
, usedSpans
));
769 /*===================================================================================*/
770 int fits_in_after(sp
, fixedSpan
, side
, usedSpans
)
771 connect
*sp
, *fixedSpan
;
775 int p
= sp
->exit
->q1
;
777 srange dummyXRange
, dummyYRange
;
779 /* First see if a range can be found between <p> and <fixedSpan>->exit in which
781 if (p
> fixedSpan
->exit
->q1
)
783 dummyYRange
.q1
= fixedSpan
->exit
->q2
; dummyYRange
.q2
= p
;
787 dummyYRange
.q1
= p
; dummyYRange
.q2
= fixedSpan
->exit
->q1
;
790 /* find the nearest (horizontally) terminal to line up on. */
791 closesTerm
= select_non_systerm(sp
->mod
->terms
->this->nt
->terms
, side
);
792 dummyXRange
.q1
= dummyXRange
.q2
= closesTerm
->mod
->x_pos
+ closesTerm
->x_pos
;
794 if (unobstructed_p(&dummyYRange
, &dummyXRange
, sp
, usedSpans
, side
) == TRUE
)
796 sp
->exit
->q1
= dummyYRange
.q1
;
797 sp
->exit
->q2
= dummyYRange
.q2
;
798 if (fits_in_spanset_p(sp
, usedSpans
) == TRUE
) return(TRUE
);
801 /* Otherwise, try fitting <sp> immediately after <fixedSpan> */
802 sp
->exit
->q1
= fixedSpan
->exit
->q2
+ sp
->down
+ fixedSpan
->up
;
803 sp
->exit
->q2
= sp
->exit
->q1
;
804 return(fits_in_spanset_p(sp
, usedSpans
));
806 /*===================================================================================*/
807 fit_into_available_space(sp
, side
, usedSpans
)
810 connlist
**usedSpans
;
812 /* find something near sp->exit that will accomodate <sp> in <usedSpans> */
815 connlist
*before
= NULL
, *after
= NULL
;
816 connlist
*cnl
, *bl
, *al
;
818 center_range_on_single_point(sp
->exit
);
820 sort_list(*usedSpans
, descending_order
);
822 /* Create a list of spans that occur <before> and <after> <sp>. The break occurs
823 before the span near where <sp> wants to fall: */
824 for (cnl
= *usedSpans
; cnl
!= NULL
; cnl
= cnl
->next
)
826 if ((falls_in_srange_p(p
, cnl
->this->exit
) == TRUE
) ||
827 (p
< cnl
->this->exit
->q1
))
834 push(cnl
->this, &before
);
838 /* (useAveraging == TRUE)?? Something to try later... */
840 if ((after
!= NULL
) && (before
!= NULL
))
842 /* Which is closer? */
843 if ((after
->this->exit
->q1
- p
) < (p
- before
->this->exit
->q2
))
845 /* after->this is, so try next to there first: */
846 if (fits_in_before(sp
, after
->this, side
, *usedSpans
) == TRUE
)
854 if (fits_in_after(sp
, before
->this, side
, *usedSpans
) == TRUE
)
863 /* Toggle back and forth between the before & after lists looking for a
864 legal place to insert <sp>: */
867 while ((al
!= NULL
) && (bl
!= NULL
))
869 if ((bl
== NULL
) || /* No before list left... */
870 (((al
!= NULL
) && (bl
!= NULL
)) && /* the <al> entry is closer */
871 ((al
->this->exit
->q1
- p
) < (p
- bl
->this->exit
->q2
))))
873 if ((fits_in_before(sp
, al
->this, side
, *usedSpans
) == TRUE
) ||
874 (fits_in_after(sp
, al
->this, side
, *usedSpans
) == TRUE
))
882 if ((al
== NULL
) || /* no after list left... */
883 ((al
!= NULL
) && (bl
!= NULL
))) /* the <bl> entry is closer */
885 if ((fits_in_after(sp
, bl
->this, side
, *usedSpans
) == TRUE
) ||
886 (fits_in_before(sp
, bl
->this, side
, *usedSpans
) == TRUE
))
895 /* If you get this far, <sp> could not be fit into the middle of <usedSpans> */
896 /* Force it on the end somewhere */
899 for (cnl
= after
; ((cnl
!= NULL
) && (cnl
->next
!= NULL
)); cnl
= cnl
->next
);
902 ((cnl
->this->exit
->q1
- p
) < (p
- bl
->this->exit
->q2
)))
904 /* if closer to the top of the page: */
905 sp
->exit
->q1
= cnl
->this->exit
->q2
+ sp
->down
+ cnl
->this->up
;
906 sp
->exit
->q2
= sp
->exit
->q1
;
910 /* force it to the begining of <usedSpans>: */
911 sp
->exit
->q2
= bl
->this->exit
->q1
- sp
->up
- bl
->this->down
;
912 sp
->exit
->q1
= sp
->exit
->q2
;
914 push(sp
, usedSpans
); /* It Better Fit!! BB Problems??? */
918 /*===================================================================================*/
919 repair_failed_spans(failedSpans
, side
, goodSpans
)
920 connlist
*failedSpans
;
922 connlist
**goodSpans
;
928 sort_list(failedSpans
, ascending_order
);
929 for (cnl
= failedSpans
; cnl
!= NULL
; cnl
= cnl
->next
)
932 if (*goodSpans
== NULL
) push(span
, goodSpans
);
933 else fit_into_available_space(span
, side
, goodSpans
);
936 /*===================================================================================*/
937 verify_all_spans(goodSpans
, side
, spanStillScrewed
)
938 connlist
**goodSpans
;
940 connlist
**spanStillScrewed
;
944 connlist
*master
= NULL
, *cnl
;
946 master
= (connlist
*)copy_list(sort_list(*goodSpans
, ascending_order
));
947 for (cnl
= master
; cnl
!= NULL
; cnl
= cnl
->next
)
949 span
= (connect
*)rem_item(cnl
->this, goodSpans
);
950 if (fits_in_spanset_p(span
, *goodSpans
) == TRUE
) push(span
, goodSpans
);
953 fit_into_available_space(span
, side
, goodSpans
);
954 push(span
, spanStillScrewed
);
959 /*===================================================================================*/
960 int locate_systerm(span
, x_pos
)
964 /* Finds and sets the best Y location for this module: use the given span info
966 (1) Pick a corner. Highest corner is prefered for inputs, lowest for outputs
967 (2) Pick the center of the range spanned by the corners chosen
968 (3) Pick the center of the available exit range
971 int min
, max
, cornerY
;
976 if ((span
== NULL
) || (span
->exit
== NULL
)) return(FALSE
);
980 min
= span
->exit
->q1
;
981 max
= span
->exit
->q2
;
983 /* Rule (0) -- Use terminal poins */
984 cornerY
= terminal_point_to_save(exit
, span
->corners
);
985 if (cornerY
!= TILE_SPACE_Y_POS
)
987 systerm
->y_pos
= cornerY
- span
->down
;
988 systerm
->x_pos
= x_pos
;
989 exit
->q1
= exit
->q2
= cornerY
;
994 for (cl
= span
->corners
; cl
!= NULL
; cl
= cl
->next
)
996 cornerY
= cl
->this->cy
->sr
->q1
;
998 /* If there is a corner that connects inside the exit range, use it: */
999 if (falls_in_srange_p(cornerY
, exit
) == TRUE
)
1002 systerm
->y_pos
= cornerY
- span
->down
;
1003 systerm
->x_pos
= x_pos
;
1004 exit
->q1
= exit
->q2
= cornerY
;
1007 min
= MIN(cornerY
, min
); /* Expand the range that the term can fall in */
1008 max
= MAX(cornerY
, max
);
1011 if (falls_in_srange_p((min
+max
)/2, exit
) == TRUE
)
1013 systerm
->y_pos
= (min
+max
)/2 - span
->down
;
1014 systerm
->x_pos
= x_pos
;
1015 exit
->q1
= exit
->q2
= (min
+max
)/2;
1018 else if (falls_in_srange_p((min
+max
+1)/2, exit
) == TRUE
)
1020 systerm
->y_pos
= (min
+max
+1)/2 - span
->down
;
1021 systerm
->x_pos
= x_pos
;
1022 exit
->q1
= exit
->q2
= (min
+max
+1)/2;
1028 center_range_on_single_point(exit
); /* see "local_route.c" */
1029 systerm
->y_pos
= exit
->q1
- span
->down
;
1030 systerm
->x_pos
= x_pos
;
1034 /*===================================================================================*/
1035 set_spans(spans
, x_pos
, leftovers
, base
, height
)
1038 mlist
**leftovers
; /* Things not dealt with that should have been */
1044 /* Now that valid ranges have been set up, localize the ranges */
1045 for (col
= spans
; col
!= NULL
; col
= col
->next
)
1047 /* Now use this information to place the modules. Any terminal with an entry
1048 sould be placed directly. Anything with a NULL ->exit field needs to be
1049 handled seperately. */
1051 locate_systerm(col
->this, x_pos
);
1052 if (col
->this->exit
== NULL
)
1055 m
->placed
= UNPLACED
;
1059 /* Create the fuzzy (delayed-evaluation) position... (not quite right) */
1060 m
->fx
->item1
= create_int_varStruct(&m
->x_pos
);
1061 m
->fy
->item1
= create_int_varStruct(&m
->y_pos
);
1063 /* record the base & height values (for BB calculation) */
1064 *base
= MIN(*base
, col
->this->exit
->q1
- col
->this->down
- CHANNEL_HEIGHT
);
1065 *height
= MAX(*height
, col
->this->exit
->q2
+ col
->this->up
-
1066 *base
+ CHANNEL_HEIGHT
);
1071 /*===================================================================================*/
1072 /*---------------------------------------------------------------
1073 * place_systerm_partitions(part, x_pos) (Level 2)
1074 * place the modules in the given partition, given that all those in
1075 * partitions[0] have been placed AND ROUTED (See "local_route.c")
1077 * This is supposed to use the routing and terminal locations available to
1078 * place the given terminals on the edge of the page (The x position given)
1080 * So here is the plan:
1081 Find the list of terminals to be placed, and then see if there are nets associated
1082 with them extant in the (routed) partition[0]. There will either be a wire (corner
1083 list) or at least a terminal.
1085 now the trick is to align as many terminals as possible on _unobstructed_ corners.
1086 So, what is an _unobstructed_ corner? It is one in which no bends are required
1087 to connect to it. Properly done, this process should result in a set of modules
1088 and a (vertical) range to tie them to. Based on these range, place the modules.
1089 Anything without a placement range still needs to be placed as well, and there is
1090 the problem of insuring that the various ranges do not force the modules to
1093 *---------------------------------------------------------------
1095 place_systerm_partitions(part
, x_pos
, bb_base
, bb_height
)
1097 int *bb_base
, *bb_height
;
1101 mlist
*ml
, *mml
, *leftovers
= NULL
;
1104 connlist
*col
, *screwedSpans
= NULL
, *bestSpans
= NULL
;
1106 /* The partition number indexes either the input system terminals, or the
1107 output system terminals. (see "place.c") */
1108 for (ml
= partitions
[part
]; ml
!= NULL
; ml
= ml
->next
)
1110 /* Reset the terminal information within the net structures: */
1111 add_terms_to_nets(ml
->this);
1112 paint_corners(ml
->this);
1114 newSpan
= create_connect(ml
->this, NULL
, NULL
);
1116 /* Find the best unobstructed range in which to place this module,
1117 and push it onto the <bestRanges> list */
1118 if (part
== partition_count
+ 1) side
= RIGHT
;
1121 sr
= locate_best_placement_range_for_systerm(newSpan
, side
, bestSpans
);
1126 queue(newSpan
, &bestSpans
);
1130 if (debug_level
> 0)
1131 fprintf(stderr
, "Placement will be irregular for system terminal <%s>.\n",
1133 /* Now mark the span, so it can be fitted later: */
1134 push(newSpan
, &screwedSpans
);
1138 /* Now fix those that we are happy with: */
1139 set_spans(bestSpans
, x_pos
, &leftovers
, bb_base
, bb_height
);
1141 /* Now find a way to adjust the failed spans so they will fit: */
1142 repair_failed_spans(screwedSpans
, side
, &bestSpans
);
1143 set_spans(screwedSpans
, x_pos
, &leftovers
, bb_base
, bb_height
);
1145 screwedSpans
= (connlist
*)free_list(screwedSpans
);
1146 verify_all_spans(&bestSpans
, side
, &screwedSpans
);
1147 set_spans(screwedSpans
, x_pos
, &leftovers
, bb_base
, bb_height
);
1149 if (leftovers
!= NULL
)
1151 fprintf(stderr
, "WARNING: System Terminals on the %s side may overlap.\n",
1156 for (ml
= partitions
[part
]; ml
!= NULL
; ml
= ml
->next
)
1158 /* move the partition to partition 0 */
1159 partitions
[0] = (mlist
*)concat_list(ml
->this, partitions
[0]);
1161 /* and mark it as placed */
1162 ml
->this->placed
= PLACED
;
1164 free_list(screwedSpans
);
1165 free_list(leftovers
);
1166 free_list(bestSpans
);
1168 /*===================================================================================*/
1169 /*---------------------------------------------------------------
1170 * fine_systerm_placement (Level 1)
1171 * Put all the partitions into one bounding box in partition 0,
1172 * based on picking the largest number of connections off the diagonal
1173 * of the connection matrix; (which has been built to match the
1174 * partitions, seen as clusters)
1175 *---------------------------------------------------------------
1177 mlist
*fine_systerm_placement(x1
, y1
, x2
, y2
)
1178 int *x1
, *y1
, *x2
, *y2
; /* The current Bounding Box */
1180 /* Now there are three partitions: 0, pc+1, & pc+2, which contain the (now placed)
1181 * internal modules, the output only system terminals, and the remaining systerms.
1182 * These remaining two sets of unplaced modules are placed using the information found by
1183 * examining the placement of the internal modules. NOTE: The systerms have been
1184 * 'placed' by the boxing routines, so the information within the mod structures must
1188 int outputColumn
= *x2
- CHANNEL_LENGTH
- SYSTERM_SIZE
;
1189 int inputColumn
= *x1
+ CHANNEL_LENGTH
;
1190 int yP
= *y1
, yL
= *y2
- *y1
;
1192 /* Reset the placement information within the module structures: */
1194 /* place the systerm modules within their partitions: */
1195 place_systerm_partitions(partition_count
+ 2, inputColumn
, &yP
, &yL
);
1196 place_systerm_partitions(partition_count
+ 1, outputColumn
, &yP
, &yL
);
1198 /* cleanup the bounding box (ganz wigtig! very important!) */
1201 /* if (debug_level != 0) */
1202 fprintf(stderr
, "Adjusting Bounding Box base from (%d,%d) to (%d,%d)\n",
1203 *x1
, *y1
, *x1
, yP
- CHANNEL_HEIGHT
);
1204 *y1
= yP
- CHANNEL_HEIGHT
;
1205 *y2
+= CHANNEL_HEIGHT
;
1207 if (*y2
- *y1
!= yL
)
1209 /* if (debug_level != 0) */
1210 fprintf(stderr
, "Adjusting Bounding Box top from (%d,%d) to (%d,%d)\n",
1211 *x2
, *y2
, *x2
, yL
- yP
);
1212 *y2
= yL
- *y1
+ CHANNEL_HEIGHT
;
1215 /* build the return list: */
1216 return((mlist
*)append_list(rcopy_list(partitions
[partition_count
+2]),
1217 rcopy_list(partitions
[partition_count
+1])));
1220 /*===================================================================================*/
1222 mlist
*make_room_for_systerm_placement(systermNets
, x1
, y1
, x2
, y2
)
1223 nlist
**systermNets
;
1224 int *x1
, *y1
, *x2
, *y2
;
1226 /* Use the old systerm placement routine, so as to allow enough room for the
1227 system terminals. The main purpose is to set xfloor, yfloor, etc. for
1228 partition 0; Also assigns X columns for systerm placement.
1231 mlist
*ml
, *systerms
= NULL
;
1232 systerms
= (mlist
*)append_list(rcopy_list(partitions
[partition_count
+2]),
1233 rcopy_list(partitions
[partition_count
+1]));
1234 expand_bounding_box_for_systerms(x1
, y1
, x2
, y2
);
1235 for (ml
= systerms
; ml
!= NULL
; ml
= ml
->next
)
1237 push(ml
->this->terms
->this->nt
, systermNets
);
1242 /*===================================================================================*/
1244 expand_bounding_box_for_systerms(x1
, y1
, x2
, y2
)
1245 int *x1
, *y1
, *x2
, *y2
;
1247 /* Determine the new bounding box llhc and urhc: */
1249 int bestX
, max_wid
= 0, max_height
= 0;
1250 int left
= partition_count
+ 2, right
= partition_count
+ 1;
1251 int noInputs
, noOutputs
, maxCount
;
1253 noInputs
= list_length(partitions
[left
]);
1254 noOutputs
= list_length(partitions
[right
]);
1255 maxCount
= MAX(noInputs
, noOutputs
);
1257 *y1
= yfloor
- CHANNEL_HEIGHT
; /* - (SYSTERM_SIZE) * maxCount; */
1258 *y2
= *y1
+ y_sizes
[0] + CHANNEL_HEIGHT
;
1259 /* 2 * (CHANNEL_HEIGHT + (SYSTERM_SIZE) * maxCount); */
1261 *x1
= xfloor
- CHANNEL_LENGTH
- noInputs
- SYSTERM_SIZE
;
1262 *x2
= *x1
+ x_sizes
[0] + 2 * (CHANNEL_LENGTH
+ noInputs
+ SYSTERM_SIZE
);
1265 /*===================================================================================*/
1267 /*---------------------------------------------------------------
1268 * gross_systerm_placement (Level 1)
1269 * Put all the partitions into one bounding box in partition 0,
1270 * based on picking the largest number of connections off the diagonal
1271 * of the connection matrix; (which has been built to match the
1272 * partitions, seen as clusters)
1273 *---------------------------------------------------------------
1275 mlist
*gross_systerm_placement(x1
, y1
, x2
, y2
)
1276 int *x1
, *y1
, *x2
, *y2
;
1278 /* Now there are three partitions: 0, pc+1, & pc+2, which contain the (now placed)
1279 * internal modules, the output only system terminals, and the remaining systerms.
1280 * These remaining two sets of unplaced modules are placed using the information found by
1281 * examining the placement of the internal modules. NOTE: The systerms have been
1282 * 'placed' by the boxing routines, so the information within the mod structures must
1286 /* Reset the placement information within the module structures:
1287 This is the OLD placement algorithm. It is not good, but it will complete, and serve
1288 well as a space-holder function. These results will need to be overwritten later.
1291 /* place the systerm modules within their partitions: */
1292 old_place_systerm_partitions(partition_count
+ 2, xfloor
); /* input terminals */
1293 old_place_systerm_partitions(partition_count
+ 1, x_sizes
[0]); /* output terminals */
1296 if((xfloor
< 0)||(yfloor
< 0))
1298 reset_borders(xfloor
,yfloor
);
1300 /* put the lower left corner of the box back at 0,0 */
1301 fixup_partition(0, xfloor
, yfloor
);
1304 /* build the return list: */
1305 return((mlist
*)append_list(rcopy_list(partitions
[partition_count
+2]),
1306 rcopy_list(partitions
[partition_count
+1])));
1308 /*===================================================================================*/
1309 /*---------------------------------------------------------------
1310 * old_place_systerm_partitions(part, x_pos) (Level 2)
1311 * place the modules in p1, given that all those in <p2> have already been
1312 * put down. TOO MESSY TO DESCRIBE!
1313 *---------------------------------------------------------------
1315 old_place_systerm_partitions(part
, x_pos
)
1319 int ysum
, count
, y_pos
, y_max
= 0, x_max
= 0;
1320 int temp
, max_wid
= 0, max_height
= 0, placement_ok
= FALSE
;
1321 int left_side
= partition_count
+ 2, right_side
= partition_count
+ 1;
1324 int systermX
, systermY
, lineupX
, placement_set
, bestX
;
1326 for (ml
= partitions
[part
]; ml
!= NULL
; ml
= ml
->next
)
1328 /* Reset the terminal information within the net structures: */
1329 add_terms_to_nets(ml
->this);
1331 /* walk through the list of modules in this partition, and find their ideal
1332 vertical location wrt partition 0, the set of already-placed partitions. */
1334 bestX
= x_sizes
[0] - xfloor
; /* used to choose the best term to line up on */
1335 placement_set
= FALSE
;
1336 max_wid
= MAX(ml
->this->x_size
, max_wid
);
1337 max_height
= MAX(ml
->this->y_size
, max_height
);
1339 for (tl
= ml
->this->terms
; tl
!= NULL
; tl
= tl
->next
)
1340 /* typically there's only one */
1342 /* Average the position amongst the terminal positions on the net */
1345 for (ttl
= tl
->this->nt
->terms
; ttl
!= NULL
; ttl
= ttl
->next
)
1347 if ((ttl
->this->mod
!= tl
->this->mod
) &&
1348 (((part
== left_side
) && (ttl
->this->type
!= OUT
)) ||
1349 ((part
== right_side
) && (ttl
->this->type
== OUT
))))
1351 ysum
+= ttl
->this->mod
->y_pos
+ ttl
->this->y_pos
;
1353 /* Try lining up on the first source (desination) terminal*/;
1354 y_pos
= ttl
->this->mod
->y_pos
+ ttl
->this->y_pos
- tl
->this->y_pos
;
1356 /* save the distance to this module, as we want the closest one.*/
1357 lineupX
= ttl
->this->mod
->x_pos
;
1359 /* save it's position (if it's ok, we'll keep it) */
1360 systermY
= y_pos
; /* (int)(ysum / count); */
1361 systermX
= (part
== right_side
) ?
1362 x_pos
+ (WHITE_SPACE
* count_terms_part(part
, LEFT
)) :
1363 x_pos
- ml
->this->x_size
-
1364 (WHITE_SPACE
* count_terms_part(part
, RIGHT
));
1366 /* Look for conflicts amongst the already-placed systerm modules: */
1367 for (mml
= partitions
[part
]; (mml
!= NULL
);)
1369 if (((mml
->this != ml
->this) && (mml
->this->placed
== PLACED
))
1371 (!((mml
->this->y_pos
>=
1372 systermY
+ ml
->this->y_size
) ||
1373 (mml
->this->y_pos
+ mml
->this->y_size
<=
1376 /* there's a problem, so fix it. */
1377 placement_ok
= FALSE
;
1382 placement_ok
= TRUE
; /* keep checking */
1386 if (placement_ok
== TRUE
) /* got a good one, so save whilst ahead */
1388 if(abs(lineupX
- x_pos
) <= bestX
)
1390 bestX
= abs(lineupX
- x_pos
);
1391 y_max
= MAX(y_max
, systermY
);
1392 x_max
= MAX(x_max
, systermX
);
1393 ml
->this->x_pos
= systermX
;
1394 ml
->this->y_pos
= systermY
;
1395 placement_set
= TRUE
;
1397 /* Create the fuzzy (delayed-evaluation) position...
1398 (not quite right) */
1399 ml
->this->fx
->item1
= create_int_varStruct(&ml
->this->x_pos
);
1400 ml
->this->fy
->item1
= create_int_varStruct(&ml
->this->y_pos
);
1402 /* now keep looking (see if there is a closer one) */
1409 if (placement_set
== FALSE
)
1411 ml
->this->x_pos
= systermX
;
1412 ml
->this->y_pos
= systermY
;
1414 /* Create the fuzzy (delayed-evaluation) position... (not quite right) */
1415 ml
->this->fx
->item1
= create_int_varStruct(&ml
->this->x_pos
);
1416 ml
->this->fy
->item1
= create_int_varStruct(&ml
->this->y_pos
);
1418 /* The module in question <ml->this> has now been placed in a (hopefully)
1419 legal position amongst its brother systerms. This should be a lineup on
1420 the closest terminal that will yield a known legal position. This may
1421 not have worked, so the following code is to insure that a legal position
1424 /* Check again for conflicts amongst the already-placed systerm modules: */
1425 for (mml
= partitions
[part
]; (mml
!= NULL
);)
1427 if (((mml
->this != ml
->this) && (mml
->this->placed
== PLACED
))
1429 (!((mml
->this->y_pos
>
1430 ml
->this->y_pos
+ ml
->this->y_size
) ||
1431 (mml
->this->y_pos
+ mml
->this->y_size
<
1434 /* there's a problem, so fix it. (brutal) */
1435 ml
->this->y_pos
= CHANNEL_HEIGHT
+ mml
->this->y_size
+
1436 MAX(mml
->this->y_pos
, ml
->this->y_pos
);
1438 mml
= partitions
[part
]; /* restart the loop, to see if this worked.*/
1440 else mml
= mml
->next
;
1444 /* move the partition to partition 0 */
1445 partitions
[0] = (mlist
*)concat_list(ml
->this, partitions
[0]);
1447 /* and mark it as placed */
1448 ml
->this->placed
= PLACED
;
1450 /* Readjust the bounding box: */
1451 if (y_sizes
[0] <= ml
->this->y_pos
+ ml
->this->y_size
)
1453 y_sizes
[0] = ml
->this->y_pos
+ ml
->this->y_size
+
1454 CHANNEL_HEIGHT
+ max_height
;
1456 if (x_sizes
[0] <= ml
->this->x_pos
+ ml
->this->x_size
)
1458 x_sizes
[0] = ml
->this->x_pos
+ ml
->this->x_size
+
1459 (WHITE_SPACE
* count_terms_part(part
, LEFT
)) + max_wid
;
1461 if (yfloor
>= ml
->this->y_pos
)
1463 yfloor
= ml
->this->y_pos
- ((WHITE_SPACE
+ CHANNEL_HEIGHT
) + max_height
);
1465 if (xfloor
>= ml
->this->x_pos
)
1467 xfloor
= ml
->this->x_pos
- (WHITE_SPACE
* count_terms_part(part
, RIGHT
)) -
1468 max_wid
- CHANNEL_LENGTH
;
1472 /*===================================================================================*/
1473 /* end of file "terminals.c" */