1 /*
2  *   Copyright (C) 1989-1991 Yale University
3  *
4  *   This work is distributed in the hope that it will be useful; you can
5  *   redistribute it and/or modify it under the terms of the
6  *   GNU General Public License as published by the Free Software Foundation;
7  *   either version 2 of the License,
8  *   or any later version, on the following conditions:
9  *
10  *   (a) YALE MAKES NO, AND EXPRESSLY DISCLAIMS
11  *   ALL, REPRESENTATIONS OR WARRANTIES THAT THE MANUFACTURE, USE, PRACTICE,
12  *   SALE OR
13  *   OTHER DISPOSAL OF THE SOFTWARE DOES NOT OR WILL NOT INFRINGE UPON ANY
14  *   PATENT OR
15  *   OTHER RIGHTS NOT VESTED IN YALE.
16  *
17  *   (b) YALE MAKES NO, AND EXPRESSLY DISCLAIMS ALL, REPRESENTATIONS AND
18  *   WARRANTIES
19  *   WHATSOEVER WITH RESPECT TO THE SOFTWARE, EITHER EXPRESS OR IMPLIED,
20  *   INCLUDING,
21  *   BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
22  *   PARTICULAR
23  *   PURPOSE.
24  *
25  *   (c) LICENSEE SHALL MAKE NO STATEMENTS, REPRESENTATION OR WARRANTIES
26  *   WHATSOEVER TO
27  *   ANY THIRD PARTIES THAT ARE INCONSISTENT WITH THE DISCLAIMERS BY YALE IN
28  *   ARTICLE
29  *   (a) AND (b) above.
30  *
31  *   (d) IN NO EVENT SHALL YALE, OR ITS TRUSTEES, DIRECTORS, OFFICERS,
32  *   EMPLOYEES AND
33  *   AFFILIATES BE LIABLE FOR DAMAGES OF ANY KIND, INCLUDING ECONOMIC DAMAGE OR
34  *   INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER YALE SHALL BE
35  *   ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE
36  *   POSSIBILITY OF THE FOREGOING.
37  *
38  */
39 
40 /* -----------------------------------------------------------------
41 FILE:	    configpads.c
42 DESCRIPTION:Configure pads
43 CONTENTS:
44 DATE:	    Jan 29, 1989 - added heading.
45 REVISIONS:  Jan 29, 1989 - removed message about pad limited designs.
46 	    Mar 30, 1989 - changed tile datastructure.
47 	    Apr 30, 1989 - fixed problem with padgroups.  Rewrote major
48 		sections of the algorithm.
49 	    Sat Feb 23 00:17:28 EST 1991 - added placepads algorithm.
50 	    Tue Mar 19 16:31:45 CST 1991 - added core expansion code.
51 	    Thu Apr 18 01:29:33 EDT 1991 - fixed problem with
52 		align_pads when no pads are on a given side.
53 	    Thu Aug 29 15:44:00 CDT 1991 - added overflow processing
54 		code.
55 ----------------------------------------------------------------- */
56 
57 #include <custom.h>
58 #include <pads.h>
59 #include <yalecad/debug.h>
60 #include <yalecad/relpos.h>
61 #include <yalecad/quicksort.h>
62 
63 #include "configpads.h"
64 
65 /* ***************** STATIC FUNCTION DEFINITIONS ******************* */
66 static BOOL check_overflow( P1(BOOL retain_pad_groups) ) ;
67 static void move_clockwise( P4(INT pad, INT side, INT cw_side, INT moveable_cw) ) ;
68 static void move_counterclockwise( P4(INT pad,INT side,INT ccw_side,INT m_ccw ) ) ;
69 static void update_pad_position( P3(PADBOXPTR pad,INT current_side, INT move_side) );
70 static void expand_core( P1(INT side) ) ;
71 static INT compare_overflow( P2(INT *side1, INT *side2) ) ;
72 static void update_pad_groups( P1(void) ) ;
73 static void resort_place_array( P1(void) ) ;
74 static void child_constraints(P5(PADBOXPTR pad,INT side,DOUBLE lb,DOUBLE ub,BOOL s));
75 static void place_variable( P3(INT first,INT numpads,INT side) ) ;
76 
77 /* ***************** STATIC VARIABLE DEFINITIONS ******************* */
78 static INT overflowS[5] ;          /* amount of overflow on each side */
79 static INT side_lengthS[5] ;       /* sum of pad lengths on a side */
80 static INT first_pad_on_sideS[5] ; /* index of first pad on side */
81 static INT last_pad_on_sideS[5] ;  /* index of last pad on side */
82 static INT pad_extraS ;            /* insure that sort works correctly */
83 
align_pads()84 void align_pads()
85 {
86     INT pad ;                      /* counter */
87     INT side ;                     /* current pad side */
88     INT last ;                     /* index of last pad on side */
89     INT first ;                    /* index of first pad on side */
90     INT count ;                    /* count number of overflow iterations */
91     INT length ;                   /* length of current pad */
92     INT needed ;                   /* extra space needed on each side */
93     INT numpads ;                  /* number of pads on this side */
94     INT cum_space ;                /* cum_space on this side */
95     INT padspacing ;               /* padspacing method for current side*/
96     INT extra_space ;              /* slack on a side */
97     BOOL overflow_exists ;         /* if set, overflow still exists */
98     BOOL retain_pad_groups ;       /* if set, padgroups will not be moved from side */
99     PADBOXPTR padptr ;             /* current pad info */
100     DOUBLE left_edge ;             /* left edge of the placed pad */
101     DOUBLE extra_space_per_pad ;   /* how much left over per pad */
102 
103     count = 0 ;
104     retain_pad_groups = TRUE ;
105     pad_extraS = 100000 ;
106     do {
107 	overflow_exists = check_overflow( retain_pad_groups ) ;
108 	if( overflow_exists ){
109 	    resort_place_array() ;
110 	}
111 	if( ++count >= 3 ){
112 	    retain_pad_groups = FALSE ;
113 	}
114     } while( overflow_exists ) ;
115 
116     update_pad_groups() ;
117 
118     for( side = 1 ; side <= 4 ; side++ ) {
119 	if(!(first_pad_on_sideS[side])){
120 	    /* there are no pads on this side */
121 	    continue ;
122 	}
123 	extra_space = perdimG[ side%2 ] - side_lengthS[side] ;
124 	/* check to see if we have overflow */
125 	if( extra_space <= 0 ){
126 	    /* we must perform abut padspacing on this side */
127 	    padspacing = ABUT_PADS ;
128 	} else {
129 	    /* do what the user requested */
130 	    padspacing = padspacingG ;
131 	}
132 
133 	first = first_pad_on_sideS[side] ;
134 	last = last_pad_on_sideS[side] ;
135 	numpads = last - first + 1 ;
136 
137 	switch( padspacing ){
138 	    case UNIFORM_PADS:
139 		extra_space_per_pad = (DOUBLE) extra_space /
140 			              (DOUBLE) (numpads+1) ;
141 		left_edge = (DOUBLE) coreG[side%2][MINI] ;
142 		for( pad = 1; pad <= numpads; pad++ ){
143 		    padptr = placearrayG[first + pad - 1] ;
144 		    /* calculate the placement of the left edge of the pad */
145 		    left_edge += extra_space_per_pad ;
146 		    /* now find the center of the current pad */
147 		    padptr->position =  ((INT) left_edge ) +
148 			padptr->length / 2 ;
149 		    /* now set left edge for next pad */
150 		    left_edge += (DOUBLE)
151 			(padptr->length + min_pad_spacingG) ;
152 		}
153 		break ;
154 	    case ABUT_PADS:
155 		extra_space_per_pad = (DOUBLE) extra_space / 2.0 ;
156 		left_edge = (DOUBLE) coreG[side%2][MINI] + extra_space_per_pad ;
157 
158 		for( pad = 1; pad <= numpads; pad++ ){
159 		    padptr = placearrayG[first + pad - 1] ;
160 		    /* now find the center of the current pad */
161 		    padptr->position =  ((INT) left_edge ) +
162 			padptr->length / 2 ;
163 		    /* now set left edge for next pad */
164 		    left_edge += (DOUBLE)
165 			(padptr->length + min_pad_spacingG) ;
166 		}
167 		break ;
168 	    case VARIABLE_PADS:
169 		/* we now we can fit it on this side */
170 		place_variable( first, numpads, side ) ;
171 		break ;
172 	    case EXACT_PADS:
173 		break ;
174 
175 	} /* end switch */
176 
177     } /* end loop on sides */
178 
179 } /* end align_pads */
180 /* ***************************************************************** */
181 
check_overflow(retain_pad_groups)182 static BOOL check_overflow( retain_pad_groups )
183 BOOL retain_pad_groups ;
184 {
185     INT i ;                        /* counter */
186     INT pad ;                      /* counter */
187     INT side ;                     /* current pad side */
188     INT cw_pad ;                   /* pad to move in clockwise direction */
189     INT ccw_pad ;                  /* pad to move in ccw direction */
190     INT length ;                   /* length of current pad */
191     INT clockwise ;                /* the side in the clockwise direction */
192     INT counterclockwise ;         /* the side in the ccw direction */
193     INT overflow_cw ;              /* amount of overflow when pad is moved cw */
194     INT overflow_ccw ;             /* amount of overflow when pad is moved ccw */
195     INT moveable_cw ;              /* size of pad to be moved cw */
196     INT moveable_ccw ;             /* size of pad to be moved ccw */
197     INT side_open[5] ;             /* whether side has been processed */
198     INT sort_overflow[5] ;         /* index for sorted overflow */
199     INT compare_overflow() ;       /* sort the sides for overflow */
200     PADBOXPTR padptr ;             /* current pad info */
201 
202     /* first accummulate the sum of all the pads on a given side */
203     /* also find the first and last pad on a given side */
204     for( side = 1 ; side <= 4 ; side++ ) {
205 	overflowS[side] = 0 ;
206 	side_lengthS[side] = 0 ;
207 	first_pad_on_sideS[side] = 0 ;
208 	last_pad_on_sideS[side] = -1 ;
209     }
210     for( pad = 1 ; pad <= numpadsG ; pad++ ) {
211 	padptr = placearrayG[pad] ;
212 	side = padptr->padside ;
213 	length = padptr->length ;
214 	/* this will add one too many min_pad_spacing */
215 	/* subtract it below */
216 	side_lengthS[side] += length + min_pad_spacingG ;
217 	if(!(first_pad_on_sideS[side])){
218 	    first_pad_on_sideS[side] = pad ;
219 	}
220 	last_pad_on_sideS[side] = pad ;
221     }
222 
223     /* check for overflow on the sides */
224     for( side = 1 ; side <= 4 ; side++ ) {
225 	/* adjust extra min_pad_spacing */
226 	if(first_pad_on_sideS[side]){
227 	    /* there are pads on this side */
228 	    side_lengthS[side] -= min_pad_spacingG ;
229 	}
230 	overflowS[side] = side_lengthS[side] - perdimG[ side%2 ] ;
231     }
232     /* check to see if we have overflow */
233     if( overflowS[L] <= 0 && overflowS[R] <= 0 &&
234 	overflowS[B] <= 0 && overflowS[T] <= 0 ){
235 	/* there is no overflow */
236 	return( FALSE ) ;
237     }
238 
239     /* overflow exists so resolve the conflict. */
240     /* first sort the overflow */
241     for( i = 1 ; i <= 4; i++ ){
242 	/* initialize sort_overflow array */
243 	sort_overflow[i] = i ;
244 	side_open[i] = TRUE ;
245     }
246     Yquicksort( &(sort_overflow[1]), 4, sizeof(INT), compare_overflow );
247     for( i = 1; i <= 4; i++ ){
248 	side = sort_overflow[i] ;
249 	side_open[side] = FALSE ;
250 	if( overflowS[side] <= 0 ){
251 	    continue ;
252 	}
253 	/* find clockwise side */
254 	clockwise = side + 1 ;
255 	if( clockwise > 4 ) clockwise = 1 ; /* wrap around */
256 	/* find counter clockwise side */
257 	counterclockwise = side - 1 ;
258 	if( counterclockwise < 1 ) counterclockwise = 4 ; /* wrap around */
259 
260 	do {
261 	    /* look for the last valid pad on side to move clockwise */
262 	    /* make sure side is still open */
263 	    cw_pad = 0 ;
264 	    if( side_open[clockwise] ){
265 		for( pad = last_pad_on_sideS[side];pad >= first_pad_on_sideS[side];
266 		    pad-- ){
267 		    padptr = placearrayG[pad] ;
268 		    if( padptr->padside != side ){
269 			/* this means we already moved this pad from this side */
270 			continue ;
271 		    }
272 		    if( retain_pad_groups && padptr->hierarchy != NONE ){
273 			/* if the retain_pad_group switch is on, we ignore any */
274 			/* pad in a padgroup */
275 			continue ;
276 		    }
277 		    if( padptr->valid_side[ALL] || padptr->valid_side[clockwise] ){
278 			cw_pad = pad ;
279 			moveable_cw = padptr->length + min_pad_spacingG ;
280 			break ;
281 		    }
282 		} /* end pad = last_pad_on_side... */
283 	    } /* end side_open[clockwise... */
284 
285 	    /* look for the first valid pad on side to move counterclockwise */
286 	    /* make sure side is still open */
287 	    ccw_pad = 0 ;
288 	    if( side_open[counterclockwise] ){
289 		for( pad = first_pad_on_sideS[side]; pad <= last_pad_on_sideS[side];
290 		    pad++ ){
291 		    padptr = placearrayG[pad] ;
292 		    if( padptr->padside != side ){
293 			/* this means we already moved this pad from this side */
294 			continue ;
295 		    }
296 		    if( retain_pad_groups && padptr->hierarchy != NONE ){
297 			/* if the retain_pad_group switch is on, we ignore any */
298 			/* pad in a padgroup */
299 			continue ;
300 		    }
301 		    if( padptr->valid_side[ALL] || padptr->valid_side[counterclockwise] ){
302 			ccw_pad = pad ;
303 			moveable_ccw = padptr->length + min_pad_spacingG ;
304 			break ;
305 		    }
306 		} /* end pad = first_pad_on_side... */
307 	    } /* end side_open[counterclockwise... */
308 
309 	    if( cw_pad && ccw_pad ){
310 		/* this is the case where there are two valid pads which can be moved */
311 		/* pick the pad && side which has smaller overflow */
312 		overflow_cw = overflowS[clockwise] + moveable_cw ; ;
313 		overflow_ccw = overflowS[counterclockwise] + moveable_ccw ; ;
314 		if( overflow_cw <= overflow_ccw ){
315 		    move_clockwise( cw_pad, side, clockwise, moveable_cw ) ;
316 		} else {
317 		    move_counterclockwise( ccw_pad, side, counterclockwise, moveable_ccw ) ;
318 		}
319 	    } else if( cw_pad ){
320 		move_clockwise( cw_pad, side, clockwise, moveable_cw ) ;
321 	    } else if( ccw_pad ){
322 		move_counterclockwise( ccw_pad, side, counterclockwise,
323 		    moveable_ccw ) ;
324 	    } else {
325 		/* no more pads to move, we need to expand core */
326 		expand_core( side ) ;
327 		return( TRUE ) ;
328 	    }
329 	} while( overflowS[side] > 0 ) ;
330 
331     } /* end for( i = 1; i <= 4; i++ ) ... */
332 
333     /* if we get here, we had some overflow */
334     return( TRUE ) ;
335 
336 } /* end check_overflow */
337 
move_clockwise(pad,side,clockwise_side,moveable_cw)338 static void move_clockwise( pad, side, clockwise_side, moveable_cw )
339 INT pad, side, clockwise_side, moveable_cw ;
340 {
341     PADBOXPTR padptr ;             /* current pad info */
342 
343     /* move pad */
344     padptr = placearrayG[pad] ;
345     padptr->padside = clockwise_side ;
346     /* determine position */
347     update_pad_position( padptr, side, clockwise_side ) ;
348     /* reset the overflows */
349     overflowS[side] -= moveable_cw ;
350     overflowS[clockwise_side] += moveable_cw ;
351 
352 } /* end move_clockwise */
353 
354 
move_counterclockwise(pad,side,counterclockwise,moveable_ccw)355 static void move_counterclockwise( pad, side, counterclockwise, moveable_ccw )
356 INT pad, side, counterclockwise, moveable_ccw ;
357 {
358     PADBOXPTR padptr ;             /* current pad info */
359 
360     /* move pad */
361     padptr = placearrayG[pad] ;
362     padptr->padside = counterclockwise ;
363     update_pad_position( padptr, side, counterclockwise ) ;
364     /* determine position */
365     /* reset the overflows */
366     overflowS[side] -= moveable_ccw ;
367     overflowS[counterclockwise] += moveable_ccw ;
368 
369 } /* end move_counterclockwise */
370 
update_pad_position(padptr,current_side,move_side)371 static void update_pad_position( padptr, current_side, move_side )
372 PADBOXPTR padptr ;             /* current pad info */
373 INT current_side ;
374 INT move_side ;
375 {
376     INT dimension ;            /* the X or Y dimension */
377 
378     dimension = move_side % 2 ;
379     switch( current_side ){
380     case L:
381 	padptr->position = coreG[dimension][MINI] - ++pad_extraS;
382 	break ;
383     case T:
384 	padptr->position = coreG[dimension][MAXI] + ++pad_extraS ;
385 	break ;
386     case R:
387 	padptr->position = coreG[dimension][MAXI] + ++pad_extraS ;
388 	break ;
389     case B:
390 	padptr->position = coreG[dimension][MINI] - ++pad_extraS;
391 	break ;
392     } /* end switch side ... */
393 } /* end update_pad_position */
394 
expand_core(side)395 static void expand_core( side )
396 INT side ;
397 {
398     INT i ;                        /* counter */
399     INT pad ;                      /* counter */
400     INT overflow_amount ;          /* amount to expand */
401     INT amount ;                   /* amount to add to each pad half of a side */
402     INT expansion ;                /* amount to expand a dimension */
403     PADBOXPTR padptr ;             /* current pad info */
404 
405     overflow_amount = 0 ;
406     /* determine how much to expand by */
407     /* normally we assume that all sides can help reduce overflow */
408     /* if we find that the overflow_amount < 0 or overflow_amount is only */
409     /* 25% of the overflow on a side, it means that some sides */
410     /* have non moveable pads.  We need to make the overflow amount the given side */
411     for( i = 1; i <= 4 ; i++ ){
412 	overflow_amount += overflowS[i] ;
413     }
414     if( overflow_amount < 0 || overflow_amount < 0.25 * overflowS[side] ){
415 	overflow_amount = overflowS[side] ;
416     }
417 
418     /* now divide the amount equally in both dimensions */
419     expansion = overflow_amount / 2 ;
420     if( expansion <= 0 ) expansion = 1 ;
421     amount = expansion / 2 ;
422     coreG[X][MINI] -= amount ;
423     coreG[X][MAXI] += (expansion - amount ) ;
424     coreG[Y][MINI] -= amount ;
425     coreG[Y][MAXI] += (expansion - amount ) ;
426     /* expand in X and Y directions */
427     /* we to search all the pads since they may not be in order */
428     for( pad = 1 ; pad <= numpadsG ; pad++ ) {
429 	padptr = placearrayG[pad] ;
430 	side = padptr->padside ;
431 	padptr->position += amount ;
432     }
433     /* now reset the perimeters */
434     perdimG[X] = coreG[X][MAXI] - coreG[X][MINI] ;
435     perdimG[Y] = coreG[Y][MAXI] - coreG[Y][MINI] ;
436 } /* end expand_core */
437 
compare_overflow(side1,side2)438 static INT compare_overflow( side1, side2 )
439 INT *side1, *side2 ;
440 {
441     /* sort largest to smallest */
442     return( overflowS[*side2] - overflowS[*side1] ) ;
443 } /* end compare_overflow */
444 
compare_placearray(padptr1,padptr2)445 static INT compare_placearray( padptr1, padptr2 )
446 PADBOXPTR *padptr1, *padptr2 ;
447 {
448     PADBOXPTR pad1, pad2;
449 
450     pad1 = *padptr1 ;
451     pad2 = *padptr2 ;
452 
453     if( pad1->padside != pad2->padside) {
454 	return( pad1->padside - pad2->padside ) ;
455     }
456     if( pad1->position < pad2->position ){
457 	return( -1 ) ;
458     } else if( pad1->position > pad2->position ){
459 	return( 1 ) ;
460     } else {
461 	return( 0 ) ;
462     }
463 } /* end compare_placearray */
464 
resort_place_array()465 static void resort_place_array()
466 {
467     Yquicksort( &(placearrayG[1]), numpadsG, sizeof(PADBOXPTR), compare_placearray );
468 } /* end resort_place_array */
469 /* ***************************************************************** */
470 
471 /* set the lo_pos and hi_pos fields for the pads */
update_pad_groups()472 static void update_pad_groups()
473 {
474 
475     INT i ;                   /* pad counter */
476     DOUBLE lobound ;          /* lower bound on position */
477     DOUBLE hibound ;          /* upper bound on position */
478     BOOL spacing_restricted ; /* whether spacing is restricted */
479     PADBOXPTR pad ;           /* current pad */
480 
481     if( padspacingG != VARIABLE_PADS ){
482 	return ;
483     }
484 
485     /* now update the lo_pos and hi_pos fields of the pad */
486     for( i = 1 ; i <= totalpadsG; i++ ) {
487 	pad = padarrayG[i];
488 	/* make copy of these we don't want to change roots copy */
489 	lobound = pad->lowerbound ;
490 	hibound  = pad->upperbound ;
491 	spacing_restricted = pad->fixed ;
492 	if( pad->padtype == PADGROUPTYPE && pad->hierarchy == ROOT  ){
493 	    child_constraints( pad, pad->padside, lobound, hibound,
494 		spacing_restricted ) ;
495 
496 	} else if( pad->padtype == PADCELLTYPE && pad->hierarchy == NONE ) {
497 	    /* the case of a pad that is not in a padgroup */
498 	    calc_constraints( pad, pad->padside, &lobound, &hibound,
499 	        &spacing_restricted, &(pad->lo_pos), &(pad->hi_pos) ) ;
500 	}
501     }
502 
503 } /* end update_pad_groups */
504 
505 /* this will set the constaints for pad groups and children of them */
child_constraints(pad,side,lb,ub,spacing_restricted)506 static void child_constraints( pad, side, lb, ub, spacing_restricted )
507 PADBOXPTR pad ;
508 INT side ;
509 DOUBLE lb, ub ;
510 BOOL spacing_restricted ;
511 {
512     INT i ;            /* pad counter */
513     INT howmany ;      /* number of children */
514     PADBOXPTR child ;  /* current child */
515 
516     calc_constraints( pad, side, &lb, &ub, &spacing_restricted,
517 	&(pad->lo_pos), &(pad->hi_pos) );
518 
519     if( pad->padtype != PADCELLTYPE ){
520 	howmany = pad->children[HOWMANY] ;
521 	for( i = 1 ;i <= howmany ; i++ ){
522 	    child = padarrayG[ pad->children[i] ] ;
523 	    child_constraints( child, side, lb, ub,spacing_restricted ) ;
524 	}
525     }
526 } /* end child_constraints */
527 /* ***************************************************************** */
528 
calc_constraints(PADBOXPTR pad,INT side,DOUBLE * lb,DOUBLE * ub,BOOL * spacing_restricted,INT * lowpos,INT * uppos)529 void calc_constraints( PADBOXPTR pad, INT side, DOUBLE *lb, DOUBLE *ub, BOOL *spacing_restricted, INT *lowpos, INT *uppos )
530 {
531     DOUBLE lowbound, hibound ;
532 
533     /* determine spacing restrictions */
534     if( *spacing_restricted ){
535 	/* this is the case that the spacing has been restricted */
536 	if( pad->fixed ){
537 	    /* if the padgroup bounds have been fixed, */
538 	    /* force position to be within bound */
539 	    /* assume we are ok and then correct it */
540 	    lowbound = pad->lowerbound ;
541 	    if( lowbound < *lb ){
542 		lowbound = *lb ;
543 	    }
544 	    if( lowbound > *ub ){
545 		lowbound = *ub ;
546 	    }
547 	    hibound = pad->upperbound ;
548 	    if( hibound < *lb ){
549 		hibound = *lb ;
550 	    }
551 	    if( hibound > *ub ){
552 		hibound = *ub ;
553 	    }
554 	} else {
555 	    /* this pad is not fixed use the given ub and lb */
556 	    lowbound = *lb ; hibound = *ub ;
557 	}
558     } else {
559 	if( pad->fixed ){
560 	    /* the padgroup bounds have not been fixed */
561 	    /* just take the pad's restricted position */
562 	    lowbound = pad->lowerbound;
563 	    hibound = pad->upperbound;
564 	    *spacing_restricted = TRUE ;
565 	}
566     }
567     if( *spacing_restricted ){
568 	*lowpos = (INT) ( lowbound * (DOUBLE)perdimG[side%2] ) ;
569 	*lowpos += coreG[side%2][MINI] ;
570 	*uppos = (INT) ( hibound * (DOUBLE)perdimG[side%2] ) ;
571 	*uppos += coreG[side%2][MINI] ;
572     } else {
573 	*lowpos = -1 ;
574 	*uppos = PINFINITY ;
575     }
576     /* **** END spacing restriction calculations *** */
577     /* return low bound */
578     *lb = lowbound ;
579     *ub = hibound ;
580 
581 } /* end calc_constraints */
582 /* ***************************************************************** */
583 
place_variable(first,numpads,side)584 static void place_variable( first, numpads, side )
585 INT first, numpads, side ;
586 {
587     INT pad ;            /* counter */
588     INT left_edge ;      /* current left edge of pad */
589     INT right_edge ;     /* current right edge of pad */
590     INT half_length ;    /* half the span of a pad */
591     INT valid_left_edge ;/* this position is open for the pad leftedge*/
592     INT valid_right_edge;/* this position is open for the pad rightedge*/
593     PADBOXPTR padptr ;   /* current pad info */
594 
595     valid_left_edge = 0 ;
596     for( pad = 0; pad < numpads; pad++ ){
597 	padptr = placearrayG[first + pad ] ;
598 	/* now find the left edge of the current pad */
599 	half_length = padptr->length / 2 ;
600 	left_edge = padptr->position - half_length ;
601 	valid_left_edge = MAX( valid_left_edge, padptr->lo_pos ) ;
602 	if( left_edge < valid_left_edge ){
603 	    /* need to remove overlap */
604 	    /* so left edge of pad becomes valid_left_edge */
605 	    left_edge = valid_left_edge ;
606 	    /* calculate new padptr position */
607 	    padptr->position = valid_left_edge + half_length ;
608 	}
609 	/* now calculate the new valid left edge */
610 	valid_left_edge = left_edge + padptr->length + min_pad_spacingG ;
611     }
612 
613     D( "placepads/after_left_edge",
614 	print_pads( "pads after left_edge\n", placearrayG, numpadsG ) ;
615     ) ;
616 
617     valid_right_edge = coreG[side%2][MAXI] ;
618     /* now condense pads if they exceed the length of the side */
619     for( pad = numpads-1; pad >= 0; pad-- ){
620 	padptr = placearrayG[first + pad] ;
621 	/* now find the left edge of the current pad */
622 	half_length = padptr->length / 2 ;
623 	half_length = padptr->length - half_length ;
624 	right_edge = padptr->position + half_length ;
625 	valid_right_edge = MIN( valid_right_edge, padptr->hi_pos ) ;
626 	if( right_edge > valid_right_edge ){
627 	    /* need to remove overlap */
628 	    /* so left edge of pad becomes valid_left_edge */
629 	    right_edge = valid_right_edge ;
630 	    /* calculate new padptr position */
631 	    padptr->position = valid_right_edge - half_length ;
632 	} else {
633 	    break ;
634 	}
635 	/* now calculate the new valid right edge */
636 	valid_right_edge = right_edge - padptr->length - min_pad_spacingG ;
637     }
638 
639 } /* end place_variable */
640 
641 
dimension_pads()642 void dimension_pads()
643 {
644     INT i ;           /* pad counter */
645     PADBOXPTR pad ;   /* current pad */
646     PINBOXPTR pin ;   /* current pin */
647     CELLBOXPTR cptr ; /* current cell */
648 
649     for( i = 1 ; i <= numpadsG; i++ ) {
650 	pad = padarrayG[i];
651 	cptr = cellarrayG[pad->cellnum] ;
652 	switch( pad->padside) {
653 	    case L:
654 		cptr->xcenter = coreG[X][MINI] - pad->height / 2 ;
655 		cptr->ycenter = pad->position ;
656 		break;
657 	    case T:
658 		cptr->xcenter = pad->position ;
659 		cptr->ycenter = coreG[Y][MAXI] + pad->height / 2 ;
660 		break;
661 	    case R:
662 		cptr->xcenter = coreG[X][MAXI] + pad->height / 2 ;
663 		cptr->ycenter = pad->position ;
664 		break;
665 	    case B:
666 		cptr->xcenter = pad->position ;
667 		cptr->ycenter = coreG[Y][MINI] - pad->height / 2 ;
668 		break;
669 	} /* end switch on side */
670 	/* now update the pins */
671 	for( pin = cptr->pinptr; pin ; pin = pin->nextpin ){
672 	    REL_POST( cptr->orient,
673 		pin->xpos, pin->ypos,                /* result */
674 		pin->txpos,
675 		pin->typos,                         /* cell relative */
676 		cptr->xcenter, cptr->ycenter ) ;    /* cell center */
677 	}
678     }
679 
680 } /* dimension_pads */
681 /* ***************************************************************** */
682 
683 
orient_pads()684 void orient_pads()
685 {
686     INT i ;                         /* counter */
687     PADBOXPTR pad ;                 /* current pad info */
688     CELLBOXPTR cptr ;               /* current cell */
689 
690      for( i = 1; i <= numpadsG; i++ ){
691 	 pad = placearrayG[i];
692 	 cptr = cellarrayG[pad->cellnum] ;
693 	 switch( pad->padside ){
694 	 case L:
695 	    /* rotate 270 | -90 */
696 	    cptr->orient = 7 ;
697 	    cptr->ycenter = cptr->xcenter;
698 	    break;
699 	 case T:
700 	    /* rotate180 */
701 	    cptr->orient = 3 ;
702 	    break;
703 	 case R:
704 	    /* rotate90 */
705 	    cptr->orient = 6 ;
706 	    cptr->ycenter = cptr->xcenter;
707 	    break;
708 	 case B:
709 	    cptr->orient = 0 ;
710 	    break;
711 	 default:
712 	    OUT1("\nNON-PADS or PAD w/o side not rotated ");
713 	    break;
714 	 }
715      }
716 } /* end orient_pads */
717 /* ***************************************************************** */
718