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