1 /*
2  *   Copyright (C) 1989-1992 Yale University
3  *   Copyright (C) 2013 Tim Edwards <tim@opencircuitdesign.com>
4  *   Copyright (C) 2014 Ruben Undheim <ruben.undheim@gmail.com>
5  *
6  *   This work is distributed in the hope that it will be useful; you can
7  *   redistribute it and/or modify it under the terms of the
8  *   GNU General Public License as published by the Free Software Foundation;
9  *   either version 2 of the License,
10  *   or any later version, on the following conditions:
11  *
12  *   (a) YALE MAKES NO, AND EXPRESSLY DISCLAIMS
13  *   ALL, REPRESENTATIONS OR WARRANTIES THAT THE MANUFACTURE, USE, PRACTICE,
14  *   SALE OR
15  *   OTHER DISPOSAL OF THE SOFTWARE DOES NOT OR WILL NOT INFRINGE UPON ANY
16  *   PATENT OR
17  *   OTHER RIGHTS NOT VESTED IN YALE.
18  *
19  *   (b) YALE MAKES NO, AND EXPRESSLY DISCLAIMS ALL, REPRESENTATIONS AND
20  *   WARRANTIES
21  *   WHATSOEVER WITH RESPECT TO THE SOFTWARE, EITHER EXPRESS OR IMPLIED,
22  *   INCLUDING,
23  *   BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
24  *   PARTICULAR
25  *   PURPOSE.
26  *
27  *   (c) LICENSEE SHALL MAKE NO STATEMENTS, REPRESENTATION OR WARRANTIES
28  *   WHATSOEVER TO
29  *   ANY THIRD PARTIES THAT ARE INCONSISTENT WITH THE DISCLAIMERS BY YALE IN
30  *   ARTICLE
31  *   (a) AND (b) above.
32  *
33  *   (d) IN NO EVENT SHALL YALE, OR ITS TRUSTEES, DIRECTORS, OFFICERS,
34  *   EMPLOYEES AND
35  *   AFFILIATES BE LIABLE FOR DAMAGES OF ANY KIND, INCLUDING ECONOMIC DAMAGE OR
36  *   INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER YALE SHALL BE
37  *   ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE
38  *   POSSIBILITY OF THE FOREGOING.
39  *
40  */
41 
42 /* -----------------------------------------------------------------
43 FILE:	    partition.c
44 DESCRIPTION:code to support standard cell partitioner.
45 CONTENTS:
46 DATE:	    Apr  9, 1989
47 REVISIONS:  May 24, 1989 - added stdcell configuration code.
48 	    Jun 21, 1989 - modified final_conf and output partition
49 		to handle equiv pins correctly.
50 	    Jun 23, 1989 - added reset cell function and added
51 		reconfig capability.
52 	    Aug 20, 1989 - moved standard cell calculation to
53 		child program genrows.
54 	    Sep 16, 1989 - fixed problem with unbust.  Multiple tile
55 		cells should use tile count as argument since tiles
56 		need to be seamed together.
57 	    Nov  4, 1989 - now read block file created by genrows in
58 		order to update the size of the core.
59 	    Apr 23, 1990 - modified instance record.
60 	    May 15, 1990 - changed .mstat parser.
61 	    Sun Dec 16 00:32:16 EST 1990 - use the library version
62 		of buster.
63 	    Fri Jan 18 18:29:54 PST 1991 - now use conservative
64 		approach to building .scel.
65 	    Wed Jan 30 14:13:36 EST 1991 - now left justify orientation
66 		rotations.
67 	    Sat Feb 23 00:28:28 EST 1991 - now handle wildcarding for
68 		reading and updated for TOMUS.
69 	    Thu Apr 18 01:39:27 EDT 1991 - now allow genrows to
70 		orient macros.
71 	    Wed May  1 19:22:03 EDT 1991 - MC now always call genrows
72 		during partitioning.
73 	    Wed Jun  5 16:30:30 CDT 1991 - eliminated unbust.
74 	    Mon Aug  5 18:06:17 CDT 1991 - eliminated special
75 		partitioning case.
76 	    Fri Oct 18 00:09:45 EDT 1991 - eliminated read_blk_file.
77 		Instead, to find core we read it using read_gen_file.
78 ----------------------------------------------------------------- */
79 
80 #include <custom.h>
81 #include <partition.h>
82 #include <pads.h>
83 #include <yalecad/buster.h>
84 #include <yalecad/file.h>
85 #include <yalecad/relpos.h>
86 #include <yalecad/string.h>
87 #include <yalecad/debug.h>
88 #include <yalecad/yreadpar.h>
89 
90 #include "config-build.h"
91 
92 #define ROWSEP    "rowSep"
93 #define GENROWPROG      "genrows"
94 #define GENROWPATH      "../genrows"
95 #define  NUMROWKEYWORD  "rows"
96 #define  ROWKEYWORD     "row"
97 
98 static INT tlengthS ;                 /* total length of stdcells */
99 static INT cheightS ;                 /* height of stdcell */
100 static INT num_classeS ;	      /* number of cell classes */
101 static INT *classS ;	      	      /* cell class name */
102 static INT *lbS ;	              /* lower bound of cell class length */
103 static INT *ubS ;	              /* upper bound of cell class length */
104 
105 static DOUBLE rowSepS ;               /* row separation, relative */
106 static DOUBLE rowSepAbsS ;            /* row separation, absolute */
107 
108 static BOOL dataValidS = FALSE ;      /* used to avoid invalid request */
109 
110 static INT num_macroS ;               /* number of macros output */
111 
112 /* Forward declaration */
113 
114 extern INT closegraphics();
115 void read_stat_file();
116 void build_mver_file(INT left, INT right, INT bottom, INT top );
117 void read_gen_file();
118 
config_rows()119 void config_rows()
120 {
121   DOUBLE read_par_file() ;     /* get default from user */
122   INT left, right, bottom, top;/* core area */
123   char *Yrelpath() ;
124   char *pathname ;
125   char *twdir ;       /* path of TimberWolf directory */
126   char *getenv() ;    /* used to get TWDIR environment variable */
127   char filename[LRECL] ;
128   BOOL stateSaved = FALSE ; /* whether need to restore state */
129   BOOL get_batch_mode() ;   /* find out whether we are in batch mode */
130 
131   read_stat_file() ;
132   (void) read_par_file() ;
133   grid_cells() ;
134 
135   /* place the pads to get standard cell core area */
136   find_core_boundary( &left, &right, &bottom, &top ) ;
137 
138   build_mver_file( left, right, bottom, top ) ;
139 
140   /* now call genrows program */
141   /* find the path of genrows relative to main program */
142   pathname = Yrelpath( argv0G, GENROWPATH ) ;
143   if( !(YfileExists(pathname))){
144     /* Check if TWDIR overridden */
145     if((twdir = getenv("TWDIR"))) {
146       M(MSG,NULL, "Directory overridden with 'TWDIR' environment variable\n" ) ;
147     }
148     else {
149       twdir = TWFLOWDIR;
150     }
151     sprintf( filename, "%s/bin/%s", twdir, GENROWPROG ) ;
152     pathname = Ystrclone( filename ) ;
153   }
154   if( doGraphicsG ){
155     G( sprintf( YmsgG, "%s -w %s %lu",
156           pathname, cktNameG, (unsigned long)TWsaveState() ) ) ;
157     stateSaved = TRUE ;
158   } else if( get_batch_mode() ){
159     sprintf( YmsgG, "%s %s", pathname, cktNameG ) ;
160   } else {  /* no graphics case */
161     sprintf( YmsgG, "%s -n %s", pathname, cktNameG ) ;
162   }
163   M( MSG, NULL, YmsgG ) ;
164   M( MSG, NULL, "\n" ) ;
165   /* Ysystem will kill program if catastrophe occurred */
166   Ysystem( GENROWPROG, ABORT, YmsgG, closegraphics ) ;
167   Ysafe_free( pathname ) ; /* free name created in Yrelpath */
168   /* ############# end of genrows execution ############# */
169 
170   if( stateSaved ){
171     /* if we save the graphics state we need to restore it */
172     G( TWrestoreState() ) ;
173   }
174 
175   /* read result to update new core */
176   read_gen_file() ;
177 
178   /* add spacing between pads and core area. */
179 #ifdef LATER
180   cellarrayG[endpadgrpsG+L]->tiles->rborder = numpadsG*track_spacingXG ;
181   cellarrayG[endpadgrpsG+R]->tiles->lborder = numpadsG*track_spacingXG ;
182   cellarrayG[endpadgrpsG+B]->tiles->tborder = numpadsG*track_spacingYG ;
183   cellarrayG[endpadgrpsG+T]->tiles->bborder = numpadsG*track_spacingYG ;
184 #endif
185 
186   /* read back result */
187   setVirtualCore( TRUE ) ;
188   placepads() ;
189 } /* end config_rows */
190 
read_stat_file()191 void read_stat_file()
192 {
193 
194   char filename[LRECL] ;
195   char input[LRECL] ;
196   char *bufferptr ;
197   char **tokens ;
198   INT  class ;
199   INT  numtokens ;
200   INT  class_count ;
201   FILE *fin ;
202 
203   /***********************************************************
204    * Read from circuitName.stat file.
205    ***********************************************************/
206   sprintf( filename, "%s.stat", cktNameG ) ;
207   fin = TWOPEN(filename,"r", ABORT ) ;
208 
209   class_count = 0 ;
210   num_classeS = 0 ;
211   while( bufferptr = fgets( input, LRECL, fin ) ){
212     tokens = Ystrparser( bufferptr, " :\t\n", &numtokens ) ;
213     if( strcmp( tokens[0], "tot_length" ) == STRINGEQ ){
214       tlengthS = atoi( tokens[1] ) ;
215     } else if( strcmp( tokens[0], "cell_height" ) == STRINGEQ ){
216       cheightS = atoi( tokens[1] ) ;
217     } else if( strcmp( tokens[0], "num_classes" ) == STRINGEQ ){
218       num_classeS = atoi( tokens[1] ) ;
219       classS = YVECTOR_MALLOC( 1, num_classeS, INT ) ;
220       lbS = YVECTOR_MALLOC( 1, num_classeS, INT ) ;
221       ubS = YVECTOR_MALLOC( 1, num_classeS, INT ) ;
222     } else if( strcmp( tokens[0], "class" ) == STRINGEQ ){
223       class = atoi( tokens[1] ) ;
224       classS[++class_count] = class ;
225       lbS[class_count] = atoi( tokens[3] ) ;
226       ubS[class_count] = atoi( tokens[5] ) ;
227     }
228   }
229 
230   TWCLOSE( fin ) ;
231 } /* end read_stat_file */
232 
read_par_file()233 DOUBLE read_par_file()
234 {
235   char *bufferptr ;
236   char **tokens ;      /* for parsing menu file */
237   INT  numtokens ;
238   INT  line ; /* line number of TWmenu file */
239   BOOL onNotOff ;
240   BOOL wildcard ;
241 
242   Yreadpar_init( cktNameG, USER, TWSC, TRUE ) ;
243   while( tokens = Yreadpar_next( &bufferptr, &line, &numtokens,
244         &onNotOff, &wildcard )){
245     if( numtokens == 0 ){
246       /* skip over empty lines */
247       continue ;
248     }
249     if( numtokens != 2 && numtokens != 3 ){
250       continue ;
251     }
252     if( strcmp( tokens[0], ROWSEP ) == STRINGEQ){
253 
254       /* there better be only two or three tokens on this line */
255       /* 3rd token for absolute row spacing is not handled */
256       if( numtokens == 2 ){
257         rowSepS = atof( tokens[1] ) ;
258       } else if (numtokens == 3 ){
259         rowSepS = atof( tokens[1] ) ;
260         rowSepAbsS = atof( tokens[2] ) ;
261       } else {
262         sprintf( YmsgG, "Syntax error on line:%d\n", line ) ;
263         M(ERRMSG, "read_par_file", YmsgG ) ;
264       }
265     }
266   }
267   if( rowSepS < 0.0 ) {
268     M(ERRMSG,"read_par_file","Improper row separation.\n" ) ;
269     M(MSG,NULL,"Row separaion should be specified in .par file\n" ) ;
270     M(MSG,NULL,"Defaulting to 1.0\n" ) ;
271     rowSepS = 1.0 ;
272     rowSepAbsS = 0.0 ;
273   }
274   return( rowSepS ) ;
275 } /* end read_par_file */
276 
277 
output_partition()278 void output_partition()
279 {
280 
281 #define  RELATIVE_TO_CURPOS  1
282 
283   INT i ;
284   long delta ;             /* how far to jump backwards */
285   INT error ;              /* error code returned from fseek */
286   INT x, y ;               /* pin positions */
287   INT xc, yc ;             /* cell center */
288   INT instance ;           /* current cell instance */
289   INT line ;               /* current line number */
290   BOOL found ;             /* find mc keywords */
291   FILE *fp ;
292   char filename[LRECL] ;
293   char buffer[LRECL] ;
294   char *bufferptr ;
295   char *matchptr ;
296   PINBOXPTR pin ;
297   CELLBOXPTR cptr ;
298 
299   /* ****************************************************************
300      Output the ports into sc cell file.
301    ***************************************************************** */
302 
303   /* other definitions for the apollo version */
304   char filename_out[LRECL] ;
305   FILE *fout ;
306 
307   sprintf( filename, "%s.scel", cktNameG ) ;
308   fp = TWOPEN( filename, "r", ABORT ) ;
309   sprintf( filename_out, "%s.temp", cktNameG ) ;
310   fout = TWOPEN( filename_out, "w", ABORT ) ;
311 
312   /* start at beginning of file and read till read mc entity or pad */
313   line = 0 ;
314   while( bufferptr = fgets( buffer, LRECL, fp )){
315     /* remove leading blanks or tabs */
316     matchptr = Yremove_lblanks( bufferptr ) ;
317     if( strncmp( matchptr, "hardcell", 8 ) == STRINGEQ ){
318       break ;
319     } else if( strncmp( matchptr, "softcell", 8 ) == STRINGEQ ){
320       break ;
321     } else if( strncmp( matchptr, "pad", 3 ) == STRINGEQ ){
322       break ;
323     } else {
324       /* do an echo */
325       line++ ;
326       fprintf( fout, "%s", bufferptr ) ;
327     }
328   }
329   D( "output_partition",
330       fprintf( stderr, "broke on line:%d\n", line ) ;
331    ) ;
332   /* send the rest of the macro output of .mdat to fout */
333   output( fout ) ;
334   TWCLOSE( fp ) ;
335   Yrm_files( filename ) ;
336   /* move the new file to .scel due to a bug in fseek on the apollo */
337   YmoveFile( filename_out, filename ) ;
338 
339 } /* end of prnt_data */
340 
341 
build_mver_file(INT left,INT right,INT bottom,INT top)342 void build_mver_file(INT left, INT right, INT bottom, INT top )
343 {
344   CELLBOXPTR cellptr ;
345   FILE *fp ;
346   char filename[LRECL] ;
347   INT type ;
348   INT i, k, cell ;
349   INT xc, yc ;
350   INT x, y ;
351   INT separation ;
352   BOUNBOXPTR bounptr ;         /* bounding box pointer */
353 
354   /* ######### Create genrows file and exec genrows ######### */
355   /* open vertex file for writing */
356   sprintf(filename, "%s.mver" , cktNameG ) ;
357   fp = TWOPEN( filename , "w", ABORT ) ;
358 
359   fprintf( fp, "total_row_length %d\n", tlengthS ) ;
360   if( num_classeS ){
361     fprintf( fp, "num_classes %d\n", num_classeS ) ;
362   }
363   for( i = 1 ; i <= num_classeS ; i++ ){
364     fprintf( fp, "class %d lb %d ub %d\n", classS[i], lbS[i], ubS[i] ) ;
365   }
366   fprintf( fp, "actual_row_height %d\n", cheightS ) ;
367   separation = (INT) ( (DOUBLE) cheightS * rowSepS + rowSepAbsS) ;
368   fprintf( fp, "channel_separation %d\n", separation ) ;
369   fprintf( fp, "min_length %d\n", (right-left) / 5 ) ;
370   fprintf( fp, "core %d %d %d %d\n", left, bottom, right, top ) ;
371   fprintf( fp, "grid %d %d\n", track_spacingXG, track_spacingYG ) ;
372   num_macroS = 0 ;
373   for( cell = 1 ; cell <= numcellsG ; cell++ ) {
374 
375     cellptr = cellarrayG[cell] ;
376     type = cellptr->celltype ;
377     if( type != CUSTOMCELLTYPE && type != SOFTCELLTYPE ){
378       continue ;
379     }
380     num_macroS++ ;
381   }
382   fprintf( fp, "num_macro %d\n", num_macroS ) ;
383 
384 
385   for( cell = 1 ; cell <= numcellsG ; cell++ ) {
386 
387     cellptr = cellarrayG[cell] ;
388     type = cellptr->celltype ;
389     if( type != CUSTOMCELLTYPE && type != SOFTCELLTYPE ){
390       continue ;
391     }
392     fprintf(fp,"macro orient %d %d vertices ", cellptr->orient,
393         cellptr->numsides ) ;
394     output_vertices( fp, cellptr ) ;
395   }
396 
397   TWCLOSE( fp ) ;
398 } /* end build_mver_file */
399 
400 
401 
402 
read_gen_file()403 void read_gen_file()
404 {
405   char filename[LRECL] ;
406   char buffer[LRECL], *bufferptr ;
407   char **tokens ;     /* for parsing file */
408   INT  numtokens, line ;
409   INT  cell ;          /* current cell number */
410   INT  type ;          /* current cell type */
411   CELLBOXPTR cellptr ; /* current cell */
412   BOOL abort ; /* whether to abort program */
413   FILE *fp ;
414 
415   if( num_macroS == 0 ){
416     return ;
417   }
418   /* **************** READ RESULTS of genrows ************/
419   sprintf(filename, "%s.gen" , cktNameG ) ;
420   fp = TWOPEN( filename , "r", ABORT ) ;
421 
422   /* parse file */
423   line = 0 ;
424   abort = FALSE ;
425   for( cell = 1 ; cell <= numcellsG ; cell++ ) {
426 
427     cellptr = cellarrayG[cell] ;
428     type = cellptr->celltype ;
429     if( type != CUSTOMCELLTYPE && type != SOFTCELLTYPE ){
430       continue ;
431     }
432     while( bufferptr=fgets(buffer,LRECL,fp )){
433       /* parse file */
434       line++ ; /* increment line number */
435       tokens = Ystrparser( bufferptr, " \t\n", &numtokens );
436       if( numtokens == 0 ){
437         /* skip over empty lines */
438         continue ;
439       } else if( numtokens == 3 ){
440         cellptr->xcenter = atoi( tokens[0] ) ;
441         cellptr->ycenter = atoi( tokens[1] ) ;
442         cellptr->orient = atoi( tokens[2] ) ;
443         break ; /* go on to the next cell */
444       } else if( strcmp(tokens[0], "core" ) == STRINGEQ &&
445           numtokens == 5 ){
446         blocklG = MIN( blocklG, atoi( tokens[1] ) ) ;
447         blockbG = MIN( blockbG, atoi( tokens[2] ) ) ;
448         blockrG = MAX( blockrG, atoi( tokens[3] ) ) ;
449         blocktG = MAX( blocktG, atoi( tokens[4] ) ) ;
450       } else {
451         sprintf( YmsgG, "Problem reading .gen file on line:%d\n",line ) ;
452         M( ERRMSG, "read_gen_file", YmsgG ) ;
453         abort = TRUE ;
454       }
455     }
456   }
457 
458   TWCLOSE( fp ) ;
459 
460   if( abort ){
461     M(ERRMSG, "read_gen_file", "Problem with genrows. Must abort\n" ) ;
462     closegraphics() ;
463     YexitPgm( PGMFAIL ) ;
464   }
465   /* ************ END READ RESULTS of genrows ************/
466 
467 } /* end read_gen_file() */
468