1 /*
2  * CalmaRead.c --
3  *
4  * Input of Calma GDS-II stream format.
5  *
6  *     *********************************************************************
7  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
8  *     * Permission to use, copy, modify, and distribute this              *
9  *     * software and its documentation for any purpose and without        *
10  *     * fee is hereby granted, provided that the above copyright          *
11  *     * notice appear in all copies.  The University of California        *
12  *     * makes no representations about the suitability of this            *
13  *     * software for any purpose.  It is provided "as is" without         *
14  *     * express or implied warranty.  Export of this software outside     *
15  *     * of the United States of America may require an export license.    *
16  *     *********************************************************************
17  */
18 
19 #ifndef lint
20 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/calma/CalmaRead.c,v 1.3 2010/06/24 12:37:15 tim Exp $";
21 #endif  /* not lint */
22 
23 #include <stdio.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 
28 #include <netinet/in.h>
29 
30 #include "utils/magic.h"
31 #include "utils/geometry.h"
32 #include "tiles/tile.h"
33 #include "utils/utils.h"
34 #include "utils/hash.h"
35 #include "database/database.h"
36 #include "database/databaseInt.h"
37 #include "utils/malloc.h"
38 #include "utils/tech.h"
39 #include "cif/cif.h"
40 #include "cif/CIFint.h"
41 #include "cif/CIFread.h"
42 #include "utils/signals.h"
43 #include "windows/windows.h"
44 #include "dbwind/dbwind.h"
45 #include "utils/styles.h"
46 #include "textio/textio.h"
47 #include "calma/calmaInt.h"
48 #include "commands/commands.h"		/* for CmdGetRootPoint */
49 #include "utils/main.h"			/* for EditCellUse */
50 #include "utils/undo.h"
51 
52 /* Globals for Calma reading */
53 FILE *calmaInputFile = NULL;		/* Read from this stream */
54 FILE *calmaErrorFile = NULL;		/* Write error output here */
55 bool CalmaSubcellPolygons = FALSE;	/* Put non-Manhattan polygons
56 					 * in their own subcells.
57 					 */
58 int CalmaPolygonCount;
59 bool CalmaSubcellPaths = FALSE;		/* Put paths in their own subcells. */
60 int CalmaPathCount;
61 bool CalmaFlattenUses = FALSE;		/* If TRUE, small cells in the input
62 					 * stream are flattened when encountered
63 					 * as uses.  This improves magic's
64 					 * performance when handling contacts
65 					 * saved as subcell arrays.
66 					 */
67 char **CalmaFlattenUsesByName = NULL;	/* NULL-terminated list of strings
68 					 * to do glob-style pattern matching
69 					 * to determine what cells to flatten
70 					 * by cellname.
71 					 */
72 bool CalmaReadOnly = FALSE;		/* Set files to read-only and
73 					 * retain file position information
74 					 * so cells can be written verbatim.
75 					 */
76 bool CalmaNoDRCCheck = FALSE;		/* If TRUE, don't mark cells as needing
77 					 * a DRC check;  they will be assumed
78 					 * DRC clean.
79 					 */
80 bool CalmaPostOrder = FALSE;		/* If TRUE, forces the GDS parser to
81 					 * read cells in post-order.  It is
82 					 * necessary, e.g., when we need to
83 					 * flatten cells that are contact cuts.
84 					 * Added by Nishit 8/16/2004
85 					 */
86 bool CalmaNoDuplicates = FALSE;		/* If TRUE, then if a cell exists in
87 					 * memory with the same name as a cell
88 					 * in the GDS file, then the cell in
89 					 * the GDS file is skipped.
90 					 */
91 bool CalmaUnique = FALSE;		/* If TRUE, then if a cell exists in
92 					 * memory with the same name as a cell
93 					 * in the GDS file, then the cell in
94 					 * memory is renamed to a unique
95 					 * identifier with a _N suffix.
96 					 */
97 extern void calmaUnexpected();
98 extern int calmaWriteInitFunc();
99 
100 bool calmaParseUnits();
101 
102 /*
103  * Scaling.
104  * Multiply all coordinates by calmaReadScale1, then divide them
105  * by calmaReadScale2 in order to get coordinates in centimicrons.
106  */
107 int calmaReadScale1;
108 int calmaReadScale2;
109 
110 int calmaTotalErrors;
111 
112 /*
113  * Lookahead: calmaLApresent is TRUE when calmaLAnbytes and calmaLArtype
114  * are set to the record header of a record we just ungot.
115  */
116 bool calmaLApresent;	/* TRUE if lookahead input waiting */
117 int calmaLAnbytes;	/* # bytes in record (from header)  */
118 int calmaLArtype;	/* Record type */
119 
120 /*
121  * Hash table for errors, indexed by (layer, datatype).
122  * The corresponding entry in this table is created whenever
123  * a (layer, datatype) is seen that we don't recognize, so
124  * we don't output an error message more than once.
125  */
126 HashTable calmaLayerHash;
127 
128 /*
129  * Hash table to keep track of all defs that have appeared
130  * in this file.  Indexed by cell def name.
131  */
132 HashTable calmaDefInitHash;
133 
134 /* Common stuff to ignore */
135 int calmaElementIgnore[] = { CALMA_ELFLAGS, CALMA_PLEX, -1 };
136 
137 /*
138  * ----------------------------------------------------------------------------
139  *
140  * CalmaReadFile --
141  *
142  * Read an entire GDS-II stream format library from the open FILE 'file'.
143  *
144  * Results:
145  *	None.
146  *
147  * Side effects:
148  *	May modify the contents of cifReadCellDef by painting or adding
149  *	new uses or labels.  May also create new CellDefs.
150  *
151  * ----------------------------------------------------------------------------
152  */
153 
154 void
CalmaReadFile(file,filename)155 CalmaReadFile(file, filename)
156     FILE *file;			/* File from which to read Calma */
157     char *filename;		/* The real name of the file read */
158 {
159     int k, version;
160     char *libname = NULL;
161     MagWindow *mw;
162     static int hdrSkip[] = { CALMA_FORMAT, CALMA_MASK, CALMA_ENDMASKS,
163 			     CALMA_REFLIBS, CALMA_FONTS, CALMA_ATTRTABLE,
164 			     CALMA_STYPTABLE, CALMA_GENERATIONS, -1 };
165     static int skipBeforeLib[] = { CALMA_LIBDIRSIZE, CALMA_SRFNAME,
166 				   CALMA_LIBSECUR, -1 };
167 
168     if (EditCellUse == (CellUse *)NULL)
169     {
170 	TxError("Cannot read GDS:  There is no edit cell.\n");
171 	return;
172     }
173 
174     /* We will use full cell names as keys in this hash table */
175     CIFReadCellInit(0);
176 
177     if (CIFWarningLevel == CIF_WARN_REDIRECT)
178     {
179 	if (CIFErrorFilename == NULL)
180 	    calmaErrorFile = NULL;
181 	else
182 	    calmaErrorFile = PaOpen(CIFErrorFilename, "w", (char *)NULL, ".",
183 			(char *)NULL, (char **)NULL);
184     }
185 
186     if (cifCurReadStyle == NULL)
187     {
188 	TxError("Don't know how to read GDS-II:\n");
189 	TxError("Nothing in \"cifinput\" section of tech file.\n");
190 	return;
191     }
192     TxPrintf("Warning: Calma reading is not undoable!  I hope that's OK.\n");
193     UndoDisable();
194 
195     calmaTotalErrors = 0;
196     CalmaPolygonCount = 0;
197     CalmaPathCount = 0;
198 
199     /* Reset cd_client pointers (using init function from CalmaWrite.c) */
200     /* This is in case a cell already in memory is being referenced;	*/
201     /* it is probably better to avoid those kinds of naming collisions	*/
202     /* though. . . 							*/
203     (void) DBCellSrDefs(0, calmaWriteInitFunc, (ClientData) NULL);
204 
205     HashInit(&calmaDefInitHash, 32, 0);
206     calmaLApresent = FALSE;
207     calmaInputFile = file;
208 
209     /* Read the GDS-II header */
210     if (!calmaReadI2Record(CALMA_HEADER, &version)) goto done;
211     if (version < 600)
212 	TxPrintf("Library written using GDS-II Release %d.0\n", version);
213     else
214 	TxPrintf("Library written using GDS-II Release %d.%d\n",
215 	    version / 100, version % 100);
216     if (!calmaSkipExact(CALMA_BGNLIB)) goto done;
217     calmaSkipSet(skipBeforeLib);
218     if (!calmaReadStringRecord(CALMA_LIBNAME, &libname)) goto done;
219     if ((libname != NULL) && (libname[0] != '\0'))
220     {
221 	/* Avoid generating a magic name with spaces in it. . .	*/
222 	/* (added by Mike Godfrey, 7/17/05)			*/
223 
224 	for (k = 0; k < strlen(libname); k++)
225 	    if (libname[k] == ' ')
226 		libname[k] = '_';
227 	TxPrintf("Library name: %s\n", libname);
228     }
229 
230     /* Skip the reflibs, fonts, etc. cruft */
231     calmaSkipSet(hdrSkip);
232 
233     /* Set the scale factors */
234     if (!calmaParseUnits()) goto done;
235 
236     /* Main body of GDS-II input */
237     while (calmaParseStructure(filename))
238 	if (SigInterruptPending)
239 	    goto done;
240     (void) calmaSkipExact(CALMA_ENDLIB);
241 
242 done:
243 
244     /* Added by Nishit, Sept. 2004---Load cell read from GDS    */
245     /* stream file to the magic layout window.  If this fails   */
246     /* then we do the original action and don't do a load into  */
247     /* the window.  Note that this follows the Magic GDS output	*/
248     /* convention of giving the library the name of the		*/
249     /* top-level cell, so magic-produced GDS can be read back	*/
250     /* with the expected cell appearing in the layout window.	*/
251 
252     if (libname != NULL)
253     {
254 	mw = CmdGetRootPoint((Point *)NULL, (Rect *)NULL);
255 	if (mw == NULL)
256 	    windCheckOnlyWindow(&mw, DBWclientID);
257 	if (mw != NULL)
258 	{
259 	    if (calmaLookCell(libname, NULL) != (CellDef *)NULL)
260 		DBWloadWindow(mw, libname, 0);
261 	}
262 	freeMagic(libname);
263     }
264 
265     CIFReadCellCleanup(FILE_CALMA);
266     HashKill(&calmaDefInitHash);
267     UndoEnable();
268 
269     if (calmaErrorFile != NULL) fclose(calmaErrorFile);
270 }
271 
272 /*
273  * ----------------------------------------------------------------------------
274  *
275  * calmaParseUnits --
276  *
277  * Process the CALMA_UNITS record that sets the relationship between
278  * user units (stored in the stream file) and centimicrons.
279  *
280  * Results:
281  *	TRUE if successful, FALSE if we encountered an error and
282  *	the caller should abort.
283  *
284  * Side effects:
285  *	Consumes input.
286  *	Sets calmaReadScale1 to the number of centimicrons per user
287  *	unit, and calmaReadScale2 to 1, unless calmaReadScale1 would be
288  *	less than 1, in which case we set calmaReadScale1 to 1 and
289  *	calmaReadScale2 to 1/calmaReadScale1.
290  *
291  * NOTE:
292  *	We don't care about user units, only database units.  The
293  *	GDS-II stream specifies the number of meters per database
294  *	unit, which we use to compute the number of centimicrons
295  *	per database unit.  Since database units are floating point,
296  *	there is a possibility of roundoff unless the number of
297  *	centimicrons per user unit is an integer value.
298  *
299  * ----------------------------------------------------------------------------
300  */
301 
302 bool
calmaParseUnits()303 calmaParseUnits()
304 {
305     int nbytes, rtype;
306     double metersPerDBUnit;
307     double userUnitsPerDBUnit;
308     double cuPerDBUnit;
309 
310     READRH(nbytes, rtype);
311 #ifdef	lint
312     nbytes = nbytes;
313 #endif	/* lint */
314 
315     if (rtype != CALMA_UNITS)
316     {
317 	calmaUnexpected(CALMA_UNITS, rtype);
318 	return (FALSE);
319     }
320 
321     /* Skip user units per database unit */
322     if (!calmaReadR8(&userUnitsPerDBUnit)) return (FALSE);
323 
324     /* Read meters per database unit */
325     if (!calmaReadR8(&metersPerDBUnit)) return (FALSE);
326 
327 #ifdef	notdef
328     TxPrintf("1 database unit equals %e user units\n", userUnitsPerDBUnit);
329     TxPrintf("1 database unit equals %e meters\n", metersPerDBUnit);
330     TxPrintf("1 user unit equals %e database units\n", 1.0/userUnitsPerDBUnit);
331     TxPrintf("1 meter equals %e database units\n", 1.0/metersPerDBUnit);
332 #endif	/* notdef */
333 
334     /* Meters per database unit (1.0e8 corresponds to traditional centimicrons) */
335     cuPerDBUnit = metersPerDBUnit * 1.0e8 * cifCurReadStyle->crs_multiplier;
336 
337     /*
338      * Multiply database units by calmaReadScale1, then divide
339      * by calmaReadScale2 to get CIF units.  The current scheme
340      * relies entirely on calmaReadScale1 being an integer.
341      */
342     if (cuPerDBUnit >= 1.0)
343     {
344 	calmaReadScale1 = (int)(cuPerDBUnit + 0.5);
345 	calmaReadScale2 = 1;
346     }
347     else
348     {
349 	cuPerDBUnit = 1.0 / cuPerDBUnit;
350 	calmaReadScale1 = 1;
351 	calmaReadScale2 = (int)(cuPerDBUnit + 0.5);
352     }
353 #ifdef	notdef
354     TxPrintf("All units to be scaled by %d/%d\n", calmaReadScale1, calmaReadScale2);
355 #endif	/* notdef */
356 
357     return (TRUE);
358 }
359 
360 /*
361  * ----------------------------------------------------------------------------
362  *
363  * CalmaReadError --
364  *
365  * This procedure is called to print out error messages during
366  * Calma file reading.
367  *
368  * Results:
369  *      None.
370  *
371  * Side effects:
372  *      An error message is printed.
373  *
374  * Note:
375  *      You can add more arguments if 10 turns out not to be enough.
376  *
377  * ----------------------------------------------------------------------------
378  */
379 
380 void
381     /*VARARGS1*/
CalmaReadError(format,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)382 CalmaReadError(format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
383     char *format;
384     char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8, *a9, *a10;
385 {
386     off_t filepos;
387 
388     calmaTotalErrors++;
389     if (CIFWarningLevel == CIF_WARN_NONE) return;
390 
391     if ((calmaTotalErrors < 100) || (CIFWarningLevel != CIF_WARN_LIMIT))
392     {
393 	filepos = ftello(calmaInputFile);
394 
395         if (CIFWarningLevel == CIF_WARN_REDIRECT)
396         {
397             if (calmaErrorFile != NULL)
398             {
399                 fprintf(calmaErrorFile, "Error while reading cell \"%s\" ",
400                                 cifReadCellDef->cd_name);
401 		fprintf(calmaErrorFile, "(byte position %"DLONG_PREFIX"d): ",
402 				(dlong)filepos);
403                 fprintf(calmaErrorFile, format, a1, a2, a3, a4, a5, a6, a7,
404                                 a8, a9, a10);
405             }
406         }
407         else
408         {
409             TxError("Error while reading cell \"%s\" ", cifReadCellDef->cd_name);
410 	    TxError("(byte position %"DLONG_PREFIX"d): ", (dlong)filepos);
411             TxError(format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
412         }
413     }
414     else if ((calmaTotalErrors == 100) && (CIFWarningLevel == CIF_WARN_LIMIT))
415     {
416         TxError("Error limit set:  Remaining errors will not be reported.\n");
417     }
418 }
419 
420 /*
421  * ----------------------------------------------------------------------------
422  *
423  * calmaUnexpected --
424  *
425  * Complain about a record where we expected one kind but got another.
426  *
427  * Results:
428  *	None.
429  *
430  * Side effects:
431  *	Prints an error message.
432  *
433  * ----------------------------------------------------------------------------
434  */
435 
436 void
calmaUnexpected(wanted,got)437 calmaUnexpected(wanted, got)
438     int wanted;	/* Type of record we wanted */
439     int got;	/* Type of record we got */
440 {
441     CalmaReadError("Unexpected record type in input: \n");
442 
443     if (CIFWarningLevel == CIF_WARN_NONE) return;
444     if (calmaTotalErrors < 100 || (CIFWarningLevel != CIF_WARN_LIMIT))
445     {
446 	if (CIFWarningLevel == CIF_WARN_REDIRECT)
447 	{
448 	    if (calmaErrorFile != NULL)
449 	    {
450 	        fprintf(calmaErrorFile,"    Expected %s record ",
451 			calmaRecordName(wanted));
452 		fprintf(calmaErrorFile, "but got %s.\n", calmaRecordName(got));
453 	    }
454 	}
455 	    else
456 	    {
457 	        TxError("    Expected %s record ", calmaRecordName(wanted));
458 	        TxError("but got %s.\n", calmaRecordName(got));
459 	    }
460     }
461 }
462 
463 /*
464  * ----------------------------------------------------------------------------
465  *
466  * calmaRecordName --
467  *
468  * Return a pointer to the printable name of a CALMA record type.
469  *
470  * Results:
471  *	See above.
472  *
473  * Side effects:
474  *	May overwrite the string we returned on the previous call.
475  *
476  * ----------------------------------------------------------------------------
477  */
478 
479 char *
calmaRecordName(rtype)480 calmaRecordName(rtype)
481     int rtype;
482 {
483     static char numeric[10];
484     static char *calmaRecordNames[] =
485     {
486 	"HEADER",	"BGNLIB",	"LIBNAME",	"UNITS",
487 	"ENDLIB",	"BGNSTR",	"STRNAME",	"ENDSTR",
488 	"BOUNDARY",	"PATH",		"SREF",		"AREF",
489 	"TEXT",		"LAYER",	"DATATYPE",	"WIDTH",
490 	"XY",		"ENDEL",	"SNAME",	"COLROW",
491 	"TEXTNODE",	"NODE",		"TEXTTYPE",	"PRESENTATION",
492 	"SPACING",	"STRING",	"STRANS",	"MAG",
493 	"ANGLE",	"UINTEGER",	"USTRING",	"REFLIBS",
494 	"FONTS",	"PATHTYPE",	"GENERATIONS",	"ATTRTABLE",
495 	"STYPTABLE",	"STRTYPE",	"ELFLAGS",	"ELKEY",
496 	"LINKTYPE",	"LINKKEYS",	"NODETYPE",	"PROPATTR",
497 	"PROPVALUE",	"BOX",		"BOXTYPE",	"PLEX",
498 	"BGNEXTN",	"ENDEXTN",	"TAPENUM",	"TAPECODE",
499 	"STRCLASS",	"RESERVED",	"FORMAT",	"MASK",
500 	"ENDMASKS"
501     };
502 
503     if (rtype < 0 || rtype >= CALMA_NUMRECORDTYPES)
504     {
505 	(void) sprintf(numeric, "%d", rtype);
506 	return (numeric);
507     }
508 
509     return (calmaRecordNames[rtype]);
510 }
511 
512 /*
513  * ----------------------------------------------------------------------------
514  *
515  * CalmaTechInit --
516  *
517  * Prepare for a technology file.
518  *
519  * Results:
520  *	None.
521  *
522  * Side effects:
523  *	Error checking.
524  *
525  * ----------------------------------------------------------------------------
526  */
527 
528 void
CalmaTechInit()529 CalmaTechInit()
530 {
531     ASSERT(sizeof(FourByteInt)==4, "definition in calmaInt.h");
532     ASSERT(sizeof(TwoByteInt)==2, "definition in calmaInt.h");
533 }
534