2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* CalmaRead.c --
|
|
|
|
|
*
|
|
|
|
|
* Input of Calma GDS-II stream format.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
|
|
|
|
* * Permission to use, copy, modify, and distribute this *
|
|
|
|
|
* * software and its documentation for any purpose and without *
|
|
|
|
|
* * fee is hereby granted, provided that the above copyright *
|
|
|
|
|
* * notice appear in all copies. The University of California *
|
|
|
|
|
* * makes no representations about the suitability of this *
|
|
|
|
|
* * software for any purpose. It is provided "as is" without *
|
|
|
|
|
* * express or implied warranty. Export of this software outside *
|
|
|
|
|
* * of the United States of America may require an export license. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
2024-10-04 12:19:10 +02:00
|
|
|
static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/calma/CalmaRead.c,v 1.3 2010/06/24 12:37:15 tim Exp $";
|
2017-04-25 14:41:48 +02:00
|
|
|
#endif /* not lint */
|
|
|
|
|
|
2023-07-11 17:31:37 +02:00
|
|
|
#include <stdarg.h>
|
2017-04-25 14:41:48 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
|
2023-07-11 21:53:07 +02:00
|
|
|
/*
|
|
|
|
|
* C99 compat
|
|
|
|
|
* Mind: tcltk/tclmagic.h must be included prior to all the other headers
|
|
|
|
|
*/
|
|
|
|
|
#include "tcltk/tclmagic.h"
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "tiles/tile.h"
|
|
|
|
|
#include "utils/utils.h"
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
#include "database/database.h"
|
|
|
|
|
#include "database/databaseInt.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
#include "utils/tech.h"
|
|
|
|
|
#include "cif/cif.h"
|
|
|
|
|
#include "cif/CIFint.h"
|
|
|
|
|
#include "cif/CIFread.h"
|
|
|
|
|
#include "utils/signals.h"
|
|
|
|
|
#include "windows/windows.h"
|
|
|
|
|
#include "dbwind/dbwind.h"
|
|
|
|
|
#include "utils/styles.h"
|
|
|
|
|
#include "textio/textio.h"
|
|
|
|
|
#include "calma/calmaInt.h"
|
|
|
|
|
#include "commands/commands.h" /* for CmdGetRootPoint */
|
2021-06-07 03:44:52 +02:00
|
|
|
#include "utils/main.h" /* for EditCellUse */
|
2017-04-25 14:41:48 +02:00
|
|
|
#include "utils/undo.h"
|
|
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/* C99 compat */
|
|
|
|
|
#include "calma/calma.h"
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Globals for Calma reading */
|
2022-05-10 15:19:39 +02:00
|
|
|
FILETYPE calmaInputFile = NULL; /* Read from this stream */
|
2017-04-25 14:41:48 +02:00
|
|
|
FILE *calmaErrorFile = NULL; /* Write error output here */
|
2023-01-18 02:14:38 +01:00
|
|
|
unsigned char CalmaSubcellPolygons = CALMA_POLYGON_NONE;
|
|
|
|
|
/* Read non-Manhattan polygons as-is */
|
2017-04-25 14:41:48 +02:00
|
|
|
int CalmaPolygonCount;
|
2017-10-07 04:32:52 +02:00
|
|
|
bool CalmaSubcellPaths = FALSE; /* Put paths in their own subcells. */
|
|
|
|
|
int CalmaPathCount;
|
2017-04-25 14:41:48 +02:00
|
|
|
bool CalmaFlattenUses = FALSE; /* If TRUE, small cells in the input
|
|
|
|
|
* stream are flattened when encountered
|
|
|
|
|
* as uses. This improves magic's
|
|
|
|
|
* performance when handling contacts
|
|
|
|
|
* saved as subcell arrays.
|
|
|
|
|
*/
|
2020-12-22 20:44:30 +01:00
|
|
|
char **CalmaFlattenUsesByName = NULL; /* NULL-terminated list of strings
|
|
|
|
|
* to do glob-style pattern matching
|
|
|
|
|
* to determine what cells to flatten
|
|
|
|
|
* by cellname.
|
|
|
|
|
*/
|
2017-04-25 14:41:48 +02:00
|
|
|
bool CalmaReadOnly = FALSE; /* Set files to read-only and
|
|
|
|
|
* retain file position information
|
|
|
|
|
* so cells can be written verbatim.
|
|
|
|
|
*/
|
2023-07-20 02:33:01 +02:00
|
|
|
float CalmaMagScale = 1.0; /* Scale by which to interpret the MAG
|
|
|
|
|
* record in GDS text records. The
|
|
|
|
|
* default is to treat the value as
|
|
|
|
|
* the text height in microns. This
|
|
|
|
|
* value reinterprets the scale.
|
|
|
|
|
*/
|
2017-04-25 14:41:48 +02:00
|
|
|
bool CalmaNoDRCCheck = FALSE; /* If TRUE, don't mark cells as needing
|
|
|
|
|
* a DRC check; they will be assumed
|
|
|
|
|
* DRC clean.
|
|
|
|
|
*/
|
|
|
|
|
bool CalmaPostOrder = FALSE; /* If TRUE, forces the GDS parser to
|
|
|
|
|
* read cells in post-order. It is
|
|
|
|
|
* necessary, e.g., when we need to
|
|
|
|
|
* flatten cells that are contact cuts.
|
|
|
|
|
* Added by Nishit 8/16/2004
|
|
|
|
|
*/
|
2020-12-04 22:56:51 +01:00
|
|
|
bool CalmaNoDuplicates = FALSE; /* If TRUE, then if a cell exists in
|
|
|
|
|
* memory with the same name as a cell
|
|
|
|
|
* in the GDS file, then the cell in
|
|
|
|
|
* the GDS file is skipped.
|
|
|
|
|
*/
|
2021-04-27 19:07:27 +02:00
|
|
|
bool CalmaUnique = FALSE; /* If TRUE, then if a cell exists in
|
|
|
|
|
* memory with the same name as a cell
|
|
|
|
|
* in the GDS file, then the cell in
|
|
|
|
|
* memory is renamed to a unique
|
|
|
|
|
* identifier with a _N suffix.
|
|
|
|
|
*/
|
2022-08-26 14:59:25 +02:00
|
|
|
extern bool CalmaDoLibrary; /* Also used by GDS write */
|
|
|
|
|
|
2024-10-04 12:32:22 +02:00
|
|
|
extern void calmaUnexpected(int wanted, int got);
|
|
|
|
|
extern int calmaWriteInitFunc(CellDef *def);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Scaling.
|
|
|
|
|
* Multiply all coordinates by calmaReadScale1, then divide them
|
|
|
|
|
* by calmaReadScale2 in order to get coordinates in centimicrons.
|
|
|
|
|
*/
|
|
|
|
|
int calmaReadScale1;
|
|
|
|
|
int calmaReadScale2;
|
|
|
|
|
|
|
|
|
|
int calmaTotalErrors;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Lookahead: calmaLApresent is TRUE when calmaLAnbytes and calmaLArtype
|
|
|
|
|
* are set to the record header of a record we just ungot.
|
|
|
|
|
*/
|
|
|
|
|
bool calmaLApresent; /* TRUE if lookahead input waiting */
|
|
|
|
|
int calmaLAnbytes; /* # bytes in record (from header) */
|
|
|
|
|
int calmaLArtype; /* Record type */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Hash table for errors, indexed by (layer, datatype).
|
|
|
|
|
* The corresponding entry in this table is created whenever
|
|
|
|
|
* a (layer, datatype) is seen that we don't recognize, so
|
|
|
|
|
* we don't output an error message more than once.
|
|
|
|
|
*/
|
|
|
|
|
HashTable calmaLayerHash;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Hash table to keep track of all defs that have appeared
|
|
|
|
|
* in this file. Indexed by cell def name.
|
|
|
|
|
*/
|
|
|
|
|
HashTable calmaDefInitHash;
|
|
|
|
|
|
|
|
|
|
/* Common stuff to ignore */
|
2024-10-04 12:19:10 +02:00
|
|
|
const int calmaElementIgnore[] = { CALMA_ELFLAGS, CALMA_PLEX, -1 };
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CalmaReadFile --
|
|
|
|
|
*
|
|
|
|
|
* Read an entire GDS-II stream format library from the open FILE 'file'.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* May modify the contents of cifReadCellDef by painting or adding
|
|
|
|
|
* new uses or labels. May also create new CellDefs.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
2024-10-04 12:34:50 +02:00
|
|
|
CalmaReadFile(
|
|
|
|
|
FILETYPE file, /* File from which to read Calma */
|
|
|
|
|
char *filename) /* The real name of the file read */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
int k, version;
|
2024-10-04 21:05:44 +02:00
|
|
|
char *libname = NULL, *libnameptr = NULL;
|
2017-04-25 14:41:48 +02:00
|
|
|
MagWindow *mw;
|
2024-10-04 12:19:10 +02:00
|
|
|
static const int hdrSkip[] = { CALMA_FORMAT, CALMA_MASK, CALMA_ENDMASKS,
|
|
|
|
|
CALMA_REFLIBS, CALMA_FONTS, CALMA_ATTRTABLE,
|
|
|
|
|
CALMA_STYPTABLE, CALMA_GENERATIONS, -1 };
|
|
|
|
|
static const int skipBeforeLib[] = { CALMA_LIBDIRSIZE, CALMA_SRFNAME,
|
|
|
|
|
CALMA_LIBSECUR, -1 };
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2021-06-05 23:02:39 +02:00
|
|
|
if (EditCellUse == (CellUse *)NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("Cannot read GDS: There is no edit cell.\n");
|
2021-06-07 03:44:52 +02:00
|
|
|
return;
|
2021-06-05 23:02:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* We will use full cell names as keys in this hash table */
|
|
|
|
|
CIFReadCellInit(0);
|
|
|
|
|
|
|
|
|
|
if (CIFWarningLevel == CIF_WARN_REDIRECT)
|
|
|
|
|
{
|
|
|
|
|
if (CIFErrorFilename == NULL)
|
|
|
|
|
calmaErrorFile = NULL;
|
|
|
|
|
else
|
|
|
|
|
calmaErrorFile = PaOpen(CIFErrorFilename, "w", (char *)NULL, ".",
|
|
|
|
|
(char *)NULL, (char **)NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cifCurReadStyle == NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("Don't know how to read GDS-II:\n");
|
|
|
|
|
TxError("Nothing in \"cifinput\" section of tech file.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
TxPrintf("Warning: Calma reading is not undoable! I hope that's OK.\n");
|
|
|
|
|
UndoDisable();
|
|
|
|
|
|
|
|
|
|
calmaTotalErrors = 0;
|
|
|
|
|
CalmaPolygonCount = 0;
|
2017-10-07 04:32:52 +02:00
|
|
|
CalmaPathCount = 0;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2020-11-21 01:56:41 +01:00
|
|
|
/* Reset cd_client pointers (using init function from CalmaWrite.c) */
|
|
|
|
|
/* This is in case a cell already in memory is being referenced; */
|
|
|
|
|
/* it is probably better to avoid those kinds of naming collisions */
|
|
|
|
|
/* though. . . */
|
|
|
|
|
(void) DBCellSrDefs(0, calmaWriteInitFunc, (ClientData) NULL);
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
HashInit(&calmaDefInitHash, 32, 0);
|
|
|
|
|
calmaLApresent = FALSE;
|
|
|
|
|
calmaInputFile = file;
|
|
|
|
|
|
|
|
|
|
/* Read the GDS-II header */
|
|
|
|
|
if (!calmaReadI2Record(CALMA_HEADER, &version)) goto done;
|
|
|
|
|
if (version < 600)
|
|
|
|
|
TxPrintf("Library written using GDS-II Release %d.0\n", version);
|
|
|
|
|
else
|
2020-05-23 23:13:14 +02:00
|
|
|
TxPrintf("Library written using GDS-II Release %d.%d\n",
|
2017-04-25 14:41:48 +02:00
|
|
|
version / 100, version % 100);
|
|
|
|
|
if (!calmaSkipExact(CALMA_BGNLIB)) goto done;
|
|
|
|
|
calmaSkipSet(skipBeforeLib);
|
|
|
|
|
if (!calmaReadStringRecord(CALMA_LIBNAME, &libname)) goto done;
|
2022-08-26 14:59:25 +02:00
|
|
|
|
|
|
|
|
/* Use CalmaDoLibrary similarly for input as for output; if set to */
|
|
|
|
|
/* TRUE, the library name is considered meaningless and discarded; */
|
|
|
|
|
/* the GDS file contents are read into memory but no view is loaded */
|
|
|
|
|
|
|
|
|
|
if (CalmaDoLibrary)
|
|
|
|
|
libnameptr = NULL;
|
|
|
|
|
else
|
|
|
|
|
libnameptr = libname;
|
|
|
|
|
|
|
|
|
|
if ((libnameptr != NULL) && (libname[0] != '\0'))
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2022-08-26 14:59:25 +02:00
|
|
|
bool modified = FALSE;
|
|
|
|
|
char *sptr;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Avoid generating a magic name with spaces in it. . . */
|
|
|
|
|
/* (added by Mike Godfrey, 7/17/05) */
|
|
|
|
|
|
|
|
|
|
for (k = 0; k < strlen(libname); k++)
|
|
|
|
|
if (libname[k] == ' ')
|
2022-08-26 14:59:25 +02:00
|
|
|
{
|
2017-04-25 14:41:48 +02:00
|
|
|
libname[k] = '_';
|
2022-08-26 14:59:25 +02:00
|
|
|
modified = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Avoid generating a magic name with slashes in it. . . */
|
|
|
|
|
/* (added by Tim, 8/26/2022) */
|
|
|
|
|
|
|
|
|
|
if ((sptr = strrchr(libname, '/')) != NULL)
|
|
|
|
|
{
|
|
|
|
|
libnameptr = sptr + 1;
|
|
|
|
|
modified = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (modified)
|
|
|
|
|
TxPrintf("Library name modified to make legal cell name syntax.\n");
|
|
|
|
|
TxPrintf("Library name: %s\n", libnameptr);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Skip the reflibs, fonts, etc. cruft */
|
|
|
|
|
calmaSkipSet(hdrSkip);
|
|
|
|
|
|
|
|
|
|
/* Set the scale factors */
|
|
|
|
|
if (!calmaParseUnits()) goto done;
|
|
|
|
|
|
|
|
|
|
/* Main body of GDS-II input */
|
2022-05-28 16:33:21 +02:00
|
|
|
while (calmaParseStructure(filename))
|
2017-04-25 14:41:48 +02:00
|
|
|
if (SigInterruptPending)
|
|
|
|
|
goto done;
|
|
|
|
|
(void) calmaSkipExact(CALMA_ENDLIB);
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
|
|
|
|
|
/* Added by Nishit, Sept. 2004---Load cell read from GDS */
|
|
|
|
|
/* stream file to the magic layout window. If this fails */
|
|
|
|
|
/* then we do the original action and don't do a load into */
|
|
|
|
|
/* the window. Note that this follows the Magic GDS output */
|
|
|
|
|
/* convention of giving the library the name of the */
|
|
|
|
|
/* top-level cell, so magic-produced GDS can be read back */
|
|
|
|
|
/* with the expected cell appearing in the layout window. */
|
|
|
|
|
|
2022-08-26 14:59:25 +02:00
|
|
|
if (libnameptr != NULL)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
mw = CmdGetRootPoint((Point *)NULL, (Rect *)NULL);
|
|
|
|
|
if (mw == NULL)
|
|
|
|
|
windCheckOnlyWindow(&mw, DBWclientID);
|
|
|
|
|
if (mw != NULL)
|
|
|
|
|
{
|
2024-10-04 12:37:20 +02:00
|
|
|
if (calmaLookCell(libnameptr) != (CellDef *)NULL)
|
2022-08-26 14:59:25 +02:00
|
|
|
DBWloadWindow(mw, libnameptr, 0);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
freeMagic(libname);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-23 14:45:42 +02:00
|
|
|
CIFReadCellCleanup(FILE_CALMA);
|
2017-04-25 14:41:48 +02:00
|
|
|
HashKill(&calmaDefInitHash);
|
|
|
|
|
UndoEnable();
|
|
|
|
|
|
2024-10-04 21:05:44 +02:00
|
|
|
if (calmaErrorFile != NULL)
|
|
|
|
|
{
|
|
|
|
|
fclose(calmaErrorFile);
|
|
|
|
|
calmaErrorFile = NULL;
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* calmaParseUnits --
|
|
|
|
|
*
|
|
|
|
|
* Process the CALMA_UNITS record that sets the relationship between
|
|
|
|
|
* user units (stored in the stream file) and centimicrons.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE if successful, FALSE if we encountered an error and
|
|
|
|
|
* the caller should abort.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Consumes input.
|
|
|
|
|
* Sets calmaReadScale1 to the number of centimicrons per user
|
|
|
|
|
* unit, and calmaReadScale2 to 1, unless calmaReadScale1 would be
|
|
|
|
|
* less than 1, in which case we set calmaReadScale1 to 1 and
|
|
|
|
|
* calmaReadScale2 to 1/calmaReadScale1.
|
|
|
|
|
*
|
|
|
|
|
* NOTE:
|
|
|
|
|
* We don't care about user units, only database units. The
|
|
|
|
|
* GDS-II stream specifies the number of meters per database
|
|
|
|
|
* unit, which we use to compute the number of centimicrons
|
|
|
|
|
* per database unit. Since database units are floating point,
|
|
|
|
|
* there is a possibility of roundoff unless the number of
|
|
|
|
|
* centimicrons per user unit is an integer value.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
2024-10-04 12:34:50 +02:00
|
|
|
calmaParseUnits(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2024-09-30 00:00:00 +02:00
|
|
|
int nbytes, rtype = 0;
|
2017-04-25 14:41:48 +02:00
|
|
|
double metersPerDBUnit;
|
|
|
|
|
double userUnitsPerDBUnit;
|
|
|
|
|
double cuPerDBUnit;
|
2023-11-21 15:44:16 +01:00
|
|
|
bool compatible;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
READRH(nbytes, rtype);
|
|
|
|
|
#ifdef lint
|
|
|
|
|
nbytes = nbytes;
|
|
|
|
|
#endif /* lint */
|
|
|
|
|
|
|
|
|
|
if (rtype != CALMA_UNITS)
|
|
|
|
|
{
|
|
|
|
|
calmaUnexpected(CALMA_UNITS, rtype);
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Skip user units per database unit */
|
|
|
|
|
if (!calmaReadR8(&userUnitsPerDBUnit)) return (FALSE);
|
|
|
|
|
|
|
|
|
|
/* Read meters per database unit */
|
|
|
|
|
if (!calmaReadR8(&metersPerDBUnit)) return (FALSE);
|
|
|
|
|
|
2023-11-21 15:44:16 +01:00
|
|
|
/* Important! When CalmaReadOnly is TRUE, then this file will have its
|
|
|
|
|
* contents output verbatim. But if the database units don't match,
|
|
|
|
|
* then it will get output at the wrong scale. Setting a magnification
|
|
|
|
|
* factor on the instance when generating output might (?) work. For
|
|
|
|
|
* now, prohibiting a GDS read in read-only mode when the database units
|
|
|
|
|
* don't match. This forces the user either to reconsider the read-only
|
|
|
|
|
* status or to rewrite the GDS at a compatible scalefactor.
|
|
|
|
|
*/
|
|
|
|
|
compatible = TRUE;
|
|
|
|
|
if (CalmaReadOnly == TRUE)
|
|
|
|
|
{
|
|
|
|
|
if (CIFCurStyle->cs_flags & CWF_ANGSTROMS)
|
|
|
|
|
{
|
|
|
|
|
if ((int)(0.5 + metersPerDBUnit * 1e12) != 100)
|
|
|
|
|
{
|
|
|
|
|
CalmaReadError("Incompatible scale factor of %g, must be 1e-10.\n",
|
|
|
|
|
metersPerDBUnit);
|
|
|
|
|
TxError("Cannot read this file in read-only mode.\n");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if ((int)(0.5 + metersPerDBUnit * 1e11) != 100)
|
|
|
|
|
{
|
|
|
|
|
CalmaReadError("Incompatible scale factor of %g, must be 1e-9.\n",
|
|
|
|
|
metersPerDBUnit);
|
|
|
|
|
TxError("Cannot read this file in read-only mode.\n");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
#ifdef notdef
|
|
|
|
|
TxPrintf("1 database unit equals %e user units\n", userUnitsPerDBUnit);
|
|
|
|
|
TxPrintf("1 database unit equals %e meters\n", metersPerDBUnit);
|
|
|
|
|
TxPrintf("1 user unit equals %e database units\n", 1.0/userUnitsPerDBUnit);
|
|
|
|
|
TxPrintf("1 meter equals %e database units\n", 1.0/metersPerDBUnit);
|
|
|
|
|
#endif /* notdef */
|
|
|
|
|
|
|
|
|
|
/* Meters per database unit (1.0e8 corresponds to traditional centimicrons) */
|
|
|
|
|
cuPerDBUnit = metersPerDBUnit * 1.0e8 * cifCurReadStyle->crs_multiplier;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Multiply database units by calmaReadScale1, then divide
|
|
|
|
|
* by calmaReadScale2 to get CIF units. The current scheme
|
|
|
|
|
* relies entirely on calmaReadScale1 being an integer.
|
|
|
|
|
*/
|
|
|
|
|
if (cuPerDBUnit >= 1.0)
|
|
|
|
|
{
|
|
|
|
|
calmaReadScale1 = (int)(cuPerDBUnit + 0.5);
|
|
|
|
|
calmaReadScale2 = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cuPerDBUnit = 1.0 / cuPerDBUnit;
|
|
|
|
|
calmaReadScale1 = 1;
|
|
|
|
|
calmaReadScale2 = (int)(cuPerDBUnit + 0.5);
|
|
|
|
|
}
|
|
|
|
|
#ifdef notdef
|
|
|
|
|
TxPrintf("All units to be scaled by %d/%d\n", calmaReadScale1, calmaReadScale2);
|
|
|
|
|
#endif /* notdef */
|
|
|
|
|
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
2019-07-23 14:45:42 +02:00
|
|
|
* CalmaReadError --
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* This procedure is called to print out error messages during
|
|
|
|
|
* Calma file reading.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* An error message is printed.
|
|
|
|
|
*
|
|
|
|
|
* Note:
|
|
|
|
|
* You can add more arguments if 10 turns out not to be enough.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
2024-10-04 12:34:50 +02:00
|
|
|
void
|
2024-10-03 23:47:50 +02:00
|
|
|
CalmaReadError(const char *format, ...)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2023-07-11 17:31:37 +02:00
|
|
|
va_list args;
|
2022-05-10 15:19:39 +02:00
|
|
|
OFFTYPE filepos;
|
2019-05-22 22:12:13 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
calmaTotalErrors++;
|
|
|
|
|
if (CIFWarningLevel == CIF_WARN_NONE) return;
|
|
|
|
|
|
|
|
|
|
if ((calmaTotalErrors < 100) || (CIFWarningLevel != CIF_WARN_LIMIT))
|
2020-05-23 23:13:14 +02:00
|
|
|
{
|
2022-05-10 15:19:39 +02:00
|
|
|
filepos = FTELL(calmaInputFile);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
if (CIFWarningLevel == CIF_WARN_REDIRECT)
|
|
|
|
|
{
|
|
|
|
|
if (calmaErrorFile != NULL)
|
|
|
|
|
{
|
2019-05-22 22:12:13 +02:00
|
|
|
fprintf(calmaErrorFile, "Error while reading cell \"%s\" ",
|
2017-04-25 14:41:48 +02:00
|
|
|
cifReadCellDef->cd_name);
|
2020-12-23 21:26:50 +01:00
|
|
|
fprintf(calmaErrorFile, "(byte position %"DLONG_PREFIX"d): ",
|
2019-05-22 22:12:13 +02:00
|
|
|
(dlong)filepos);
|
2023-07-11 17:31:37 +02:00
|
|
|
va_start(args, format);
|
|
|
|
|
Vfprintf(calmaErrorFile, format, args);
|
|
|
|
|
va_end(args);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-05-22 22:12:13 +02:00
|
|
|
TxError("Error while reading cell \"%s\" ", cifReadCellDef->cd_name);
|
|
|
|
|
TxError("(byte position %"DLONG_PREFIX"d): ", (dlong)filepos);
|
2023-07-11 22:18:47 +02:00
|
|
|
va_start(args, format);
|
|
|
|
|
TxErrorV(format, args);
|
|
|
|
|
va_end(args);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if ((calmaTotalErrors == 100) && (CIFWarningLevel == CIF_WARN_LIMIT))
|
|
|
|
|
{
|
|
|
|
|
TxError("Error limit set: Remaining errors will not be reported.\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* calmaUnexpected --
|
|
|
|
|
*
|
|
|
|
|
* Complain about a record where we expected one kind but got another.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Prints an error message.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
2024-10-04 12:34:50 +02:00
|
|
|
calmaUnexpected(
|
|
|
|
|
int wanted, /* Type of record we wanted */
|
|
|
|
|
int got) /* Type of record we got */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2019-07-23 14:45:42 +02:00
|
|
|
CalmaReadError("Unexpected record type in input: \n");
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
if (CIFWarningLevel == CIF_WARN_NONE) return;
|
|
|
|
|
if (calmaTotalErrors < 100 || (CIFWarningLevel != CIF_WARN_LIMIT))
|
|
|
|
|
{
|
|
|
|
|
if (CIFWarningLevel == CIF_WARN_REDIRECT)
|
|
|
|
|
{
|
|
|
|
|
if (calmaErrorFile != NULL)
|
|
|
|
|
{
|
|
|
|
|
fprintf(calmaErrorFile," Expected %s record ",
|
|
|
|
|
calmaRecordName(wanted));
|
|
|
|
|
fprintf(calmaErrorFile, "but got %s.\n", calmaRecordName(got));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TxError(" Expected %s record ", calmaRecordName(wanted));
|
|
|
|
|
TxError("but got %s.\n", calmaRecordName(got));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* calmaRecordName --
|
|
|
|
|
*
|
|
|
|
|
* Return a pointer to the printable name of a CALMA record type.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* See above.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* May overwrite the string we returned on the previous call.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
2024-10-04 12:19:10 +02:00
|
|
|
const char *
|
2024-10-04 12:34:50 +02:00
|
|
|
calmaRecordName(
|
|
|
|
|
int rtype)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
static char numeric[10];
|
2024-10-04 12:19:10 +02:00
|
|
|
static const char * const calmaRecordNames[] =
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
"HEADER", "BGNLIB", "LIBNAME", "UNITS",
|
|
|
|
|
"ENDLIB", "BGNSTR", "STRNAME", "ENDSTR",
|
|
|
|
|
"BOUNDARY", "PATH", "SREF", "AREF",
|
|
|
|
|
"TEXT", "LAYER", "DATATYPE", "WIDTH",
|
|
|
|
|
"XY", "ENDEL", "SNAME", "COLROW",
|
|
|
|
|
"TEXTNODE", "NODE", "TEXTTYPE", "PRESENTATION",
|
|
|
|
|
"SPACING", "STRING", "STRANS", "MAG",
|
|
|
|
|
"ANGLE", "UINTEGER", "USTRING", "REFLIBS",
|
|
|
|
|
"FONTS", "PATHTYPE", "GENERATIONS", "ATTRTABLE",
|
|
|
|
|
"STYPTABLE", "STRTYPE", "ELFLAGS", "ELKEY",
|
|
|
|
|
"LINKTYPE", "LINKKEYS", "NODETYPE", "PROPATTR",
|
|
|
|
|
"PROPVALUE", "BOX", "BOXTYPE", "PLEX",
|
|
|
|
|
"BGNEXTN", "ENDEXTN", "TAPENUM", "TAPECODE",
|
|
|
|
|
"STRCLASS", "RESERVED", "FORMAT", "MASK",
|
|
|
|
|
"ENDMASKS"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (rtype < 0 || rtype >= CALMA_NUMRECORDTYPES)
|
|
|
|
|
{
|
|
|
|
|
(void) sprintf(numeric, "%d", rtype);
|
|
|
|
|
return (numeric);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (calmaRecordNames[rtype]);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CalmaTechInit --
|
|
|
|
|
*
|
|
|
|
|
* Prepare for a technology file.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Error checking.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
2024-10-04 12:34:50 +02:00
|
|
|
CalmaTechInit(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
ASSERT(sizeof(FourByteInt)==4, "definition in calmaInt.h");
|
|
|
|
|
ASSERT(sizeof(TwoByteInt)==2, "definition in calmaInt.h");
|
2022-11-10 20:08:58 +01:00
|
|
|
|
2025-09-26 15:18:43 +02:00
|
|
|
/* NOTE: Add "$$*$$" to the default "flatglob" value */
|
|
|
|
|
/* when CalmaContactArrays behaves like the non-arrayed */
|
|
|
|
|
/* function and can be enabled by default. */
|
|
|
|
|
|
2022-11-10 20:08:58 +01:00
|
|
|
/* Initialize CalmaFlattenByName to have one entry for */
|
2025-09-26 15:18:43 +02:00
|
|
|
/* "*_CDNS_*" to match the name style used by many foundry */
|
|
|
|
|
/* cells and which corresponds to pcells that often split */
|
|
|
|
|
/* layers between cells in ways that magic can't cope with; */
|
|
|
|
|
/* and whose original parameterized functions cannot be */
|
|
|
|
|
/* recovered by magic anyway. When necessary, this default */
|
|
|
|
|
/* can be overridden by the "gds flatglob none" command */
|
|
|
|
|
/* option. */
|
2022-11-10 20:08:58 +01:00
|
|
|
|
|
|
|
|
if (CalmaFlattenUsesByName == (char **)NULL)
|
|
|
|
|
{
|
|
|
|
|
CalmaFlattenUsesByName = (char **)mallocMagic(2 * sizeof(char *));
|
2025-09-26 15:18:43 +02:00
|
|
|
*CalmaFlattenUsesByName = StrDup((char **)NULL, "*_CDNS_*");
|
2022-11-10 20:08:58 +01:00
|
|
|
*(CalmaFlattenUsesByName + 1) = NULL;
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|