1 /*
2  *   Copyright (C) 1990-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:	    yreadpar.c
42    DESCRIPTION:     Read a TimberWolf parameter file.
43    CONTENTS:
44    DATE:	    Oct 24, 1990
45    REVISION:        Nov 23, 1990 - Fixed for tab spaces in USER file.
46 		    Dec 21, 1990 - Changed buffer to static so it
47 			won't disappear upon return.
48 		    Sat Jan 26 16:33:03 PST 1991 - added genrows
49 			to list of programs.
50 		    Wed Jan 30 18:35:01 EST 1991 - fixed problem
51 			with numtokens access violation on empty lines.
52 		    Fri Feb 22 23:41:39 EST 1991 - added wildcard
53 			boolean to Yreadpar_next and renamed for Tomus.
54 		    Wed Apr 17 23:32:00 EDT 1991 - Added design rule
55 			information into the .par file.
56 		    Wed Jun  5 16:35:41 CDT 1991 - added overhang and
57 			aspect limit to design rules.  Also fixed
58 			Yreadpar_next problems.
59 		    Mon Aug 12 16:02:33 CDT 1991 - modified for new
60 			Yrbtree_init routine.
61 		    Sat Apr 18 11:29:50 EDT 1992 - added compactor
62 			program entry - CMPT.
63    ----------------------------------------------------------------- */
64 
65 #include <string.h>
66 #include <yalecad/file.h>
67 #include <yalecad/rbtree.h>
68 #include <yalecad/message.h>
69 #include <yalecad/string.h>
70 #include <yalecad/yreadpar.h>
71 
72 #define COMMENT		'#'
73 #define WILDCARD	'*'
74 #define END(v) (v-1 + sizeof(v)/sizeof(v[0]) ) /* for table lookup */
75 #define CHARACTERISTIC	(DOUBLE) 1000.0 ;
76 #define DEFAULT_LAYERS   3
77 #define DEFAULT_VIAS     2
78 
79 /* the rule type definitions */
80 #define CAPACITANCE_T    'c'
81 #define RESISTANCE_T     'r'
82 #define DIRECTION_T      'd'
83 #define LAYER_T          'l'
84 #define WIDTH_T          'w'
85 #define VIA_T            'v'
86 #define SPACING_T        's'
87 #define OVERHANG_T       'o'
88 #define ASPECTLIM_T      'a'
89 
90 #define ERROR_CHECK(type)    \
91 if(!(layerArrayS )){     \
92     M(ERRMSG,"Yreadpar_errorcheck","No rules found in parameter file\n");\
93     return( (type) 0 ) ; \
94 }
95 
96 typedef struct {
97     char *rule ;
98     union {
99 	BOOL bvalue ;
100 	INT ivalue ;
101 	DOUBLE fvalue ;
102 	char *svalue ;
103     } value ;
104 } RULEBOX, *RULEPTR ;
105 
106 static YTREEPTR rule_treeS ;
107 static INT numlayS = 0 ;
108 static INT numviaS = 0 ;
109 static INT alloc_layS = DEFAULT_LAYERS ;
110 static INT alloc_viaS = DEFAULT_VIAS ;
111 static char **layerArrayS = NIL(char **) ;
112 static char **viaArrayS = NIL(char **) ;
113 
114 /* reserved programs binary search */
115 /* -----------------------------------------------------------------
116     The following is table of the reserved words - Table must be in
117     alphabetical order for binary search to work properly.
118 ----------------------------------------------------------------- */
119 static struct ptable_rec {  /* reserved program table */
120     char *program ;      /* program name */
121     INT  program_id ;    /* program id */
122     char *suffix ;       /* program suffix */
123 } pgmtableS[] = {
124     "CMPT",	CMPT,	"cpar",
125     "GENR",	GENR,	"genpar",
126     "MICK",	MICK,	"gpar",
127     "MINC",	MINC,	"mtpar",
128     "PART",	PART,	"ppar",
129     "SGGR",	SGGR,	"sgpar",
130     "TWAR",	TWAR,	"apar",
131     "TWMC",	TWMC,	"mpar",
132     "TWSC",	TWSC,	"spar",
133     "USER",	USER,	"par"
134 } ;
135 
136 typedef struct {
137     char *parameter ;       /* the parameter keyword */
138     char **tokens ;         /* the values of the parameter */
139     INT  numtokens ;        /* number of tokens */
140     INT  program ;          /* name of program */
141 } PARAM, *PARAMPTR ;
142 
143 static FILE *fpS = NIL(FILE *) ;
144 static char copy_bufferS[LRECL] ;
145 static char bufferS[LRECL] ;
146 static INT  filter_idS = 0 ;
147 static INT  prog_idS = 0 ;
148 static INT  lineS = 0 ;
149 static char filterNameS[5] ;
150 static BOOL verboseS = TRUE ;
151 
prog2id(program)152 static INT prog2id( program )
153 char *program ;
154 {
155     INT c ;
156     struct ptable_rec *low = pgmtableS,          /* ptr to beginning */
157 		      *mid ,
158 		      *high = END(pgmtableS) ;   /* ptr to end */
159 
160     /* binary search to look thru table to find pattern match */
161     while( low <= high){
162 	mid = low + (high-low) / 2 ;
163 	if( (c = strcmp(mid->program, program) ) == STRINGEQ){
164 	    return( mid->program_id ) ; /* return token number */
165 	} else if( c < 0 ){
166 	    low = mid + 1 ;
167 	} else {
168 	    high = mid - 1 ;
169 	}
170     }
171     /* at this point we haven't found a match so we have an error */
172     return( UNKN ) ;
173 
174 } /* end prog2id function */
175 
id2prog(id)176 static char *id2prog( id )
177 INT id ;
178 {
179     if( id > 0 && id <= MAXID ){
180 	return( pgmtableS[id-1].program ) ;
181     } else {
182 	return( NIL(char *) ) ;
183     }
184 } /* end id2prog */
185 
id2suffix(id)186 static char *id2suffix( id )
187 INT id ;
188 {
189     if( id > 0 && id <= MAXID ){
190 	return( pgmtableS[id-1].suffix ) ;
191     } else {
192 	return( NIL(char *) ) ;
193     }
194 } /* end id2prog */
195 
196 /* compare routine for design rule processing */
compare_rule(key1,key2)197 static INT compare_rule( key1, key2 )
198 RULEPTR key1, key2 ;
199 {
200     return( (INT)strcmp( key1->rule, key2->rule ) ) ;
201 } /* end compare */
202 
check_layer(layer)203 static BOOL check_layer( layer )
204 char *layer ;
205 {
206     INT i ;        /* counter */
207 
208     verboseS = FALSE ;
209     if( Yreadpar_layer2id( layer ) ){
210 	verboseS = TRUE ;
211 	return( FALSE ) ;
212     } else {
213 	for( i = 1; i <= numviaS; i++ ){
214 	    if( strcmp( Yreadpar_viaId2name( i ), layer ) == STRINGEQ ){
215 		verboseS = TRUE ;
216 		return( FALSE ) ;
217 	    }
218 	}
219     }
220     sprintf( YmsgG,
221 	"Layer or via:%s has not been defined.  Rule ignored.\n", layer) ;
222     M( ERRMSG, "check_layer", YmsgG ) ;
223     verboseS = TRUE ;
224     return( TRUE ) ;
225 } /* end check_layer */
226 
227 
make_data(rule,value,type)228 static char *make_data( rule, value, type )
229 char *rule ;
230 char *value ;
231 char type ;
232 {
233     RULEPTR data ;
234     RULEBOX data_buffer ;
235     DOUBLE  fvalue ;
236     INT     data_value ;
237     char    key[LRECL] ;
238 
239     /* make the key */
240     sprintf( key, "%s:%c", rule, type ) ;
241     data_buffer.rule = key ;
242 
243     /* see if key already exists */
244     if( Yrbtree_search( rule_treeS, (char *) &(data_buffer) ) ){
245 	sprintf( YmsgG, "Rule on line:%d already exists. Ignored.\n", lineS ) ;
246 	M( ERRMSG, "Yreadpar_init", YmsgG ) ;
247 	return( NIL(char *) ) ;
248     }
249 
250     data = YMALLOC( 1, RULEBOX ) ;
251     data->rule = Ystrclone( key ) ;
252 
253     switch( type ){
254     case CAPACITANCE_T:
255     case RESISTANCE_T:
256 	data->value.fvalue = atof( value ) ;
257 	break ;
258     case DIRECTION_T:
259 	/* use the HnotV convention */
260 	if( strcmp( value, "vertical" ) == STRINGEQ ){
261 	    data->value.bvalue = FALSE ;
262 	} else if( strcmp( value, "horizontal" ) == STRINGEQ ){
263 	    data->value.bvalue = TRUE ;
264 	} else {
265 	    M( ERRMSG, "Yreadpar_init", "Unknown layer direction\n" ) ;
266 	}
267 	break ;
268     case LAYER_T:
269 	data->value.ivalue = (INT) value ;
270 	break ;
271     case WIDTH_T:
272 	/* now calculate value */
273 	fvalue = atof( value ) ;
274 
275         /* This code converts the float to an integer
276 	fvalue *= CHARACTERISTIC ;
277 	data_value = ROUND( fvalue ) ;
278 	data->value.ivalue = data_value ;
279         */
280 
281         data->value.fvalue = fvalue ;
282 
283 	break ;
284     case ASPECTLIM_T:
285 	data->value.fvalue = atof( value ) ;
286 	break ;
287     } /* end switch on type */
288 
289     return( (char *) data ) ;
290 
291 } /* end make_data */
292 
make_data2(object1,object2,value,type)293 static char *make_data2( object1, object2, value, type )
294 char *object1 ;
295 char *object2 ;
296 char *value ;
297 char type ;
298 {
299     RULEPTR data ;
300     RULEBOX data_buffer ;
301     DOUBLE  fvalue ;
302     INT     data_value ;
303     char    key[LRECL] ;
304 
305 
306     /* make the key order the key alphabetically */
307     if( strcmp( object1, object2 ) <= STRINGEQ ){
308 	sprintf( key, "%s/%s:%c", object1, object2, type ) ;
309     } else {
310 	sprintf( key, "%s/%s:%c", object2, object1, type ) ;
311     }
312     data_buffer.rule = key ;
313 
314     /* see if key already exists */
315     if( Yrbtree_search( rule_treeS, (char *) &(data_buffer) ) ){
316 	sprintf( YmsgG, "Rule on line:%d already exists. Ignored.\n", lineS ) ;
317 	M( ERRMSG, "Yreadpar_init", YmsgG ) ;
318 	return( NIL(char *) ) ;
319     }
320 
321     data = YMALLOC( 1, RULEBOX ) ;
322     data->rule = Ystrclone( key ) ;
323 
324     switch( type ){
325     case VIA_T:
326 	data->value.svalue = Ystrclone( value ) ;
327 	break ;
328     case SPACING_T:
329 	/* now calculate value */
330 	fvalue = atof( value ) ;
331 
332         /* This code converts the float to an integer
333 	fvalue *= CHARACTERISTIC ;
334 	data_value = ROUND( fvalue ) ;
335 	data->value.ivalue = data_value ;
336         */
337 
338         data->value.fvalue = fvalue ;
339 
340 	break ;
341     }
342     return( (char *) data ) ;
343 } /* end make_data_spacing */
344 
345 
Yreadpar_init(design_name,parfile,filter,abortFlag)346 VOID Yreadpar_init( design_name, parfile, filter, abortFlag )
347 char *design_name ;
348 INT  parfile ;
349 INT  filter ;
350 BOOL abortFlag ;
351 {
352     char *suffix ;              /* parameter file suffix */
353     char *pname ;               /* program name of filter */
354     char filename[LRECL] ;      /* the file name */
355     char *bufferptr ;
356     char **tokens ;
357     INT  i ;                    /* counter */
358     INT  numtokens ;            /* number of tokens on a line */
359     BOOL rule_section ;         /* true if rule section exists */
360     char *data ;                /* rule data to be stored */
361     static BOOL rules_unreadL=TRUE; /* false after the rules have been read */
362 
363     if( suffix = id2suffix( parfile ) ){
364 	prog_idS = parfile ;
365 	sprintf( filename, "%s.%s", design_name, suffix ) ;
366 	if( pname = id2prog( filter )){
367 	    filter_idS = filter ;
368 	    strcpy( filterNameS, pname ) ;
369 	} else {
370 	    M( ERRMSG, "Yreadpar_init", "Unknown filter program\n" ) ;
371 	}
372     } else {
373 	M( ERRMSG, "Yreadpar_init", "Unknown parameter file\n" ) ;
374 	return ;
375     } /* end switch on program */
376 
377     /* now that we have the file name open the par file */
378     if(fpS){
379 	M( ERRMSG, "Yreadpar_init",
380 	    "Only one par file may be read at the same time\n" ) ;
381 	return ;
382     }
383     fpS = TWOPEN( filename, "r", abortFlag ) ;
384     if(!(fpS) ){
385 	return ;
386     }
387     lineS = 0 ;
388     rule_section = FALSE ;
389 
390 
391     /* TRY to read the RULES SECTION of the parameter file */
392     while( bufferptr = fgets( bufferS, LRECL, fpS ) ){
393 	lineS++ ;
394 	/* remove leading blanks */
395 	bufferptr = Yremove_lblanks( bufferptr ) ;
396 	if( *bufferptr == '#' ){
397 	    /* skip over comments */
398 	    continue ;
399 	}
400 	tokens = Ystrparser( bufferptr, " \t\n", &numtokens ) ;
401 	if( numtokens == 0 ){
402 	    continue ;
403 	}
404 	if( strcmp( tokens[0], "RULES" ) == STRINGEQ ){
405 	    rule_section = TRUE ;
406 	    /* initialize tree of rules */
407 	    rule_treeS = Yrbtree_init( compare_rule ) ;
408 	    /* initialize the number of layers */
409 	    layerArrayS = YVECTOR_CALLOC( 1,alloc_layS,char *) ;
410 	    viaArrayS =   YVECTOR_CALLOC( 1,alloc_viaS,char *) ;
411 	    continue ;
412 	} else if( strcmp( tokens[0], "ENDRULES" ) == STRINGEQ ){
413 	    rules_unreadL = FALSE ;
414 	    break ;
415 	}
416 	if( rule_section && rules_unreadL ){
417 	    if( strcmp( tokens[0], "width" ) == STRINGEQ &&
418 		numtokens == 3 ){
419 		if( check_layer( tokens[1] ) ){
420 		    continue ;
421 		}
422 		data = make_data( tokens[1], tokens[2], WIDTH_T ) ;
423 		if( data ){
424 		    Yrbtree_insert( rule_treeS, data ) ;
425 		}
426 	    } else if( strcmp( tokens[0], "spacing" ) == STRINGEQ &&
427 		numtokens == 4 ){
428 		if( check_layer( tokens[1] ) ){
429 		    continue ;
430 		}
431 		if( check_layer( tokens[2] ) ){
432 		    continue ;
433 		}
434 		data = make_data2( tokens[1], tokens[2], tokens[3], SPACING_T ) ;
435 		if( data ){
436 		    Yrbtree_insert( rule_treeS, data ) ;
437 		}
438 	    } else if( strcmp( tokens[0], "via" ) == STRINGEQ &&
439 		(numtokens == 4 || numtokens == 5) ){
440 		if( ++numviaS >= alloc_viaS ){
441 		    /* need to expand the number of vias allocated */
442 		    alloc_viaS = numviaS + 3 ;
443 		    viaArrayS = YVECTOR_REALLOC( viaArrayS,1,alloc_viaS,char * ) ;
444 		    for( i = numviaS; i <= alloc_viaS; i++ ){
445 			viaArrayS[i] = NIL(char *) ;
446 		    }
447 
448 		}
449 		/* at this point safe to use vianame */
450 		/* we need two mechanisms : viaid to vianame - use array */
451 		/* and vianame to viaid - use balanced tree */
452 		viaArrayS[numviaS] = Ystrclone( tokens[1] ) ;
453 		data = make_data2( tokens[2], tokens[3], tokens[1], VIA_T ) ;
454 		if( data ){
455 		    Yrbtree_insert( rule_treeS, data ) ;
456 		}
457 		if( numtokens == 5 ){
458 		    data = make_data( tokens[1], tokens[4], ASPECTLIM_T ) ;
459 		} else {
460 		    /* set the default to 1.0 for aspect ratio limit */
461 		    data = make_data( tokens[1], "1.0", ASPECTLIM_T ) ;
462 		}
463 		if( data ) Yrbtree_insert( rule_treeS, data ) ;
464 
465 	    } else if( strncmp( tokens[0], "layer",5 ) == STRINGEQ &&
466 		numtokens == 5 ){
467 		if( ++numlayS >= alloc_layS ){
468 		    /* need to expand the number of layers allocated */
469 		    alloc_layS = numlayS + 3 ;
470 		    layerArrayS = YVECTOR_REALLOC(layerArrayS,1,alloc_layS,char*);
471 		    for( i = numlayS; i <= alloc_layS; i++ ){
472 			layerArrayS[i] = NIL(char *) ;
473 		    }
474 
475 		}
476 		/* at this point safe to use layer */
477 		/* we need two mechanisms : layerid to layername - use array */
478 		/* and layername to layerid - use balanced tree */
479 		layerArrayS[numlayS] = Ystrclone( tokens[1] ) ;
480 		data = make_data( tokens[1], (char *) numlayS, LAYER_T ) ;
481 		if( data ) Yrbtree_insert( rule_treeS, data ) ;
482 		/* store the values of res, cap, and routing preference */
483 		data = make_data( tokens[1], tokens[2], RESISTANCE_T ) ;
484 		if( data ) Yrbtree_insert( rule_treeS, data ) ;
485 		data = make_data( tokens[1], tokens[3], CAPACITANCE_T ) ;
486 		if( data ) Yrbtree_insert( rule_treeS, data ) ;
487 		data = make_data( tokens[1], tokens[4], DIRECTION_T ) ;
488 		if( data ) Yrbtree_insert( rule_treeS, data ) ;
489 
490 	    } else if( strncmp( tokens[0], "overhang",8 ) == STRINGEQ &&
491 		numtokens == 4 ){
492 		data = make_data2( tokens[1], tokens[2], tokens[3], OVERHANG_T ) ;
493 		if( data ) Yrbtree_insert( rule_treeS, data ) ;
494 
495 	    } else {
496 		sprintf( YmsgG, "Unknown rule at line:%d in filename:%s\n",
497 		    lineS, filename ) ;
498 		M( ERRMSG, "Yreadpar_init", YmsgG ) ;
499 	    }
500 
501 	}/* end processing of rule section */
502 
503     } /* end while */
504 
505     if(!(rule_section)){
506 	rewind(fpS) ;
507 	lineS = 0 ;
508     }
509 
510 } /* end Yreadpar_init */
511 
Yreadpar_next(lineptr,line,numtokens,onNotOff,wildcard)512 char **Yreadpar_next( lineptr, line, numtokens, onNotOff, wildcard )
513 char **lineptr ;
514 INT *line ;
515 INT  *numtokens ;
516 BOOL *onNotOff ;
517 BOOL *wildcard ;
518 {
519     PARAMPTR data ;
520     char *bufferptr ;
521     char **tokens ;
522     BOOL rule_section ;
523 
524 
525     if( filter_idS == UNKN || !(fpS) ){
526 	/* don't read an unknown format */
527 	return( NIL(char **) ) ;
528     }
529     /* assume that every option is on */
530     *onNotOff = TRUE ;
531     rule_section = FALSE ;
532     while( bufferptr = fgets( bufferS, LRECL, fpS )){
533 	/* parse file */
534 	lineS++ ;
535 	*line = lineS ;
536 	/* remove leading blanks */
537 	bufferptr = Yremove_lblanks( bufferptr ) ;
538 	/* skip comments */
539 	if( *bufferptr == COMMENT ){
540 	    continue ;
541 	}
542 	if( strncmp( bufferptr, "RULES", 5 ) == STRINGEQ ){
543 	    rule_section = TRUE ;
544 	    /* skip over rules section */
545 	    continue ;
546 	} else if( strncmp( bufferptr, "ENDRULES", 8 ) == STRINGEQ ){
547 	    rule_section = FALSE ;
548 	    /* skip over rules section */
549 	    continue ;
550 	} else if( rule_section ){
551 	    continue ;
552 	}
553 	*wildcard = FALSE ;
554 	strcpy( copy_bufferS, bufferptr ) ;
555 	*lineptr = copy_bufferS ;
556 	if( prog_idS == USER ){
557 	    bufferptr = Yremove_lblanks( bufferptr ) ;
558 	    if( *bufferptr != WILDCARD ){
559 		tokens = Ystrparser( bufferptr, "*\n", numtokens ) ;
560 		if( *numtokens == 2 ){
561 		    /* look for match for this program */
562 		    if( strcmp( tokens[0], filterNameS ) != STRINGEQ ){
563 			/* go on to the next line */
564 			if( prog_idS == USER ){
565 			    continue ;
566 			}
567 		    }
568 		    bufferptr = tokens[1] ;
569 		} else if( *numtokens == 0 ){
570 		    continue ;
571 		} else {
572 		    sprintf( YmsgG,
573 			"Trouble parsing line:%d :\n\t%s\n", lineS,
574 			copy_bufferS ) ;
575 		    M( ERRMSG, "Yreadpar_next", YmsgG ) ;
576 		    continue ;
577 		}
578 	    } else {
579 		/* WILDCARD skip over it */
580 		*wildcard = TRUE ;
581 		bufferptr++ ;
582 	    }
583 	}
584 	tokens = Ystrparser( bufferptr, " :\t\n", numtokens ) ;
585 	if( *numtokens > 1 ){
586 	    if( strcmp( tokens[*numtokens-1], "off" ) == STRINGEQ ){
587 		/* we have turned this value off */
588 		*onNotOff = FALSE ;
589 	    }
590 	}
591 	return( tokens ) ;
592     }
593     TWCLOSE( fpS ) ;
594     fpS = NIL( FILE * ) ;
595     return( NIL(char **) ) ;
596 
597 } /* end Yreadpar_next */
598 
compare_parameter(key1,key2)599 static INT compare_parameter( key1, key2 )
600 PARAMPTR key1, key2 ;
601 {
602     return( (INT)strcmp( key1->parameter, key2->parameter ) ) ;
603 } /* end compare */
604 
Yreadpar_file()605 YPARPTR Yreadpar_file()
606 {
607     PARAMPTR data ;
608     YPARPTR  store ;              /* a tree with all the parameters */
609     char *lineptr ;
610     char **tokens ;
611     INT  numtokens ;
612     INT  line ;
613     INT  i ;                     /* counter */
614     BOOL onNotOff ;
615     BOOL wildcard ;
616 
617     store = (YPARPTR) NULL ;
618 
619     if( prog_idS == UNKN || !(fpS) ){
620 	/* don't read an unknown format */
621 	return( store ) ;
622     }
623 
624     /* initialize a tree which store the data found in the *par file*/
625     YRBTREE_INIT( store, compare_parameter );
626 
627     /* assume that every option is on */
628     while( tokens = Yreadpar_next( &lineptr, &line, &numtokens,
629 	&onNotOff, &wildcard )){
630 	if( numtokens == 0 ){
631 	    continue ;
632 	}
633 	if( numtokens >= 2 ){
634 	    /* copy tokens for storing in a tree */
635 	    data = YMALLOC( 1, PARAM ) ;
636 	    data->parameter = Ystrclone( tokens[0] ) ;
637 	    data->program = filter_idS ;
638 	    data->tokens = YMALLOC( numtokens-1, char * ) ;
639 	    for( i = 1; i < numtokens ; i++ ){
640 		data->tokens[i-1] = Ystrclone( tokens[i] ) ;
641 	    }
642 	    data->numtokens = numtokens - 1 ; /* save rest of line */
643 	    /* now write the tokens */
644 	    Yrbtree_insert( store, data ) ;
645 	} else {
646 	    sprintf( YmsgG,
647 		"Trouble parsing line:%d :\n\t%s\n", line,
648 		lineptr ) ;
649 	    M( ERRMSG, "Yreadpar_file", YmsgG ) ;
650 	    continue ;
651 	}
652     } /* end while loop */
653 
654     TWCLOSE( fpS ) ;
655     fpS = NIL( FILE * ) ;
656     return( store ) ;
657 
658 } /* end Yreadpar_file */
659 
Yreadpar_lookup(par_object,param,program,numtokens)660 char **Yreadpar_lookup( par_object, param, program, numtokens )
661 YPARPTR par_object ;          /* parameter tree */
662 char *param ;                 /* parameter */
663 INT program ;                 /* program id */
664 INT *numtokens ;              /* returns the number of tokens for parameter */
665 {
666     PARAMPTR data ;           /* store this in the tree */
667     PARAM key ;
668 
669     *numtokens = 0 ;
670     key.parameter = param ;
671     data = (PARAMPTR) Yrbtree_interval(par_object,&key,&key,TRUE) ;
672     while( data ){
673 	if( data->program == program ){
674 	    *numtokens = data->numtokens ;
675 	    return( data->tokens ) ;
676 	}
677 	data = (PARAMPTR) Yrbtree_interval(par_object,&key,&key,FALSE) ;
678     }
679     /* if we get to this point we didn't find a match */
680     return( NIL(char **) ) ;
681 } /* end Yreadpar_lookup */
682 
Yreadpar_spacing(object1,object2)683 DOUBLE Yreadpar_spacing( object1, object2 )
684 char *object1, *object2 ;
685 {
686     char  key[LRECL] ;
687     RULEPTR data ;
688     RULEBOX data_buffer ;
689 
690     ERROR_CHECK(DOUBLE) ;
691     /* first build the key */
692     sprintf( key, "%s/%s:%c", object1, object2, SPACING_T ) ;
693     data_buffer.rule = key ;
694 
695     if( data = (RULEPTR) Yrbtree_search( rule_treeS, (char *) &(data_buffer) ) ){
696 	return( data->value.fvalue ) ;
697     } else if( verboseS ){
698 	sprintf( YmsgG,
699 	    "Spacing for %s to %s not defined in the given design rules.\n",
700 	    object1, object2 );
701 	M( ERRMSG, "Yreadpar_spacing", YmsgG ) ;
702 	M( ERRMSG, NULL, "\tDefaulting to zero.\n\n" ) ;
703     }
704 	return( 0 ) ;
705 
706 } /* end Yreadpar_spacing */
707 
Yreadpar_width(object)708 DOUBLE Yreadpar_width( object )
709 char *object ;
710 {
711     char  key[LRECL] ;
712     RULEPTR data ;
713     RULEBOX data_buffer ;
714 
715     ERROR_CHECK(DOUBLE) ;
716     /* first build the key */
717     sprintf( key, "%s:%c", object, WIDTH_T ) ;
718     data_buffer.rule = key ;
719     if( data = (RULEPTR) Yrbtree_search( rule_treeS, (char *) &(data_buffer) ) ){
720 	return( data->value.fvalue ) ;
721     } else {
722 	sprintf( YmsgG,
723 	    "Width for %s not defined in the given design rules.\n",
724 	    object );
725 	M( ERRMSG, "Yreadpar_width", YmsgG ) ;
726 	M( ERRMSG, NULL, "\tDefaulting to zero.\n\n" ) ;
727 	return( 0 ) ;
728     }
729 
730 } /* end Yreadpar_spacing */
731 
Yreadpar_pitch(object)732 DOUBLE Yreadpar_pitch( object )
733 char *object ;
734 {
735     DOUBLE spacing ;
736     DOUBLE width ;
737 
738     /* pitch for a given layer is spacing plus width */
739 
740     ERROR_CHECK(DOUBLE) ;
741     spacing = Yreadpar_spacing( object, object ) ;
742     width = Yreadpar_width( object ) ;
743     return( spacing + width ) ;
744 } /* end Yreadpar_pitch */
745 
Yreadpar_layer_res(object)746 DOUBLE Yreadpar_layer_res( object )
747 char *object ;
748 {
749     char  key[LRECL] ;
750     RULEPTR data ;
751     RULEBOX data_buffer ;
752 
753     ERROR_CHECK(DOUBLE) ;
754     /* first build the key */
755     sprintf( key, "%s:%c", object, RESISTANCE_T ) ;
756     data_buffer.rule = key ;
757     if( data = (RULEPTR) Yrbtree_search( rule_treeS, (char *) &(data_buffer) ) ){
758 	return( data->value.fvalue ) ;
759     } else if( verboseS ){
760 	sprintf( YmsgG,
761 	    "Resistance for layer %s not defined in the given design rules.\n",
762 	    object );
763 	M( ERRMSG, "Yreadpar_layer_res", YmsgG ) ;
764 	M( ERRMSG, NULL, "\tDefaulting to zero.\n\n" ) ;
765     }
766 	return( 0 ) ;
767 
768 } /* end Yreadpar_layer_res */
769 
Yreadpar_layer_cap(object)770 DOUBLE Yreadpar_layer_cap( object )
771 char *object ;
772 {
773     char  key[LRECL] ;
774     RULEPTR data ;
775     RULEBOX data_buffer ;
776 
777     ERROR_CHECK(DOUBLE) ;
778     /* first build the key */
779     sprintf( key, "%s:%c", object, CAPACITANCE_T ) ;
780     data_buffer.rule = key ;
781     if( data = (RULEPTR) Yrbtree_search( rule_treeS, (char *) &(data_buffer) ) ){
782 	return( data->value.fvalue ) ;
783     } else if( verboseS ){
784 	sprintf( YmsgG,
785 	    "Capacitance for layer %s defined in the given design rules.\n",
786 	    object );
787 	M( ERRMSG, "Yreadpar_layer_cap", YmsgG ) ;
788 	M( ERRMSG, NULL, "\tDefaulting to zero.\n\n" ) ;
789     }
790 	return( (DOUBLE) 0.0 ) ;
791 
792 } /* end Yreadpar_layer_cap */
793 
Yreadpar_layer_HnotV(object)794 BOOL Yreadpar_layer_HnotV( object )
795 char *object ;
796 {
797     char  key[LRECL] ;
798     char  *keyptr ;
799     RULEPTR data ;
800     RULEBOX data_buffer ;
801 
802     ERROR_CHECK(BOOL) ;
803     /* first build the key */
804     sprintf( key, "%s:%c", object, DIRECTION_T ) ;
805     data_buffer.rule = key ;
806     if( data = (RULEPTR) Yrbtree_search( rule_treeS, (char *) &(data_buffer) ) ){
807 	return( data->value.bvalue ) ;
808     } else if( verboseS ){
809 	sprintf( YmsgG,
810 	    "Routing direction for layer %s defined in the given design rules.\n",
811 	    object );
812 	M( ERRMSG, "Yreadpar_layer_HnotV", YmsgG ) ;
813 	M( ERRMSG, NULL, "\tDefaulting to horizontal.\n\n" ) ;
814     }
815 	return( TRUE ) ;
816 
817 } /* end Yreadpar_layer_HnotV */
818 
Yreadpar_layer2id(object)819 INT Yreadpar_layer2id( object )
820 char *object ;
821 {
822     char  key[LRECL] ;
823     RULEPTR data ;
824     RULEBOX data_buffer ;
825 
826     ERROR_CHECK(INT) ;
827     /* first build the key */
828     sprintf( key, "%s:%c", object, LAYER_T ) ;
829     data_buffer.rule = key ;
830     if( data = (RULEPTR) Yrbtree_search( rule_treeS, (char *) &(data_buffer) ) ){
831 	return( data->value.ivalue ) ;
832     } else if( verboseS ){
833 	sprintf( YmsgG,
834 	    "Routing layer %s not defined in the given design rules.\n",
835 	    object );
836 	M( ERRMSG, "Yreadpar_layer2id", YmsgG ) ;
837 	M( ERRMSG, NULL, "\tDefaulting to horizontal.\n\n" ) ;
838     }
839 	return( TRUE ) ;
840 
841 } /* end Yreadpar_layer2id */
842 
Yreadpar_id2layer(layerid)843 char *Yreadpar_id2layer( layerid )
844 INT layerid ;
845 {
846     ERROR_CHECK(char*) ;
847     if( layerid > 0 && layerid <= numlayS ){
848 	return( layerArrayS[layerid] ) ;
849     } else {
850 	sprintf( YmsgG,
851 	    "Layer id:%d is out of bounds. Numlayers = %d\n",
852 	    layerid, numlayS ) ;
853 	M( ERRMSG, "Yreadpar_id2layer", YmsgG ) ;
854 	M( ERRMSG, NULL, "\tDefaulting to layer 1.\n\n" ) ;
855 	return( layerArrayS[1] ) ;
856     }
857 
858 } /* end Yreadpar_id2layer */
859 
Yreadpar_numlayers()860 INT Yreadpar_numlayers()
861 {
862     return( numlayS ) ;
863 } /* end Yreadpar_numlayers */
864 
Yreadpar_vianame(object1,object2)865 char *Yreadpar_vianame( object1, object2 )
866 char *object1, *object2 ;
867 {
868     char  key[LRECL] ;
869     RULEPTR data ;
870     RULEBOX data_buffer ;
871 
872     ERROR_CHECK(char*) ;
873     /* first build the key */
874     data_buffer.rule = key ;
875     /* make the key order the key alphabetically */
876     if( strcmp( object1, object2 ) <= STRINGEQ ){
877 	sprintf( key, "%s/%s:%c", object1, object2, VIA_T ) ;
878     } else {
879 	sprintf( key, "%s/%s:%c", object2, object1, VIA_T ) ;
880     }
881     if( data = (RULEPTR) Yrbtree_search( rule_treeS, (char *) &(data_buffer) ) ){
882 	return( data->value.svalue ) ;
883     } else if( verboseS ){
884 	sprintf( YmsgG,
885 	    "Could not find a via between layers %s and %s.\n",
886 	    object1, object2 );
887 	M( ERRMSG, "Yreadpar_vianame", YmsgG ) ;
888     }
889 	return( NIL(char *) ) ;
890 
891 } /* end Yreadpar_vianame */
892 
Yreadpar_viaId2name(viaid)893 char *Yreadpar_viaId2name( viaid )
894 INT viaid ;
895 {
896     ERROR_CHECK(char*) ;
897     if( viaid > 0 && viaid <= numviaS ){
898 	return( viaArrayS[viaid] ) ;
899     } else {
900 	sprintf( YmsgG,
901 	    "Via id:%d is out of bounds. Numvias = %d\n",
902 	    viaid, numviaS ) ;
903 	M( ERRMSG, "Yreadpar_viaId2name", YmsgG ) ;
904 	M( ERRMSG, NULL, "\tDefaulting to via id 1.\n\n" ) ;
905 	return( viaArrayS[1] ) ;
906     }
907 
908 } /* end Yreadpar_viaId2name */
909