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