1 /*
2  *   Copyright (C) 1988-1992 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:	    placepads.c
42 DESCRIPTION:This file contains the place pads routines.
43 CONTENTS:
44 	    placepads()
45 	    find_core()
46 	    setVirtualCore( flag )
47 		BOOL flag ;
48 	    find_core_boundry( left, right, bottom, top )
49 		INT *left, *right, *bottom, *top ;
50 	    get_global_pos( cell, l, b, r, t )
51 		INT cell, *l, *r, *b, *t ;
52 DATE:	    Aug 12, 1988
53 REVISIONS:  Oct 24, 1988 - added virtual core switch to control pad
54 		placement.
55 	    Jan 17, 1988 - add find_core_boundary for channel graph
56 		generation code - outgeo.c .
57 	    Jan 20, 1989 - fixed problem when pad has no pin connected
58 		to it.  Made sure softcells are using correct fields
59 		and coordinates are translated.
60 	    Feb. 15, 1989 - added get_global_pos so that amount of
61 		duplicated code is reduced.
62 	    Apr  30, 1989 - added bound to padcenter for non-virtual
63 		core placement.  Modified putChildren to place
64 		padgroups with sidespace restriction.
65 	    Oct 20, 1989 - Now pads are output with global routing
66 		density.
67 	    Feb  7, 1990 - Updated placepad core coordinates to
68 		reflect new routing scheme.
69 	    Sun Jan 20 21:47:52 PST 1991 - ported to AIX.
70 	    Thu Feb 14 02:44:36 EST 1991 - new pad placement algorithm.
71 	    Fri Feb 15 15:19:38 EST 1991 - modified for VARIABLE_PADS
72 		case.
73 	    Sun Feb 17 21:07:39 EST 1991 - renamed globals.
74 	    Wed Jun  5 16:39:11 CDT 1991 - added retain_side option
75 		and now pad pins correctly.
76 	    Fri Sep  6 15:16:27 CDT 1991 - moved retain_side option
77 		so it works when no pad groups exist.
78 	    Thu Sep 19 16:33:58 EDT 1991 - fixed problem with sidespace
79 		options when only a fraction of the pins to pads have
80 		connections to the core.
81 ----------------------------------------------------------------- */
82 
83 #define PAD_VARS
84 
85 #include <standard.h>
86 #include <pads.h>
87 #include <config.h>
88 #include <parser.h>
89 #include <yalecad/debug.h>
90 
91 /* global references */
92 extern INT **pairArrayG ;
93 
94 /* ***************** STATIC FUNCTION DEFINITIONS ******************* */
95 static void find_optimum_locations( P1(void) ) ;
96 static void place_pad( P2(PADBOXPTR pad,INT bestside ) ) ;
97 static void place_children( P5(PADBOXPTR pad,INT side,DOUBLE lb,DOUBLE ub,BOOL sr) ) ;
98 static INT find_cost_for_a_side(P5(PADBOXPTR pad,INT side,DOUBLE lb,DOUBLE ub,
99    BOOL spacing_restricted ) ) ;
100 static void find_core( P1(void) ) ;
101 
102 void get_global_pos(INT cell, INT *l, INT *b, INT *r, INT *t);
103 
104 /* ***************** STATIC VARIABLE DEFINITIONS ******************* */
105 static BOOL virtualCoreS = FALSE ;
106 static INT sumposS ; /* sum of the modified opt. pin pos. of pad pins */
107 static INT sumtieS ; /* sum of all the opt. pin pos. of pad pins */
108 static INT pin_countS ; /* number of pins found with valid connections */
109 static BOOL retain_sideS = FALSE ; /* during global routing side is set */
110 
111 /*-------------------------------------------------------------------
112 The placepads module tries to place the pads such that the distance
113 between the pads and their nearest connected pins in the is minimized.
114 It must also adhere to user-specified restrictions on side, position,
115 spacing and ordering.
116 ____________________________________________________________________*/
117 
placepads()118 void placepads()
119 {
120     if( padspacingG == EXACT_PADS ){
121 	return ;
122     }
123     find_core();  /* GET THE UPDATED CORE'S DIMENSION */
124 
125     D( "placepads/initially",
126 	print_pads( "pads initially\n", padarrayG, totalpadsG ) ;
127     ) ;
128 
129     find_optimum_locations() ;
130     D( "placepads/after_find_opt",
131 	print_pads( "pads after_cost\n", sortarrayG, totalpadsG ) ;
132     ) ;
133 
134     sort_pads();
135     D( "placepads/after_sort",
136 	print_pads( "pads after sort\n", placearrayG, numpadsG );
137     ) ;
138 
139     align_pads();
140     D( "placepads/after_align",
141 	print_pads( "pads after align\n", placearrayG, numpadsG ) ;
142     ) ;
143 
144     orient_pads();
145     D( "placepads/after_orient",
146 	print_pads( "pads after orient\n", placearrayG, numpadsG ) ;
147     ) ;
148 
149     dimension_pads();
150     D( "placepads/after_dim",
151 	print_pads( "pads after dimension\n", placearrayG, numpadsG ) ;
152     ) ;
153 
154 } /* end placepads */
155 /* ***************************************************************** */
156 
find_optimum_locations()157 static void find_optimum_locations()
158 {
159     INT i ;                  /* pad counter */
160     INT side ;               /* loop thru valid sides */
161     INT cost ;               /* current cost */
162     INT bestpos ;            /* best modified position for pad */
163     INT besttie ;            /* best position for pad for tiebreak */
164     INT bestcost ;           /* best cost for pad or padgroup */
165     INT bestside ;           /* best side to place pad or padgroup */
166     PADBOXPTR pad ;          /* current pad */
167 
168     /** FIND OPTIMUM PLACE FOR PADS ACCORDING TO THE RESTRICTIONS **/
169     for( i = 1; i <= totalpadsG; i++ ){
170 
171 	/**** LEAVES AND SUBROOTS NEED TO BE PLACED ON THE SAME
172 	**** SIDE AS THEIR PARENT ROOT, HENCE WE PLACE THE ROOT
173 	**** FIRST, AND THEN PLACE ALL ITS CHILDREN **/
174 
175 	pad = padarrayG[i] ;
176 	if( pad->padtype == PADGROUPTYPE && pad->hierarchy == ROOT  ){
177 	    /* the case of a padgroup root */
178 	    bestcost = INT_MAX ;
179 	    bestside = 1 ;
180 	    for (side = 1; side <= 4; side++ ) {
181 		if( pad->valid_side[ALL] || pad->valid_side[side] ){
182 		    cost = find_cost_for_a_side( pad,side,
183 			pad->lowerbound, pad->upperbound, pad->fixed ) ;
184 		    if( cost < bestcost) {
185 			bestcost = cost;
186 			bestside = side ;
187 		    }
188 		}
189 	    }
190 	    place_children( pad, bestside, pad->lowerbound,
191 		pad->upperbound, pad->fixed ) ;
192 
193 	} else if( pad->padtype == PADTYPE && pad->hierarchy == NONE ) {
194 	    /* the case of a pad that is not in a padgroup */
195 	    bestcost = INT_MAX ;
196 	    bestpos = 0 ; besttie = 0 ;
197 	    for (side = 1; side <= 4; side++ ) {
198 		if( pad->valid_side[ALL] || pad->valid_side[side] ){
199 		    cost = find_cost_for_a_side( pad,side,
200 			pad->lowerbound, pad->upperbound, pad->fixed ) ;
201 		    if( cost < bestcost) {
202 			bestcost = cost;
203 			bestside = side ;
204 			bestpos = sumposS ;
205 			besttie = sumtieS ;
206 		    }
207 		}
208 	    }
209 	    /* now use the best positions for the position */
210 	    sumposS = bestpos ;
211 	    sumtieS = besttie ;
212 	    place_pad( pad, bestside ) ;
213 
214 	} /* end simple pad case */
215     }
216 } /* end find_optimum */
217 
218 /* ***************************************************************** */
find_cost_for_a_side(pad,side,lb,ub,spacing_restricted)219 static INT find_cost_for_a_side(pad,side,lb,ub,spacing_restricted)
220 PADBOXPTR pad;
221 INT  side ;
222 DOUBLE lb, ub ;
223 BOOL spacing_restricted ;
224 {
225     INT i ;           /* children counter */
226     INT pos ;         /* current pos. of current core pin constrained*/
227     INT dist ;        /* current distance from core pin to pad */
228     INT cost ;        /* sum of the opt pad pins to closest core pin */
229     INT dist2 ;       /* under restrictions dist from core pin to pad */
230     INT lowpos ;      /* convert lower bound to a position */
231     INT uppos ;       /* convert upper bound to a position */
232     INT bestpos ;     /* best constrained pos for pad to core for 1 net */
233     INT besttie ;     /* best position for pad to core for 1 net */
234     INT bestdist ;    /* best distance for pad to core for 1 net */
235     INT tiebreak ;    /* best place to put pad pin unconstrained */
236     BOOL pinFound ;   /* true if we find a match on current net */
237     PINBOXPTR pinptr; /* current pin */
238     PINBOXPTR netterm;/* loop thru pins of a net */
239     PADBOXPTR child;  /* go thru the children of the padgroup */
240     CBOXPTR cptr ;    /* current cell */
241     PADBOXPTR padptr; /* use to check if pad */
242 
243 
244     /**** FOR NORMAL PADS AND LEAVES, JUST CALCULATE THE COST */
245     /*** AND POSITION. THE LEAF CASE IS THE RETURN CONDITION OF */
246     /*** THE RECURSION ON THE ROOT PADS ***/
247 
248     if( retain_sideS && side != pad->padside ){
249 	/* during global routing must retain the side */
250 	return( PINFINITY ) ;
251     }
252     if( pad->hierarchy == LEAF || pad->hierarchy == SUBROOT ){
253 	if( !(pad->valid_side[ALL]) && !(pad->valid_side[side]) ){
254 	    /* this is not a valid side return a huge cost */
255 	    return( PINFINITY ) ;
256 	}
257     }
258     /* At this point are guaranteed to have a valid side */
259     cost = 0 ;
260     sumposS = 0 ;
261     sumtieS = 0 ;
262 
263     /* determine spacing restrictions */
264     calc_constraints( pad, side, &lb, &ub, &spacing_restricted,
265 	&lowpos, &uppos ) ;
266 
267     if( pad->hierarchy == LEAF || pad->hierarchy == NONE ){
268 
269 
270 	/**** FOR ALL PINS BELONGING TO THE SAME NET AS PINS ON THE
271 	    PAD, FIND THE PIN CLOSEST TO THE SIDE IN padside. ****/
272 
273 	/**** ASSUME NO PIN WAS FOUND ***/
274 	pin_countS = 0 ;
275 
276 	for ( pinptr=carrayG[pad->cellnum]->pins;pinptr;pinptr=pinptr->nextpin) {
277 	    bestdist = INT_MAX ;
278 	    /*** GO TO FIRST TERMS OF THE NET TO MAKE SURE ALL
279 	         TERMINALS ARE INCLUDED ***/
280 	    pinFound = FALSE ;
281 	    netterm = netarrayG[pinptr->net]->pins;
282 	    for( ;netterm ;netterm = netterm->next ) {
283 
284 		/**** CALCULATE THE DISTANCE FROM CORE.
285 		**** pos IS THE POSITION OF THE PAD ON THIS SIDE
286 		**** WHICH RESULTS IN THE SHORTEST DISTANCE TO THE PIN.
287 		**** ONLY PINS ON CELLS ARE IN THIS CONTEST **/
288 
289 		cptr = carrayG[netterm->cell] ;
290 		if( (padptr = cptr->padptr) && !(padptr->macroNotPad)){
291 		    /* skip over this pad */
292 		    continue ;
293 		}
294 		switch (side) {
295 		    case L:
296 			pos  = netterm->ypos;
297 			dist = netterm->xpos - coreG[X][MINI];
298 			break;
299 		    case T:
300 			pos  = netterm->xpos;
301 			dist = coreG[Y][MAXI] - netterm->ypos;
302 			break;
303 		    case R:
304 			pos  = netterm->ypos;
305 			dist = coreG[X][MAXI] - netterm->xpos;
306 			break;
307 		    case B:
308 			pos  = netterm->xpos;
309 			dist = netterm->ypos - coreG[Y][MINI];
310 			break;
311 		    default :
312 			pos = INT_MAX ;
313 			dist = INT_MAX ;
314 		} /* end switch on side */
315 
316 		tiebreak = pos ; /* save original spot */
317 		if( spacing_restricted ){
318 		    /* the pad placement on the side has been */
319 		    /* restricted in some way */
320 		    if( lowpos <= pos && pos <= uppos ){
321 			/* everythings cool do no extra distance */
322 			dist2 = 0 ;
323 		    } else if( lowpos > pos ){
324 			dist2 = ABS( lowpos - pos ) ;
325 			pos = lowpos ;
326 		    } else if( pos > uppos ){
327 			dist2 = ABS( pos - uppos ) ;
328 			pos = uppos ;
329 		    }
330 		    /* modify the distance by it Manhattan length */
331 		    /* to the pad in the orthogonal direction */
332 		    /* since this pad is fixed at a point */
333 /* could modify this to be more accurate since we want matching padpin*/
334 		    dist += dist2 ;
335 		}
336 		if (dist < bestdist) {
337 		    bestdist = dist;    /*** UPDATE THE BEST DISTANCE */
338 		    bestpos  = pos;     /*** AND BEST POSITION        */
339 		    besttie = tiebreak; /* save the original position */
340 		    pinFound = TRUE ;   /* pin on this net was found */
341 		}
342 	    } /* for(;netterm... end looking at this net */
343 
344 	    if( pinFound ){
345 		/*** SUM UP THE BEST POSITION OF ALL PINS       */
346 		sumposS  += bestpos ;
347 		sumtieS += besttie ;
348 
349 		/*** KEEP TRACK OF THE TOTAL COST FOR THIS SIDE */
350 		cost += bestdist;
351 		pin_countS++ ;
352 	    }
353 	} /* end for loop on pins of the pad */
354 
355 	/*** IF NO PIN IS FOUND TO MATCH WITH PAD ARBITRARILY ***/
356 	/*** SET best position to random number for THIS PAD ***/
357 	if( pin_countS == 0 ){
358 	    if( spacing_restricted ){
359 		/* average between constraints */
360 		sumposS = (lowpos + uppos) / 2 ;
361 	    } else {
362 		/*
363 		    Randomly pick a cost to break ties in the
364 		    case that this pad could go on any side. Small
365 		    value will not effect padgroups
366 		*/
367 		cost = PICK_INT( 0, 3 ) ;
368 		switch (side) {
369 		case L:
370 		    sumposS = PICK_INT( coreG[Y][MINI],coreG[Y][MAXI] ) ;
371 		    break;
372 		case T:
373 		    sumposS = PICK_INT( coreG[X][MINI],coreG[X][MAXI] ) ;
374 		    break;
375 		case R:
376 		    sumposS = PICK_INT( coreG[Y][MINI],coreG[Y][MAXI] ) ;
377 		    break;
378 		case B:
379 		    sumposS = PICK_INT( coreG[X][MINI],coreG[X][MAXI] ) ;
380 		    break;
381 		default:
382 		    break;
383 		}
384 	    }
385 	    sumtieS = sumposS ;
386 	} /* end pin_countS == 0 */
387 
388 	return( cost ) ;
389 
390      } else {
391 
392 	/***
393 	    IF THE PAD IS A SUPERPAD, THEN SEARCH THROUGH ALL ***
394 	    ITS CHILDREN AND SUM THE COST AND IDEAL POSITION  ***
395 	    RECURSIVELY.  Use the spacing restrictions derived above.
396 	***/
397 
398 
399 	for( i = 1 ;i <= pad->children[HOWMANY]; i++ ){
400 	    child = padarrayG[pad->children[i]];
401 	    cost += find_cost_for_a_side( child, side,
402 		lb, ub, spacing_restricted ) ;
403 	}
404 	return( cost );
405     }
406 } /* end find_cost_for_a_side */
407 /* ***************************************************************** */
408 
409 /**** SET POSITION OF THE PAD.  POS IS THE SUM OF THE OPTIMAL POSITION
410  **** FOR ALL TERMINALS OF THE PAD. WE DIVIDE BY THE NUMBER OF TERMINAL
411  **** TO GET THE AVERAGE.  Place_pad must be performed immediately
412  **** after a find_cost_for_a_side since sumposS and sumtieS
413  **** are set in those routines.  Otherwise set sumposS and sumtieS
414  **** to their proper values.
415  ***/
place_pad(pad,bestside)416 static void place_pad( pad, bestside )
417 PADBOXPTR pad ;
418 INT bestside ;
419 {
420 
421     /* use the number of pins with valid connections */
422     /* pin_countS is set inf find_cost_for_a_side */
423     if( pin_countS == 0 ){
424 	/*** SET PAD TO RANDOM POSITION DETERMINED IN find_cost_for_side*/
425 	pad->position = sumposS ;
426 	pad->tiebreak = sumtieS ;
427     } else {
428 	pad->position = sumposS / pin_countS ;
429 	pad->tiebreak = sumtieS / pin_countS ;
430     }
431     /* now bound pad center to current core boundary for normal case */
432     pad->padside = bestside ;
433 #ifdef LATER
434     switch( bestside ){
435 	case L:
436 	case R:
437 	    pad->position = MAX( pad->position, coreG[Y][MINI] ) ;
438 	    pad->position = MIN( pad->position, coreG[Y][MAXI] ) ;
439 	    break;
440 	case T:
441 	case B:
442 	    pad->position = MAX( pad->position, coreG[X][MINI] ) ;
443 	    pad->position = MIN( pad->position, coreG[X][MAXI] ) ;
444     } /* end bound of pad position */
445 #endif
446 
447 } /* end place_pad */
448 /* ***************************************************************** */
449 
450 
451 
452 /**** RECURSIVELY SET THE PADSIDE OF ALL CHILDREN OF THE ROOT PAD TO THE
453  **** PADSIDE OF THE PARENT. GIVEN THAT SIDE, SET THE OPTIMAL CXCENTER */
place_children(pad,side,lb,ub,spacing_restricted)454 static void place_children( pad, side, lb, ub, spacing_restricted )
455 PADBOXPTR pad ;
456 INT side ;
457 DOUBLE lb, ub ;
458 BOOL spacing_restricted ;
459 {
460     INT i ;           /* pad counter */
461     INT pos ;         /* position of last placed pad */
462     INT min_pos ;     /* min position of the last padgroup */
463     INT max_pos ;     /* max position of the last padgroup */
464     DOUBLE lowbound ; /* lower bound for pad or pad group */
465     DOUBLE hibound ;  /* upper bound for pad or pad group */
466     PADBOXPTR child;  /* go thru the children of the padgroup */
467 
468     /* DETERMINE SPACING RESTRICTIONS */
469     lowbound = 0.0 ;
470     hibound = 1.0 ;
471     if( spacing_restricted ){
472 	/* this is the case that the spacing has been restricted */
473 	if( pad->fixed ){
474 	    /* if the padgroup bounds have been fixed, */
475 	    /* force position to be within bound */
476 	    /* assume we are ok and then correct it */
477 	    lowbound = pad->lowerbound ;
478 	    if( lowbound < lb ){
479 		lowbound = lb ;
480 	    }
481 	    if( lowbound > ub ){
482 		lowbound = ub ;
483 	    }
484 	    hibound = pad->upperbound ;
485 	    if( hibound < lb ){
486 		hibound = lb ;
487 	    }
488 	    if( hibound > ub ){
489 		hibound = ub ;
490 	    }
491 	} else {
492 	    /* this pad is not fixed use the given ub and lb */
493 	    lowbound = lb ; hibound = ub ;
494 	}
495     } else {
496 	if( pad->fixed ){
497 	    /* the padgroup bounds have not been fixed */
498 	    /* just take the pad's restricted position */
499 	    lowbound = pad->lowerbound;
500 	    hibound = pad->upperbound;
501 	    spacing_restricted = TRUE ;
502 	}
503     }
504     /* **** END spacing restriction calculations *** */
505 
506     if( pad->hierarchy == LEAF ){
507 	find_cost_for_a_side( pad, side,
508 	    lowbound, hibound, spacing_restricted ) ;
509 	place_pad( pad, side ) ;
510 	return ;
511     } else {
512 	pos = 0 ;
513 	min_pos = INT_MAX ;
514 	max_pos = INT_MIN ;
515 	for( i = 1; i <= pad->children[HOWMANY]; i++ ){
516 	    child = padarrayG[pad->children[i]];
517 	    place_children( child, side, lowbound, hibound, spacing_restricted ) ;
518 	    pos += child->position ;
519 	    min_pos = MIN( child->position, min_pos ) ;
520 	    max_pos = MAX( child->position, max_pos ) ;
521 	}
522 	if( pad->children[HOWMANY] ){
523 	    pad->position = pos /= pad->children[HOWMANY] ;
524 	} else {
525 	    pad->position = pos ;
526 	}
527 	/* for tiebreak use the bounds of the padgroup and average them. */
528 	/* set the side of the pad */
529 	pad->padside = side ;
530 	pad->tiebreak = (min_pos + max_pos ) / 2 ;
531 	return ;
532     }
533 } /* end place_children */
534 /* ***************************************************************** */
535 
536 
537 
538 
539 /* ***************************************************************** */
540 #ifdef DEBUG
print_pads(message,array,howmany)541 void print_pads( message, array, howmany )
542 char *message ;
543 PADBOXPTR *array ;
544 INT howmany ;
545 {
546     INT i ;
547     PADBOXPTR ptr ;
548     CBOXPTR   cptr ;
549 
550     fprintf( stderr, "\n%s\n", message ) ;
551 
552     /* now print them out */
553     for( i = 1 ; i <= howmany; i++ ){
554 	ptr = array[i] ;
555 	cptr = carrayG[ ptr->cellnum ] ;
556 	fprintf( stderr,
557 	    "pad:%s x:%d y:%d type:%d side:%d pos:%d tie:%d orient:%d\n",
558 	    cptr->cname, cptr->cxcenter, cptr->cycenter, ptr->hierarchy,
559 	    ptr->padside, ptr->position, ptr->tiebreak, cptr->corient ) ;
560     }
561     fprintf( stderr, "\n" ) ;
562 
563     dimension_pads() ;
564     G( process_graphics() ) ;
565 
566 } /* end print_pads */
567 
568 #endif /* DEBUG */
569 /* ***************************************************************** */
570 
571 
find_core()572 static void find_core()
573 {
574     INT minx, maxx ;
575     INT miny, maxy ;
576     INT l, r, b, t ;
577     INT i ;
578     INT num ;
579     INT cell ;
580     INT block ;
581     INT xc, yc ;
582     BBOXPTR bptr ;
583 
584     /* initialize xmin, ymax, etc. */
585     minx = INT_MAX ;
586     miny = INT_MAX ;
587     maxx = INT_MIN ;
588     maxy = INT_MIN ;
589     if( virtualCoreS ){
590 
591 	for( block = 1 ; block <= numRowsG ; block++ ) {
592 	    num = pairArrayG[block][0] ;
593 	    if( num == 0 ) {
594 		continue ;
595 	    }
596 	    cell = pairArrayG[block][ 1 ] ;
597 	    l = carrayG[cell]->cxcenter + carrayG[cell]->tileptr->left ;
598 	    cell = pairArrayG[block][ pairArrayG[block][0] ] ;
599 	    r  = carrayG[cell]->cxcenter + carrayG[cell]->tileptr->right ;
600 	    minx = MIN( minx, l ) ;
601 	    maxx = MAX( maxx, r ) ;
602 	}
603 	cell = pairArrayG[1][ 1 ] ;
604 	b = carrayG[cell]->cycenter + carrayG[cell]->tileptr->bottom ;
605 	miny = MIN( miny, b ) ;
606 	cell = pairArrayG[numRowsG][ 1 ] ;
607 	t = carrayG[cell]->cycenter + carrayG[cell]->tileptr->top ;
608 	maxy = MAX( maxy, t ) ;
609 
610     } else {
611 	for( block = 1 ; block <= numRowsG ; block++ ) {
612 	    bptr = barrayG[block] ;
613 	    xc = bptr->bxcenter ;
614 	    yc = bptr->bycenter ;
615 	    minx = MIN( minx, bptr->bleft + xc ) ;
616 	    maxx = MAX( maxx, bptr->bright + xc ) ;
617 	    miny = MIN( miny, bptr->bbottom + yc ) ;
618 	    maxy = MAX( maxy, bptr->btop + yc ) ;
619 	}
620     }
621     /* now check macro cells if they exist */
622     for( i=numcellsG+1;i<=lastpadG;i++ ){
623 	if( carrayG[i]->padptr->macroNotPad ){
624 	    /* only calculate position if it is a macro */
625 	    get_global_pos( i, &l, &b, &r, &t ) ;
626 
627 	    minx = MIN( minx, l ) ;
628 	    maxx = MAX( maxx, r ) ;
629 	    miny = MIN( miny, b ) ;
630 	    maxy = MAX( maxy, t ) ;
631 	}
632     }
633 
634     /* now guarantee space between core and pads */
635     minx -= track_pitchG ;
636     miny -= track_pitchG ;
637     maxx += track_pitchG ;
638     maxy += track_pitchG ;
639 
640     /* now save the dimensions */
641     coreG[Y][MINI]  = miny ;
642     coreG[Y][MAXI]  = maxy ;
643 
644     coreG[X][MINI]  = minx ;
645     coreG[X][MAXI]  = maxx ;
646 
647     perdimG[X] = maxx - minx ;
648     perdimG[Y] = maxy - miny ;
649 
650 } /* end FindCore */
651 
652 /* turn virtual core on and off */
setVirtualCore(flag)653 void setVirtualCore( flag )
654 BOOL flag ;
655 {
656     virtualCoreS = flag ;
657 } /* end set Virtual core */
658 
659 
660 /* given a cell it returns bounding box of cell in global coordinates */
get_global_pos(INT cell,INT * l,INT * b,INT * r,INT * t)661 void get_global_pos(INT cell, INT *l, INT *b, INT *r, INT *t )
662 {
663 
664     CBOXPTR ptr ;
665 
666     ptr = carrayG[cell] ;
667     *l = ptr->tileptr->left ;
668     *r = ptr->tileptr->right ;
669     *b = ptr->tileptr->bottom ;
670     *t = ptr->tileptr->top ;
671     YtranslateT( l, b, r, t, (INT) ptr->corient ) ;
672 
673     /* now add xcenter ycenter to get global position */
674     *l += ptr->cxcenter ;
675     *r += ptr->cxcenter ;
676     *b += ptr->cycenter ;
677     *t += ptr->cycenter ;
678 
679 } /* end get_global_pos */
680 
placepads_retain_side(flag)681 void placepads_retain_side( flag )
682 BOOL flag;
683 {
684     retain_sideS = flag ;
685 } /* end placepads_retain_side */
686