1 /*
2  *   Copyright (C) 1988-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:	    paths.c
42 DESCRIPTION:output length of paths
43 CONTENTS:   print_paths.
44 	    INT calc_incr_time( cell )
45 		INT cell ;
46 	    update_time( cell )
47 		INT cell ;
48 	    INT calc_incr_time2( cella, cellb )
49 		INT cella, cellb ;
50 	    update_time2( cella, cellb )
51 		INT cella, cellb ;
52 	    init_path_set()
53 	    add2path_set( path )
54 		INT  path ;
55 	    PSETPTR enum_path_set()
56 	    clear_path_set()
57 	    init_net_set()
58 	    add2net_set( net )
59 		INT  net ;
60 	    BOOL member_net_set( net )
61 	    clear_net_set()
62 	    INT dcalc_full_penalty()
63 	    INT dcalc_path_len(path_num)
64 		INT path_num ;
65 DATE:	    Oct	22, 1988
66 REVISIONS:  Dec  3, 1988 - completed timing driven code.
67 	    Jan 29, 1989 - added \n's for pretty output.
68 	    Mar 11, 1989 - added statistics to print_paths.
69 			 - added wirelength to print_paths.
70 	    Mar 13, 1989 - now output penalty in print_paths.
71 	    Fri Jan 18 18:32:01 PST 1991 - updated output format.
72 	    Sun Jan 20 21:34:36 PST 1991 - ported to AIX.
73 ----------------------------------------------------------------- */
74 
75 #include <custom.h>
76 #include <yalecad/debug.h>
77 #include <yalecad/file.h>
78 #include <yalecad/stat.h>
79 
80 /* Forward declarations */
81 
82 INT dcalc_min_path_len();
83 INT dcalc_max_path_len();
84 void add2path_set( INT path );
85 void clear_path_set();
86 
print_paths()87 void print_paths( )
88 {
89 
90     char filename[LRECL] ;
91     PATHPTR pptr, get_path_list() ;
92     GLISTPTR net ;
93     NETBOXPTR nptr ;
94     PINBOXPTR netptr ;
95     FILE *fp ;
96     DOUBLE mean ;
97     DOUBLE paths ;
98     BOOL pad ;
99     INT *stat ;
100     INT num_paths ;
101     INT length ;
102     INT pathLength ;
103     INT loLength ;
104     INT hiLength ;
105     INT i = 0 ;
106     INT xspan ;
107     INT yspan ;
108     INT in = 0 ;
109     INT above = 0 ;
110     INT below = 0 ;
111     INT penalty  = 0 ;
112     INT way_above = 0 ;
113     INT way_below = 0 ;
114     INT really_above = 0 ;
115     INT really_below = 0 ;
116     INT really_way_above = 0 ;
117     INT really_way_below = 0 ;
118 
119     /* get total number of paths in timing analysis */
120     num_paths = get_total_paths() ;
121     /* allocate the an array for calculating statistics */
122     if( num_paths ){
123 	stat = (INT *) Ysafe_malloc( num_paths * sizeof(INT) ) ;
124     }
125     sprintf(filename, "%s.mpth" , cktNameG ) ;
126     fp = TWOPEN( filename , "w", ABORT ) ;
127     /* first the lengths of the nets */
128     fprintf( fp, "The paths:\n" ) ;
129     fprintf( fp, "##############################################\n" ) ;
130     for( pptr=get_path_list() ;pptr;pptr=pptr->next ){
131 	pathLength = 0 ;
132 	loLength = 0 ;
133 	hiLength = 0 ;
134 	xspan = 0 ;
135 	yspan = 0 ;
136 
137 	/* get pathLength for path */
138 	fprintf( fp, "path %3d:\n",++i ) ;
139 	for( net = pptr->nets ; net ; net = net->next ){
140 	    nptr = netarrayG[net->p.net] ;
141 	    fprintf( fp, "\t\t%s\n", nptr->nname ) ;
142 	    length = nptr->halfPx +
143 		(INT)(vertical_path_weightG * (DOUBLE) nptr->halfPy) ;
144 	    xspan += nptr->halfPx ;
145 	    yspan += nptr->halfPy ;
146 	    pathLength += length ;
147 	    loLength = loLength + (INT)
148 		(nptr->max_driver * (FLOAT)length + nptr->driveFactor);
149 	    hiLength = hiLength + (INT)
150 		(nptr->min_driver * (FLOAT)length + nptr->driveFactor);
151 	}
152 	fprintf( fp, "\tpriority:%d lower bound:%d upper bound:%d\n",
153 	    pptr->priority, pptr->lower_bound, pptr->upper_bound ) ;
154 	fprintf( fp,"\tweighted length:%d fast driver len:%d slow driver len:%d\n",
155 	    pathLength, loLength, hiLength ) ;
156 	fprintf( fp, "\txspan:%d yspan:%d length:%d\n", xspan, yspan,
157 	    xspan+yspan ) ;
158 	if( pptr->priority ){
159 	    ASSERT( loLength == pptr->lo_path_len,"print_paths",
160 		"lo_pathLength does not equal incremental value " ) ;
161 	    ASSERT( hiLength == pptr->hi_path_len,"print_paths",
162 		"hi_pathLength does not equal incremental value " ) ;
163 	}
164 	if( loLength < pptr->lower_bound ){
165 	    penalty += pptr->lower_bound - loLength ;
166 	    /* look for paths with some slack on bound */
167 	    if( loLength < (INT)( 0.90 * (DOUBLE) pptr->lower_bound) ){
168 		below++ ;
169 
170 		/* check if this path has a net with a pad in it */
171 		pad = FALSE ;
172 		for( net = pptr->nets ; net ; net = net->next ){
173 		    netptr = netarrayG[net->p.net]->pins ;
174 		    for( ; netptr ; netptr = netptr->next ) {
175 			if( netptr->cell > numcellsG ) {
176 			    pad = TRUE ;
177 			    break ;
178 			}
179 		    }
180 		}
181 		if( !pad ) {
182 		    really_below++ ;
183 		}
184 	    }
185 	    if( loLength < (INT)( 0.80 * (DOUBLE) pptr->lower_bound) ){
186 		way_below++ ;
187 		if( !pad ) {
188 		    really_way_below++ ;
189 		}
190 	    }
191 	} else if( hiLength > pptr->upper_bound ){
192 	    penalty += hiLength - pptr->upper_bound ;
193 	    if( hiLength > (INT)( 1.10 * (DOUBLE) pptr->upper_bound) ){
194 		above++ ;
195 
196 		pad = FALSE ;
197 		for( net = pptr->nets ; net ; net = net->next ){
198 		    netptr = netarrayG[net->p.net]->pins ;
199 		    for( ; netptr ; netptr = netptr->next ) {
200 			if( netptr->cell > numcellsG ) {
201 			    pad = TRUE ;
202 			    break ;
203 			}
204 		    }
205 		}
206 		if( !pad ) {
207 		    really_above++ ;
208 		}
209 	    }
210 	    if( hiLength > (INT)( 1.20 * (DOUBLE) pptr->upper_bound) ){
211 		way_above++ ;
212 		if( !pad ) {
213 		    really_way_above++ ;
214 		}
215 	    }
216 	} else {
217 	    in++ ;
218 	}
219 	/* add pathlength to stat array */
220 	stat[i-1] = pathLength ;
221 
222     }
223     /* first the lengths of the nets */
224     fprintf( fp, "\nThe nets:\n" ) ;
225     fprintf( fp, "##############################################\n" ) ;
226     for( i=1;i<=numnetsG;i++ ){
227 	nptr = netarrayG[i] ;
228 	fprintf( fp, "net %3d:%s xspan:%d yspan:%d length:%d numpins:%d\n",
229 	    i, nptr->nname, nptr->halfPx, nptr->halfPy,
230 	    nptr->halfPx + nptr->halfPy, nptr->numpins ) ;
231     }
232     /* avoid a divide by zero */
233     if( num_paths ){
234 	paths = (DOUBLE) num_paths ;
235 	fprintf( fp, "\nSummary:\n" ) ;
236 	fprintf( fp, "Total wirelength               :%5d\n", funccostG ) ;
237 	fprintf( fp, "Total time penalty             :%5d\n", penalty ) ;
238 	fprintf( fp, "Number of paths                :%5d\n", num_paths ) ;
239 	fprintf( fp, "Number of active paths         :%5d\n", numpathsG ) ;
240 	fprintf( fp, "Number of paths 10%% below spec :%5d - %4.2f%%\n",
241 	    below, 100.0 * (DOUBLE) below / paths ) ;
242 	fprintf( fp, "Number of paths 10%% above spec :%5d - %4.2f%%\n",
243 	    above, 100.0 * (DOUBLE) above / paths ) ;
244 	fprintf( fp, "Number of paths within  spec   :%5d - %4.2f%%\n",
245 	    in, 100.0 * (DOUBLE) in / paths ) ;
246 	fprintf( fp, "# of non-pad paths out of spec :%5d\n", really_above +
247 						really_below ) ;
248 	fprintf( fp, "Number of paths 20%% below spec :%5d - %4.2f%%\n",
249 	    way_below, 100.0 * (DOUBLE) way_below / paths ) ;
250 	fprintf( fp, "Number of paths 20%% above spec :%5d - %4.2f%%\n",
251 	    way_above, 100.0 * (DOUBLE) way_above / paths ) ;
252 	fprintf( fp, "# of non-pad paths out of spec :%5d\n",
253 				really_way_above + really_way_below ) ;
254 	fprintf( fp, "Min  length                    :%4.2le\n",
255 	    Ystat_min( stat, num_paths, sizeof(INT) ) ) ;
256 	fprintf( fp, "Max  length                    :%4.2le\n",
257 	    Ystat_max( stat, num_paths, sizeof(INT) ) ) ;
258 	mean = Ystat_mean( stat, num_paths, sizeof(INT) ) ;
259 	fprintf( fp, "Mean length                    :%4.2le\n", mean ) ;
260 	fprintf( fp, "Standard Dev. length           :%4.2le\n",
261 	    sqrt( Ystat_var( stat, num_paths, sizeof(INT),mean) ) ) ;
262 	Ysafe_free( stat ) ;
263     }
264     TWCLOSE( fp ) ;
265 
266 } /* end print_paths */
267 
268 /* -----------------------------------------------------------------
269     The update path routines
270     The incremental routines speed execution by looking at only those
271     paths connected to the cells that are to be moved.  In addition,
272     only those nets which are modified by the move are updated.  This
273     gives us an incremental length which we add to old half perimeter
274     to give us total lenght of this net.  The penalty is based on this
275     length.  We calculate an incremental penalty based on the change
276     in the penalty.
277 ----------------------------------------------------------------- */
278 /* calculate the timing cost incrementally */
calc_incr_time(cell)279 INT calc_incr_time( cell )
280 INT cell ;
281 {
282     INT newpenal ;        /* proposed move's timing penalty delta */
283     INT oldpenal ;        /* the old penalty of the nets that move */
284     INT length ;          /* path length incremental */
285     INT loLength ;        /* lo path length incremental */
286     INT hiLength ;        /* hi path length incremental */
287     INT path_num ;        /* name of path */
288     INT net ;             /* net of path */
289     GLISTPTR pptr ;       /* pointer to paths of a cell */
290     GLISTPTR net_of_path ;
291     PATHPTR path ;
292     NETBOXPTR dimptr ;
293 
294     newpenal = 0 ;
295     oldpenal = 0 ;
296     /* for all paths of the cell that has moved */
297     for( pptr = cellarrayG[cell]->paths; pptr ; pptr = pptr->next ) {
298 
299 	path_num = pptr->p.path ;
300 	ASSERTNCONT( path_num > 0 && path_num <= numpathsG,
301 	    "calc_incr_time", "path is out of bounds" ) ;
302 	path = patharrayG[path_num] ;
303 	/* for all nets k of a path i */
304 	loLength = 0 ;
305 	hiLength = 0 ;
306 	for( net_of_path=path->nets;net_of_path;
307 	    net_of_path=net_of_path->next ){
308 	    net = net_of_path->p.net ;
309 
310 	    dimptr = netarrayG[net] ;
311 
312 	    /* accumulate length of path */
313 	    if( member_net_set( net ) ){
314 		/* this half - perimeter has changed use update */
315 		/* calculate total change on path */
316 		length = ( dimptr->newhalfPx - dimptr->halfPx +
317 		    (INT)(vertical_path_weightG * (DOUBLE)dimptr->newhalfPy) -
318 		    (INT)(vertical_path_weightG * (DOUBLE)dimptr->halfPy) );
319 		loLength = loLength + (INT) (dimptr->max_driver * (FLOAT) length +
320 		    dimptr->driveFactor ) ;
321 		hiLength = hiLength + (INT) (dimptr->min_driver * (FLOAT) length +
322 		    dimptr->driveFactor ) ;
323 	    } /* else this half - perimeter has not changed use old */
324 	}
325 	/* save total result - change to total length */
326 	path->new_lo_path_len = loLength += path->lo_path_len ;
327 	path->new_hi_path_len = hiLength += path->hi_path_len ;
328 
329 	ASSERT( loLength == dcalc_min_path_len(path_num), NULL, NULL ) ;
330 	ASSERT( hiLength == dcalc_max_path_len(path_num), NULL, NULL ) ;
331 
332 	/* calculate change in timing penalty */
333 	/* no penalty if within target window */
334 	/* lowerbound <= length <= upperbound */
335 	if( hiLength > path->upper_bound ){
336 	    newpenal += hiLength - path->upper_bound ;
337 	} else if( loLength < path->lower_bound ){
338 	    newpenal += path->lower_bound - loLength ;
339 	}
340 	/* now the old penalty */
341 	if( path->hi_path_len > path->upper_bound ){
342 	    oldpenal += path->hi_path_len - path->upper_bound ;
343 	} else if( path->lo_path_len < path->lower_bound ){
344 	    oldpenal += path->lower_bound - path->lo_path_len ;
345 	}
346     }
347     /* return the change in penalty */
348     return( newpenal - oldpenal ) ;
349 
350 } /* end function calc_incr_time */
351 
352 
update_time(cell)353 void update_time( cell )
354 INT cell ;
355 {
356 
357     INT path_num ;        /* name of path */
358     GLISTPTR pptr ;       /* pointer to paths of a cell */
359     PATHPTR path ;
360 
361     /* for all paths of the cell that has moved */
362     for( pptr = cellarrayG[cell]->paths; pptr ; pptr = pptr->next ) {
363 
364 	path_num = pptr->p.path ;
365 	ASSERTNCONT( path_num > 0 && path_num <= numpathsG,
366 	    "update_time", "path is out of bounds" ) ;
367 	path = patharrayG[path_num] ;
368 	/* keep result */
369 	path->lo_path_len = path->new_lo_path_len ;
370 	path->hi_path_len = path->new_hi_path_len ;
371     }
372 
373 } /* end function update_time */
374 
375 /* calculate the timing cost incrementally for two cells */
calc_incr_time2(cella,cellb)376 INT calc_incr_time2( cella, cellb )
377 INT cella ;
378 INT cellb ;
379 {
380     INT newpenal ;        /* proposed move's timing penalty delta */
381     INT oldpenal ;        /* the old penalty of the nets that move */
382     INT length ;          /* incremental path length */
383     INT loLength ;        /* lo path length incremental */
384     INT hiLength ;        /* hi path length incremental */
385     INT path_num ;        /* name of path */
386     INT net ;             /* net of path */
387     GLISTPTR pptr ;       /* pointer to paths of a cell */
388     GLISTPTR net_of_path ;
389     PATHPTR path ;
390     PSETPTR pathlist, enum_path_set() ;
391     NETBOXPTR dimptr ;
392 
393     newpenal = 0 ;
394     oldpenal = 0 ;
395     clear_path_set() ;
396 
397     /* use add2path_set to get union of paths from cella and cellb */
398     for( pptr = cellarrayG[cella]->paths; pptr ; pptr = pptr->next ) {
399 	add2path_set( pptr->p.path ) ;
400     }
401     for( pptr = cellarrayG[cellb]->paths; pptr ; pptr = pptr->next ) {
402 	add2path_set( pptr->p.path ) ;
403     }
404 
405 
406     /* now use UNIQUE list of the union of the two cell's paths */
407     for( pathlist=enum_path_set(); pathlist; pathlist=pathlist->next){
408 
409 	path_num = pathlist->path ;
410 	ASSERTNCONT( path_num > 0 && path_num <= numpathsG,
411 	    "calc_incr_time2", "path is out of bounds" ) ;
412 	path = patharrayG[path_num] ;
413 
414 	/* for all nets k of a path i */
415 	loLength = 0 ;
416 	hiLength = 0 ;
417 	for( net_of_path=path->nets;net_of_path;
418 	    net_of_path=net_of_path->next ){
419 	    net = net_of_path->p.net ;
420 
421 	    dimptr = netarrayG[net] ;
422 
423 	    /* accumulate length of path */
424 	    if( member_net_set( net ) ){
425 		/* this half - perimeter has changed use update */
426 		/* calculate total change on path */
427 		length = ( dimptr->newhalfPx - dimptr->halfPx +
428 		    (INT)(vertical_path_weightG * (DOUBLE)dimptr->newhalfPy) -
429 		    (INT)(vertical_path_weightG * (DOUBLE)dimptr->halfPy) );
430 		loLength = loLength + (INT) (dimptr->max_driver * (FLOAT) length +
431 		    dimptr->driveFactor ) ;
432 		hiLength = hiLength + (INT) (dimptr->min_driver * (FLOAT) length +
433 		    dimptr->driveFactor ) ;
434 	    } /* else this half - perimeter has not changed use old */
435 	}
436 	/* save total result - change to total length */
437 	path->new_lo_path_len = loLength += path->lo_path_len ;
438 	path->new_hi_path_len = hiLength += path->hi_path_len ;
439 
440 	ASSERT( loLength == dcalc_min_path_len(path_num), NULL, NULL ) ;
441 	ASSERT( hiLength == dcalc_max_path_len(path_num), NULL, NULL ) ;
442 
443 	/* calculate change in timing penalty */
444 	/* no penalty if within target window */
445 	/* lowerbound <= length <= upperbound */
446 	if( hiLength > path->upper_bound ){
447 	    newpenal += hiLength - path->upper_bound ;
448 	} else if( loLength < path->lower_bound ){
449 	    newpenal += path->lower_bound - loLength ;
450 	}
451 	/* now the old penalty */
452 	if( path->hi_path_len > path->upper_bound ){
453 	    oldpenal += path->hi_path_len - path->upper_bound ;
454 	} else if( path->lo_path_len < path->lower_bound ){
455 	    oldpenal += path->lower_bound - path->lo_path_len ;
456 	}
457     }
458     /* return the change in penalty */
459     return( newpenal - oldpenal ) ;
460 
461 } /* end function calc_incr_time2 */
462 
update_time2(cella,cellb)463 void update_time2( cella, cellb )
464 INT cella, cellb ;
465 {
466     INT path_num ;        /* name of path */
467     PATHPTR path ;
468     PSETPTR pathlist, enum_path_set() ;
469 
470     /* now use UNIQUE list of the union of the two cell's paths */
471     for( pathlist=enum_path_set(); pathlist; pathlist=pathlist->next){
472 
473 	DS( path_num = pathlist->path ; ) ;
474 	ASSERTNCONT( path_num > 0 && path_num <= numpathsG,
475 	    "update_time2", "path is out of bounds" ) ;
476 	path = patharrayG[pathlist->path] ;
477 	/* keep result */
478 	path->lo_path_len = path->new_lo_path_len ;
479 	path->hi_path_len = path->new_hi_path_len ;
480     }
481 
482 } /* end function update_time */
483 /* -----------------------------------------------------------------
484    The set required in the update path routines needs the following
485    operations done efficiently :
486        membership - O(1)
487        add to set if unique - O(1)
488        clear set  - O(1)
489        set enumeration - O( paths in set )
490 Below is a space hungry O( numpaths ) but time efficient implementation
491 We combine two data structures to accomplish this goal. We use array
492 for testing membership and uniqueness but use list for enumeration.
493 By incrementing count we can reinitialize easily.
494 Note: PSETBOX, PSETPTR definitions are in custom.h
495 ----------------------------------------------------------------- */
496 static PSETPTR path_set_listS ;   /* list is beginning of set as a list */
497 static PSETPTR *path_set_arrayS ; /* set is an array of path set boxes */
498 static INT path_set_countS ;      /* current set count */
499 
500 /* initialize set */
init_path_set()501 void init_path_set()
502 {
503     INT i ;
504 
505     path_set_arrayS=(PSETPTR *)Ysafe_malloc((numpathsG+1)*sizeof(PSETPTR));
506     for( i=0;i<=numpathsG;i++ ){
507 	path_set_arrayS[i] = (PSETPTR) Ysafe_calloc( 1, sizeof(PSETBOX) ) ;
508     }
509     path_set_countS = 1 ;
510     path_set_listS = NULL ;
511 } /* end initset */
512 
513 /* add a path to the set if not already in set */
add2path_set(INT path)514 void add2path_set( INT path )
515 {
516     PSETPTR temp, cpath ;
517 
518     if( path >= 1 || path <= numpathsG ){
519 	cpath = path_set_arrayS[path] ;
520 	/* something is a member in set is counts match */
521 	if( cpath->member != path_set_countS ){
522 	    /* new path to be added */
523 	    /* connect to the single linked list */
524 	    if( temp = path_set_listS ){
525 		/* hook to old list */
526 		path_set_listS = cpath ;
527 		cpath->next = temp ;
528 	    } else {
529 		path_set_listS = cpath ;
530 		/* terminate new list */
531 		cpath->next = NULL ;
532 	    }
533 	    cpath->path = path ; /* store data */
534 	    cpath->member = path_set_countS ; /* store membership */
535 	}
536 
537     } else {
538 	M( ERRMSG, "ADD2SET","value of path is out of bounds of set\n" ) ;
539     }
540 } /* end add2path_set */
541 
enum_path_set()542 PSETPTR enum_path_set()
543 {
544     return( path_set_listS ) ;
545 }
546 
clear_path_set()547 void clear_path_set()
548 {
549     path_set_countS ++ ;
550     path_set_listS = NULL ;
551 } /* end clear_path_set */
552 
553 /* -----------------------------------------------------------------
554    Below is a second set of set routines required in the update path
555    routines which operate on nets instead of paths.  The following
556    operations need to be done efficiently :
557        membership - O(1)
558        add to set if unique - O(1)
559        clear set  - O(1)
560    Since we don't need to enumerate set we only need array to implement
561    this set.
562 ----------------------------------------------------------------- */
563 static INT *net_set_array ; /* set is an array of net set boxes */
564 static INT net_set_count ;      /* current set count */
565 
566 /* initialize set */
init_net_set()567 void init_net_set()
568 {
569     net_set_array = (INT *) Ysafe_calloc((numnetsG+1), sizeof(INT) );
570     net_set_count = 1 ;
571 } /* end initset */
572 
573 /* add a net to the set if not already in set */
add2net_set(net)574 void add2net_set( net )
575 INT  net ;
576 {
577     if( net >= 1 || net <= numnetsG ){
578 	/* current count make array member a valid member of set */
579 	net_set_array[net] = net_set_count ;
580 
581     } else {
582 	M( ERRMSG, "ADD2SET", "value of path is out of bounds of set" ) ;
583     }
584 } /* end add2net_set */
585 
member_net_set(int net)586 BOOL member_net_set( int net )
587 /* test for membership */
588 {
589     if( net_set_array[net] == net_set_count ){
590 	return( TRUE ) ;
591     } else {
592 	return( FALSE ) ;
593     }
594 } /* end member_net_set */
595 
clear_net_set()596 void clear_net_set()
597 {
598     /* to clear set we only need to increment net_set_count */
599     /* we can use this set up to 2 Gig times without any problem */
600     net_set_count ++ ;
601 } /* end clear_path_set */
602 
603 /* debug function to make sure calculation is correct */
dcalc_full_penalty()604 INT dcalc_full_penalty()
605 {
606     INT timingpenal ;
607     INT length ;          /* path length incremental */
608     INT low_length ;      /* lo path length */
609     INT high_length ;     /* hi path length */
610     INT pathcount ;
611     INT net ;             /* net of path */
612     GLISTPTR net_of_path ;
613     PATHPTR path ;
614     NETBOXPTR dimptr ;
615 
616     /* now calculate the penalties */
617     /* first the timing penalty */
618     timingpenal = 0 ;
619     for( pathcount = 1 ; pathcount <= numpathsG ; pathcount++ ) {
620 
621 	path = patharrayG[pathcount] ;
622 	ASSERTNCONT( path, "findcost", "pointer to path is NULL" ) ;
623 	/* for all nets k of a path i */
624 	low_length = 0 ;
625 	high_length = 0 ;
626 	for( net_of_path=path->nets;net_of_path;
627 	    net_of_path=net_of_path->next ){
628 	    net = net_of_path->p.net ;
629 	    dimptr = netarrayG[net] ;
630 
631 
632 	    /* accumulate length of path */
633 	    if( member_net_set( net ) ){
634 		/* this half - perimeter has changed use update */
635 		/* calculate total change on path */
636 		length = dimptr->newhalfPx + (INT)(vertical_path_weightG *
637 			(DOUBLE) dimptr->newhalfPy) ;
638 	    } else {
639 		/* old length */
640 		length = dimptr->halfPx + (INT)(vertical_path_weightG *
641 			(DOUBLE) dimptr->halfPy) ;
642 	    }
643 	    low_length = low_length + (INT)
644 		    (dimptr->max_driver * (FLOAT) length +
645 			    dimptr->driveFactor ) ;
646 	    high_length = high_length + (INT)
647 		    (dimptr->min_driver * (FLOAT) length +
648 			    dimptr->driveFactor ) ;
649 	}
650 	/* calculate penalty */
651 	/* no penalty if within target window */
652 	/* lowerbound <= length <= upperbound */
653 	if( high_length > path->upper_bound ){
654 	    timingpenal += high_length - path->upper_bound ;
655 	} else if( low_length < path->lower_bound ){
656 	    timingpenal += path->lower_bound - low_length ;
657 	}
658     }
659     return( timingpenal ) ;
660 }
661 
dcalc_min_path_len(path_num)662 INT dcalc_min_path_len(path_num)
663 INT path_num ;
664 {
665 
666     INT length ;          /* path length incremental */
667     INT net ;             /* net of path */
668     INT halfP ;           /* the modified half perimeter */
669     GLISTPTR net_of_path ;
670     PATHPTR path ;
671     NETBOXPTR dimptr ;
672 
673     path = patharrayG[path_num] ;
674     /* for all nets k of a path i */
675     length = 0 ;
676     for( net_of_path=path->nets;net_of_path;
677 	net_of_path=net_of_path->next ){
678 	net = net_of_path->p.net ;
679 	dimptr = netarrayG[net] ;
680 
681 	/* accumulate length of path */
682 	if( member_net_set( net ) ){
683 	    /* this half - perimeter has changed use update */
684 	    /* calculate total change on path */
685 	    halfP = dimptr->newhalfPx + (INT)(vertical_path_weightG *
686 		    (DOUBLE) dimptr->newhalfPy) ;
687 	    length = length + (INT) (dimptr->max_driver * halfP +
688 		dimptr->driveFactor ) ;
689 	} else {
690 	    /* old length */
691 	    halfP = dimptr->halfPx + (INT)(vertical_path_weightG *
692 		    (DOUBLE) dimptr->halfPy) ;
693 	    length = length + (INT) (dimptr->max_driver * halfP +
694 		dimptr->driveFactor ) ;
695 	}
696     }
697     return( length ) ;
698 } /* end dcald_min_path_len */
699 
dcalc_max_path_len(path_num)700 INT dcalc_max_path_len(path_num)
701 INT path_num ;
702 {
703 
704     INT length ;          /* path length incremental */
705     INT net ;             /* net of path */
706     INT halfP ;           /* the modified half perimeter */
707     GLISTPTR net_of_path ;
708     PATHPTR path ;
709     NETBOXPTR dimptr ;
710 
711     path = patharrayG[path_num] ;
712     /* for all nets k of a path i */
713     length = 0 ;
714     for( net_of_path=path->nets;net_of_path;
715 	net_of_path=net_of_path->next ){
716 	net = net_of_path->p.net ;
717 	dimptr = netarrayG[net] ;
718 
719 	/* accumulate length of path */
720 	if( member_net_set( net ) ){
721 	    /* this half - perimeter has changed use update */
722 	    /* calculate total change on path */
723 	    halfP = dimptr->newhalfPx + (INT)(vertical_path_weightG *
724 		    (DOUBLE) dimptr->newhalfPy) ;
725 	    length = length + (INT) (dimptr->min_driver * halfP +
726 		dimptr->driveFactor ) ;
727 	} else {
728 	    /* old length */
729 	    halfP = dimptr->halfPx + (INT)(vertical_path_weightG *
730 		    (DOUBLE) dimptr->halfPy) ;
731 	    length = length + (INT) (dimptr->min_driver * halfP +
732 		dimptr->driveFactor ) ;
733 	}
734     }
735     return( length ) ;
736 } /* end dcalc_max_path_len */
737