Several enhancements: (1) Added command option "gds no_duplicates"
to allow a "gds read" command to ignore cells in the GDS which already exist in memory. This allows magic to be "pre-seeded" with specific views of cells in the GDS. Default is false, which is backwards- compatble behavior. (2) Changed the behavior of the the way the use path is written to and read from a .mag file, checking the path prefix against Tcl variables PDK_PATH, PDKPATH, PDK_ROOT, and PDKROOT, and replacing any such leading path component with the variable name. On reading a .mag file, any variable name at the start of the path that matches a Tcl variable will be substituted.
This commit is contained in:
parent
1b3299ec90
commit
1c82265244
|
|
@ -290,6 +290,7 @@ calmaParseStructure(filename)
|
|||
off_t filepos;
|
||||
bool was_called;
|
||||
bool was_initialized;
|
||||
bool predefined;
|
||||
CellDef *def;
|
||||
|
||||
/* Make sure this is a structure; if not, let the caller know we're done */
|
||||
|
|
@ -299,6 +300,7 @@ calmaParseStructure(filename)
|
|||
|
||||
/* Read the structure name */
|
||||
was_initialized = FALSE;
|
||||
predefined = FALSE;
|
||||
if (!calmaSkipExact(CALMA_BGNSTR)) goto syntaxerror;
|
||||
if (!calmaReadStringRecord(CALMA_STRNAME, &strname)) goto syntaxerror;
|
||||
TxPrintf("Reading \"%s\".\n", strname);
|
||||
|
|
@ -345,7 +347,12 @@ calmaParseStructure(filename)
|
|||
freeMagic(newname);
|
||||
}
|
||||
}
|
||||
cifReadCellDef = calmaFindCell(strname, &was_called);
|
||||
cifReadCellDef = calmaFindCell(strname, &was_called, &predefined);
|
||||
if (predefined == TRUE)
|
||||
{
|
||||
calmaNextCell();
|
||||
return TRUE;
|
||||
}
|
||||
DBCellClearDef(cifReadCellDef);
|
||||
DBCellSetAvail(cifReadCellDef);
|
||||
HashSetValue(he, cifReadCellDef);
|
||||
|
|
@ -666,7 +673,7 @@ calmaElementSref(filename)
|
|||
{
|
||||
TxPrintf("Cell definition %s does not exist!\n", sname);
|
||||
fseek(calmaInputFile, originalFilePos, SEEK_SET);
|
||||
def = calmaFindCell(sname, NULL);
|
||||
def = calmaFindCell(sname, NULL, NULL);
|
||||
/* Cell flags set to "dereferenced" in case there is no */
|
||||
/* definition in the GDS file. If there is a definition */
|
||||
/* made after the instance, then the flag will be cleared. */
|
||||
|
|
@ -674,7 +681,7 @@ calmaElementSref(filename)
|
|||
}
|
||||
}
|
||||
|
||||
if (!def) def = calmaFindCell(sname, NULL);
|
||||
if (!def) def = calmaFindCell(sname, NULL, NULL);
|
||||
|
||||
if (DBIsAncestor(def, cifReadCellDef))
|
||||
{
|
||||
|
|
@ -1031,13 +1038,16 @@ gdsCopyPaintFunc(tile, gdsCopyRec)
|
|||
*/
|
||||
|
||||
CellDef *
|
||||
calmaFindCell(name, was_called)
|
||||
calmaFindCell(name, was_called, predefined)
|
||||
char *name; /* Name of desired cell */
|
||||
bool *was_called; /* If this cell is in the hash table, then it
|
||||
* was instanced before it was defined. We
|
||||
* need to know this so as to avoid flattening
|
||||
* the cell if requested.
|
||||
*/
|
||||
bool *predefined; /* If this cell was in memory before the GDS
|
||||
* file was read, then this flag gets set.
|
||||
*/
|
||||
|
||||
{
|
||||
HashEntry *h;
|
||||
|
|
@ -1059,6 +1069,16 @@ calmaFindCell(name, was_called)
|
|||
*/
|
||||
DBReComputeBbox(def);
|
||||
}
|
||||
else
|
||||
{
|
||||
TxPrintf("Warning: cell %s already existed before reading GDS!\n",
|
||||
name);
|
||||
if (CalmaNoDuplicates)
|
||||
{
|
||||
if (predefined) *predefined = TRUE;
|
||||
TxPrintf("Using pre-existing cell definition\n");
|
||||
}
|
||||
}
|
||||
HashSetValue(h, def);
|
||||
if (was_called) *was_called = FALSE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,11 @@ bool CalmaPostOrder = FALSE; /* If TRUE, forces the GDS parser to
|
|||
* flatten cells that are contact cuts.
|
||||
* Added by Nishit 8/16/2004
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
extern void calmaUnexpected();
|
||||
extern int calmaWriteInitFunc();
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ extern bool CalmaDoLabels;
|
|||
extern bool CalmaDoLibrary;
|
||||
extern bool CalmaDoLower;
|
||||
extern bool CalmaAddendum;
|
||||
extern bool CalmaNoDuplicates;
|
||||
extern bool CalmaMergeTiles;
|
||||
extern bool CalmaFlattenArrays;
|
||||
extern bool CalmaNoDRCCheck;
|
||||
|
|
|
|||
|
|
@ -99,13 +99,14 @@ bool cmdDumpParseArgs();
|
|||
#define CALMA_LIBRARY 8
|
||||
#define CALMA_LOWER 9
|
||||
#define CALMA_MERGE 10
|
||||
#define CALMA_READ 11
|
||||
#define CALMA_READONLY 12
|
||||
#define CALMA_RESCALE 13
|
||||
#define CALMA_WARNING 14
|
||||
#define CALMA_WRITE 15
|
||||
#define CALMA_POLYS 16
|
||||
#define CALMA_PATHS 17
|
||||
#define CALMA_NO_DUP 11
|
||||
#define CALMA_READ 12
|
||||
#define CALMA_READONLY 13
|
||||
#define CALMA_RESCALE 14
|
||||
#define CALMA_WARNING 15
|
||||
#define CALMA_WRITE 16
|
||||
#define CALMA_POLYS 17
|
||||
#define CALMA_PATHS 18
|
||||
|
||||
#define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */
|
||||
|
||||
|
|
@ -138,6 +139,7 @@ CmdCalma(w, cmd)
|
|||
"library [yes|no] do not output the top level, only subcells",
|
||||
"lower [yes|no] allow both upper and lower case in labels",
|
||||
"merge [yes|no] merge tiles into polygons in the output",
|
||||
"noduplicates [yes|no] do not read cells that exist before reading GDS",
|
||||
"read file read Calma GDS-II format from \"file\"\n"
|
||||
" into edit cell",
|
||||
"readonly [yes|no] set cell as read-only and generate output from GDS file",
|
||||
|
|
@ -451,6 +453,26 @@ CmdCalma(w, cmd)
|
|||
CalmaSubcellPolygons = (option < 3) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_NO_DUP:
|
||||
if (cmd->tx_argc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaNoDuplicates));
|
||||
#else
|
||||
TxPrintf("Cell defs that exist before reading GDS will not be paresd.\n",
|
||||
(CalmaNoDuplicates) ? "not " : "");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
else if (cmd->tx_argc != 3)
|
||||
goto wrongNumArgs;
|
||||
|
||||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaNoDuplicates = (option < 3) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_PATHS:
|
||||
if (cmd->tx_argc == 3)
|
||||
{
|
||||
|
|
|
|||
118
database/DBio.c
118
database/DBio.c
|
|
@ -45,6 +45,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <paths.h>
|
||||
#endif
|
||||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "tiles/tile.h"
|
||||
|
|
@ -1373,7 +1374,7 @@ badTransform:
|
|||
else if (DBIsAncestor(subCellDef, cellDef))
|
||||
{
|
||||
/*
|
||||
* Watchout for attempts to create circular structures.
|
||||
* Watch out for attempts to create circular structures.
|
||||
* If this happens, disregard the subcell.
|
||||
*/
|
||||
TxPrintf("Subcells are used circularly!\n");
|
||||
|
|
@ -1382,6 +1383,33 @@ badTransform:
|
|||
goto nextLine;
|
||||
}
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
/* If path starts with '$' then check for a possible Tcl variable */
|
||||
/* replacement. */
|
||||
|
||||
if (*pathptr == '$')
|
||||
{
|
||||
char *varstart, *varend, savechar, *tvar;
|
||||
|
||||
varstart = pathptr + 1;
|
||||
if (*varstart == '{') varstart++;
|
||||
varend = varstart + 1;
|
||||
while (*varend != '\0' && *varend != '}' && *varend != '/'
|
||||
&& *varend != '\n' && *varend != ' ') varend++;
|
||||
savechar = *varend;
|
||||
*varend = '\0';
|
||||
|
||||
tvar = (char *)Tcl_GetVar(magicinterp, varstart, TCL_GLOBAL_ONLY);
|
||||
*varend = savechar;
|
||||
if (savechar == '}') varend++;
|
||||
if (tvar)
|
||||
{
|
||||
memmove(pathptr + strlen(tvar), varend, strlen(varend) + 1);
|
||||
memmove(pathptr, tvar, strlen(tvar));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Relative path handling: If path does not have a leading "/" */
|
||||
/* or "~" and cellDef->cd_file has path components, then the path */
|
||||
/* should be interpreted relative to the path of the parent cell. */
|
||||
|
|
@ -3146,6 +3174,7 @@ dbWriteCellFunc(cellUse, cdarg)
|
|||
struct writeArg *arg = (struct writeArg *) cdarg;
|
||||
Transform *t;
|
||||
Rect *b;
|
||||
bool subbed = FALSE;
|
||||
char cstring[256], *pathend, *pathstart, *parent;
|
||||
|
||||
t = &(cellUse->cu_transform);
|
||||
|
|
@ -3197,25 +3226,90 @@ dbWriteCellFunc(cellUse, cdarg)
|
|||
}
|
||||
else
|
||||
{
|
||||
/* If path starts with home path, then replace with "~" */
|
||||
/* to make IP semi-portable between home directories */
|
||||
/* with the same file structure. */
|
||||
#ifdef MAGIC_WRAPPER
|
||||
char *tvar;
|
||||
|
||||
char *homedir = getenv("HOME");
|
||||
/* Check for the leading component of the file path being equal to */
|
||||
/* one of several common variable names for the PDK location, and */
|
||||
/* if there is a match, then substitute the variable name for the */
|
||||
/* matching leading path component. */
|
||||
|
||||
if (!strncmp(cellUse->cu_def->cd_file, homedir, strlen(homedir))
|
||||
&& (*(cellUse->cu_def->cd_file + strlen(homedir)) == '/'))
|
||||
if (subbed == FALSE)
|
||||
{
|
||||
sprintf(cstring, "use %s %c%s ~%s\n", cellUse->cu_def->cd_name,
|
||||
tvar = (char *)Tcl_GetVar(magicinterp, "PDK_PATH", TCL_GLOBAL_ONLY);
|
||||
if (tvar)
|
||||
if (!strncmp(pathstart, tvar, strlen(tvar)))
|
||||
{
|
||||
sprintf(cstring, "use %s %c%s $PDK_PATH%s\n",
|
||||
cellUse->cu_def->cd_name,
|
||||
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
|
||||
cellUse->cu_id, pathstart + strlen(tvar));
|
||||
subbed = TRUE;
|
||||
}
|
||||
}
|
||||
if (subbed == FALSE)
|
||||
{
|
||||
tvar = (char *)Tcl_GetVar(magicinterp, "PDKPATH", TCL_GLOBAL_ONLY);
|
||||
if (tvar)
|
||||
if (!strncmp(pathstart, tvar, strlen(tvar)))
|
||||
{
|
||||
sprintf(cstring, "use %s %c%s $PDKPATH%s\n",
|
||||
cellUse->cu_def->cd_name,
|
||||
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
|
||||
cellUse->cu_id, pathstart + strlen(tvar));
|
||||
subbed = TRUE;
|
||||
}
|
||||
}
|
||||
if (subbed == FALSE)
|
||||
{
|
||||
tvar = (char *)Tcl_GetVar(magicinterp, "PDK_ROOT", TCL_GLOBAL_ONLY);
|
||||
if (tvar)
|
||||
if (!strncmp(pathstart, tvar, strlen(tvar)))
|
||||
{
|
||||
sprintf(cstring, "use %s %c%s $PDK_ROOT%s\n",
|
||||
cellUse->cu_def->cd_name,
|
||||
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
|
||||
cellUse->cu_id, pathstart + strlen(tvar));
|
||||
subbed = TRUE;
|
||||
}
|
||||
}
|
||||
if (subbed == FALSE)
|
||||
{
|
||||
tvar = (char *)Tcl_GetVar(magicinterp, "PDKROOT", TCL_GLOBAL_ONLY);
|
||||
if (tvar)
|
||||
if (!strncmp(pathstart, tvar, strlen(tvar)))
|
||||
{
|
||||
sprintf(cstring, "use %s %c%s $PDKROOT%s\n",
|
||||
cellUse->cu_def->cd_name,
|
||||
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
|
||||
cellUse->cu_id, pathstart + strlen(tvar));
|
||||
subbed = TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (subbed == FALSE)
|
||||
{
|
||||
/* If path starts with home path, then replace with "~" */
|
||||
/* to make IP semi-portable between home directories */
|
||||
/* with the same file structure. */
|
||||
|
||||
char *homedir = getenv("HOME");
|
||||
|
||||
if (!strncmp(cellUse->cu_def->cd_file, homedir, strlen(homedir))
|
||||
&& (*(cellUse->cu_def->cd_file + strlen(homedir)) == '/'))
|
||||
{
|
||||
sprintf(cstring, "use %s %c%s ~%s\n", cellUse->cu_def->cd_name,
|
||||
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
|
||||
cellUse->cu_id, cellUse->cu_def->cd_file +
|
||||
strlen(homedir));
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(cstring, "use %s %c%s %s\n", cellUse->cu_def->cd_name,
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(cstring, "use %s %c%s %s\n", cellUse->cu_def->cd_name,
|
||||
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
|
||||
cellUse->cu_id, pathstart);
|
||||
}
|
||||
}
|
||||
}
|
||||
FPRINTR(arg->wa_file, cstring);
|
||||
|
|
|
|||
Loading…
Reference in New Issue