Merge branch 'master' of https://github.com/RTimothyEdwards/magic into spice_hier
This commit is contained in:
commit
bbe256e77d
|
|
@ -1,5 +0,0 @@
|
|||
[filter "header"]
|
||||
smudge = ./.git-expand-header %f
|
||||
clean = sed -e's/\\$Header:[^$]*\\$/\\$Header\\$/g'
|
||||
[diff "gds"]
|
||||
textconv = hexdump -v -C
|
||||
|
|
@ -21,9 +21,13 @@ scmos/scmos-sub.tech
|
|||
scmos/scmos-tm.tech
|
||||
scmos/scmos.tech
|
||||
scmos/scmosWR.tech
|
||||
scmos/nmos.tech
|
||||
tcltk/magic.sh
|
||||
tcltk/magic.tcl
|
||||
tcltk/magicdnull
|
||||
tcltk/magicexec
|
||||
tcltk/ext2spice.sh
|
||||
tcltk/ext2sim.sh
|
||||
magic/tclmagic.dylib
|
||||
tcltk/magicdnull.dSYM/
|
||||
tcltk/magicexec.dSYM/
|
||||
|
|
|
|||
|
|
@ -290,6 +290,8 @@ calmaParseStructure(filename)
|
|||
off_t filepos;
|
||||
bool was_called;
|
||||
bool was_initialized;
|
||||
bool predefined;
|
||||
bool do_flatten;
|
||||
CellDef *def;
|
||||
|
||||
/* Make sure this is a structure; if not, let the caller know we're done */
|
||||
|
|
@ -299,6 +301,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,16 +348,18 @@ 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);
|
||||
cifCurReadPlanes = cifSubcellPlanes;
|
||||
cifReadCellDef->cd_flags &= ~CDDEREFERENCE;
|
||||
|
||||
/* Done with strname */
|
||||
if (strname != NULL) freeMagic(strname);
|
||||
|
||||
/* For read-only cells, set flag in def */
|
||||
if (CalmaReadOnly)
|
||||
cifReadCellDef->cd_flags |= CDVENDORGDS;
|
||||
|
|
@ -403,7 +408,36 @@ calmaParseStructure(filename)
|
|||
/* cifReadCellDef->cd_flags |= CDNOEDIT; */
|
||||
}
|
||||
|
||||
/* Make sure it ends with an ENDSTR record */
|
||||
/* Check if the cell name matches the pattern list of cells to flatten */
|
||||
|
||||
do_flatten = FALSE;
|
||||
if ((CalmaFlattenUsesByName != NULL) && (!was_called))
|
||||
{
|
||||
int i = 0;
|
||||
char *pattern;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
pattern = CalmaFlattenUsesByName[i];
|
||||
if (pattern == NULL) break;
|
||||
i++;
|
||||
|
||||
/* Check pattern against strname */
|
||||
if (Match(pattern, strname))
|
||||
{
|
||||
do_flatten = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CalmaFlattenUses && (!was_called) && (npaths < CalmaFlattenLimit)
|
||||
&& (nsrefs == 0))
|
||||
do_flatten = TRUE;
|
||||
|
||||
/* Done with strname */
|
||||
if (strname != NULL) freeMagic(strname);
|
||||
|
||||
/* Make sure the structure ends with an ENDSTR record */
|
||||
if (!calmaSkipExact(CALMA_ENDSTR)) goto syntaxerror;
|
||||
|
||||
/*
|
||||
|
|
@ -411,13 +445,13 @@ calmaParseStructure(filename)
|
|||
* cell by painting when instanced. But---if this cell was
|
||||
* instanced before it was defined, then it can't be flattened.
|
||||
*/
|
||||
if (CalmaFlattenUses && (!was_called) && (npaths < CalmaFlattenLimit)
|
||||
&& (nsrefs == 0))
|
||||
|
||||
if (do_flatten)
|
||||
{
|
||||
/* If CDFLATGDS is already set, may need to remove */
|
||||
/* existing planes and free memory. */
|
||||
|
||||
if ((cifReadCellDef->cd_client != (ClientData)CLIENTDEFAULT) &&
|
||||
if ((cifReadCellDef->cd_client != (ClientData)0) &&
|
||||
(cifReadCellDef->cd_flags & CDFLATGDS))
|
||||
{
|
||||
Plane **cifplanes = (Plane **)cifReadCellDef->cd_client;
|
||||
|
|
@ -432,7 +466,7 @@ calmaParseStructure(filename)
|
|||
}
|
||||
}
|
||||
freeMagic((char *)cifReadCellDef->cd_client);
|
||||
cifReadCellDef->cd_client = (ClientData)CLIENTDEFAULT;
|
||||
cifReadCellDef->cd_client = (ClientData)0;
|
||||
}
|
||||
|
||||
TxPrintf("Saving contents of cell %s\n", cifReadCellDef->cd_name);
|
||||
|
|
@ -610,7 +644,7 @@ calmaElementSref(filename)
|
|||
*/
|
||||
|
||||
def = calmaLookCell(sname);
|
||||
if (!def && (CalmaPostOrder || CalmaFlattenUses))
|
||||
if (!def && (CalmaPostOrder || CalmaFlattenUses || (CalmaFlattenUsesByName != NULL)))
|
||||
{
|
||||
/* Force the GDS parser to read the cell definition in
|
||||
* post-order. If cellname "sname" is not defined before
|
||||
|
|
@ -659,14 +693,14 @@ calmaElementSref(filename)
|
|||
scalen = 1;
|
||||
scaled = cifCurReadStyle->crs_multiplier / crsMultiplier;
|
||||
}
|
||||
CIFScalePlanes(scalen, scaled, cifCurReadPlanes);
|
||||
CIFScalePlanes(scaled, scalen, cifCurReadPlanes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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 +708,7 @@ calmaElementSref(filename)
|
|||
}
|
||||
}
|
||||
|
||||
if (!def) def = calmaFindCell(sname, NULL);
|
||||
if (!def) def = calmaFindCell(sname, NULL, NULL);
|
||||
|
||||
if (DBIsAncestor(def, cifReadCellDef))
|
||||
{
|
||||
|
|
@ -917,8 +951,7 @@ calmaElementSref(filename)
|
|||
|
||||
for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++)
|
||||
{
|
||||
if ((def->cd_client != (ClientData)CLIENTDEFAULT) &&
|
||||
(gdsplanes[pNum] != NULL))
|
||||
if ((def->cd_client != (ClientData)0) && (gdsplanes[pNum] != NULL))
|
||||
{
|
||||
gdsCopyRec.plane = cifCurReadPlanes[pNum];
|
||||
if (isArray)
|
||||
|
|
@ -1032,13 +1065,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;
|
||||
|
|
@ -1060,6 +1096,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,8 +98,8 @@ calmaInputRescale(n, d)
|
|||
{
|
||||
/* Scale the GDS planes in this cell's cd_client record */
|
||||
Plane **gdsplanes = (Plane **)def->cd_client;
|
||||
/* Should not happen, but punt if client record is not set */
|
||||
if (def->cd_client != (ClientData)CLIENTDEFAULT)
|
||||
/* Should not happen, but punt if client record is not set; */
|
||||
if (def->cd_client != (ClientData)0)
|
||||
CIFScalePlanes(n, d, gdsplanes);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,11 @@ bool CalmaFlattenUses = FALSE; /* If TRUE, small cells in the input
|
|||
* performance when handling contacts
|
||||
* saved as subcell arrays.
|
||||
*/
|
||||
char **CalmaFlattenUsesByName = NULL; /* NULL-terminated list of strings
|
||||
* to do glob-style pattern matching
|
||||
* to determine what cells to flatten
|
||||
* by cellname.
|
||||
*/
|
||||
bool CalmaReadOnly = FALSE; /* Set files to read-only and
|
||||
* retain file position information
|
||||
* so cells can be written verbatim.
|
||||
|
|
@ -77,7 +82,13 @@ 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();
|
||||
|
||||
bool calmaParseUnits();
|
||||
|
||||
|
|
@ -172,6 +183,12 @@ CalmaReadFile(file, filename)
|
|||
CalmaPolygonCount = 0;
|
||||
CalmaPathCount = 0;
|
||||
|
||||
/* 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);
|
||||
|
||||
HashInit(&calmaDefInitHash, 32, 0);
|
||||
calmaLApresent = FALSE;
|
||||
calmaInputFile = file;
|
||||
|
|
@ -368,7 +385,7 @@ CalmaReadError(format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
|
|||
{
|
||||
fprintf(calmaErrorFile, "Error while reading cell \"%s\" ",
|
||||
cifReadCellDef->cd_name);
|
||||
fprintf(calmaErrorFile, "(byte position %"DLONG_PREFIX"ld): ",
|
||||
fprintf(calmaErrorFile, "(byte position %"DLONG_PREFIX"d): ",
|
||||
(dlong)filepos);
|
||||
fprintf(calmaErrorFile, format, a1, a2, a3, a4, a5, a6, a7,
|
||||
a8, a9, a10);
|
||||
|
|
|
|||
|
|
@ -53,11 +53,13 @@ static char rcsid[] __attribute__ ((unused)) ="$Header: /usr/cvsroot/magic-8.0/c
|
|||
#include "utils/stack.h"
|
||||
|
||||
/* Exports */
|
||||
bool CalmaDoLibrary = FALSE; /* If TRUE, do not output the top level */
|
||||
bool CalmaDoLabels = TRUE; /* If FALSE, don't output labels with GDS-II */
|
||||
bool CalmaDoLower = TRUE; /* If TRUE, allow lowercase labels. */
|
||||
bool CalmaFlattenArrays = FALSE; /* If TRUE, output arrays as individual uses */
|
||||
bool CalmaAddendum = FALSE; /* If TRUE, do not output readonly cell defs */
|
||||
bool CalmaDoLibrary = FALSE; /* If TRUE, do not output the top level */
|
||||
bool CalmaDoLabels = TRUE; /* If FALSE, don't output labels with GDS-II */
|
||||
bool CalmaDoLower = TRUE; /* If TRUE, allow lowercase labels. */
|
||||
bool CalmaFlattenArrays = FALSE; /* If TRUE, output arrays as individual uses */
|
||||
bool CalmaAddendum = FALSE; /* If TRUE, do not output readonly cell defs */
|
||||
bool CalmaNoDateStamp = FALSE; /* If TRUE, output zero for creation date stamp */
|
||||
bool CalmaAllowUndefined = FALSE; /* If TRUE, allow calls to undefined cells */
|
||||
|
||||
/* Experimental stuff---not thoroughly tested (as of Sept. 2007)! */
|
||||
bool CalmaContactArrays = FALSE; /* If TRUE, output contacts as subcell arrays */
|
||||
|
|
@ -304,7 +306,12 @@ CalmaWrite(rootDef, f)
|
|||
*/
|
||||
|
||||
dummy.cu_def = rootDef;
|
||||
DBCellReadArea(&dummy, &rootDef->cd_bbox);
|
||||
if (DBCellReadArea(&dummy, &rootDef->cd_bbox, !CalmaAllowUndefined))
|
||||
{
|
||||
TxError("Failure to read entire subtree of the cell.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DBFixMismatch();
|
||||
|
||||
/*
|
||||
|
|
@ -396,7 +403,10 @@ calmaDumpStructure(def, outf, calmaDefHash, filename)
|
|||
|
||||
/* Output structure begin */
|
||||
calmaOutRH(28, CALMA_BGNSTR, CALMA_I2, outf);
|
||||
calmaOutDate(def->cd_timestamp, outf);
|
||||
if (CalmaNoDateStamp)
|
||||
calmaOutDate(time((time_t *) 0), outf);
|
||||
else
|
||||
calmaOutDate(def->cd_timestamp, outf);
|
||||
calmaOutDate(time((time_t *) 0), outf);
|
||||
|
||||
/* Find the structure's unique prefix, in case structure calls subcells */
|
||||
|
|
@ -799,15 +809,19 @@ calmaProcessDef(def, outf, do_library)
|
|||
|
||||
if (isReadOnly && hasContent && CalmaAddendum) return (0);
|
||||
|
||||
/* Give some feedback to the user */
|
||||
TxPrintf(" Writing cell %s\n", def->cd_name);
|
||||
|
||||
/*
|
||||
* Output the definitions for any of our descendants that have
|
||||
* not already been output. Numbers are assigned to the subcells
|
||||
* as they are output.
|
||||
* as they are output. If the cell will get a "full dump" (by
|
||||
* having GDS_START but no GDS_END), then do not output any subcells,
|
||||
* as they are expected to be in the referenced GDS file.
|
||||
*/
|
||||
(void) DBCellEnum(def, calmaProcessUse, (ClientData) outf);
|
||||
if (!hasContent || hasGDSEnd)
|
||||
if (DBCellEnum(def, calmaProcessUse, (ClientData) outf) != 0)
|
||||
return 1;
|
||||
|
||||
/* Give some feedback to the user */
|
||||
TxPrintf(" Generating output for cell %s\n", def->cd_name);
|
||||
|
||||
if (isReadOnly && hasContent)
|
||||
{
|
||||
|
|
@ -826,14 +840,22 @@ calmaProcessDef(def, outf, do_library)
|
|||
/* This is a rare error, but if the subcell is inside */
|
||||
/* another vendor GDS, it would not normally be output. */
|
||||
|
||||
DBPropGet(def->cd_parents->cu_parent, "GDS_FILE", &isReadOnly);
|
||||
if (!isReadOnly || isAbstract)
|
||||
TxError("Calma output error: Can't find GDS file \"%s\" "
|
||||
"for vendor cell \"%s\". Using magic's "
|
||||
"internal definition\n", filename,
|
||||
def->cd_name);
|
||||
DBPropGet((def->cd_parents->cu_parent == NULL) ? def :
|
||||
def->cd_parents->cu_parent, "GDS_FILE", &isReadOnly);
|
||||
if (isReadOnly)
|
||||
{
|
||||
def->cd_flags |= CDVENDORGDS;
|
||||
return 0; /* Ignore without raising an error */
|
||||
}
|
||||
|
||||
TxError("Calma output error: Can't find GDS file \"%s\" "
|
||||
"for vendor cell \"%s\". It will not be output.\n",
|
||||
filename, def->cd_name);
|
||||
|
||||
if (CalmaAllowUndefined)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
else if (isAbstract || (!hasGDSEnd))
|
||||
{
|
||||
|
|
@ -867,7 +889,10 @@ calmaProcessDef(def, outf, do_library)
|
|||
|
||||
/* Output structure header */
|
||||
calmaOutRH(28, CALMA_BGNSTR, CALMA_I2, outf);
|
||||
calmaOutDate(def->cd_timestamp, outf);
|
||||
if (CalmaNoDateStamp)
|
||||
calmaOutDate(time((time_t *) 0), outf);
|
||||
else
|
||||
calmaOutDate(def->cd_timestamp, outf);
|
||||
calmaOutDate(time((time_t *) 0), outf);
|
||||
|
||||
/* Name structure the same as the magic cellname */
|
||||
|
|
@ -922,7 +947,7 @@ calmaProcessDef(def, outf, do_library)
|
|||
if (!do_library)
|
||||
calmaOutFunc(def, outf, &TiPlaneRect);
|
||||
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -964,7 +989,10 @@ calmaOutFunc(def, f, cliprect)
|
|||
|
||||
/* Output structure begin */
|
||||
calmaOutRH(28, CALMA_BGNSTR, CALMA_I2, f);
|
||||
calmaOutDate(def->cd_timestamp, f);
|
||||
if (CalmaNoDateStamp)
|
||||
calmaOutDate(time((time_t *) 0), f);
|
||||
else
|
||||
calmaOutDate(def->cd_timestamp, f);
|
||||
calmaOutDate(time((time_t *) 0), f);
|
||||
|
||||
/* Output structure name */
|
||||
|
|
@ -2693,7 +2721,10 @@ calmaOutHeader(rootDef, f)
|
|||
|
||||
/* Beginning of library */
|
||||
calmaOutRH(28, CALMA_BGNLIB, CALMA_I2, f);
|
||||
calmaOutDate(rootDef->cd_timestamp, f);
|
||||
if (CalmaNoDateStamp)
|
||||
calmaOutDate(time((time_t *) 0), f);
|
||||
else
|
||||
calmaOutDate(rootDef->cd_timestamp, f);
|
||||
calmaOutDate(time((time_t *) 0), f);
|
||||
|
||||
/* Library name (name of root cell) */
|
||||
|
|
|
|||
|
|
@ -31,13 +31,17 @@ extern bool CalmaDoLabels;
|
|||
extern bool CalmaDoLibrary;
|
||||
extern bool CalmaDoLower;
|
||||
extern bool CalmaAddendum;
|
||||
extern bool CalmaNoDuplicates;
|
||||
extern bool CalmaNoDateStamp;
|
||||
extern bool CalmaMergeTiles;
|
||||
extern bool CalmaFlattenArrays;
|
||||
extern bool CalmaNoDRCCheck;
|
||||
extern bool CalmaFlattenUses;
|
||||
extern char **CalmaFlattenUsesByName;
|
||||
extern bool CalmaReadOnly;
|
||||
extern bool CalmaContactArrays;
|
||||
extern bool CalmaPostOrder;
|
||||
extern bool CalmaAllowUndefined;
|
||||
|
||||
/* Externally-visible procedures: */
|
||||
extern bool CalmaWrite();
|
||||
|
|
|
|||
865
cif/CIFgen.c
865
cif/CIFgen.c
File diff suppressed because it is too large
Load Diff
258
cif/CIFhier.c
258
cif/CIFhier.c
|
|
@ -26,6 +26,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#endif /* not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
|
|
@ -201,6 +202,193 @@ cifHierCleanup()
|
|||
SigEnableInterrupts();
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifMaskHints --
|
||||
*
|
||||
* Copy a mask hint into a target cell by adding it to the
|
||||
* property list of the target cell. If the target cell already
|
||||
* has the same mask hint key, then the mask hint value is
|
||||
* appended to the property in the target cell def.
|
||||
*
|
||||
* Returns:
|
||||
* 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* Modifies properties of the target cell def.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifMaskHints(name, value, targetDef)
|
||||
char *name;
|
||||
char *value;
|
||||
CellDef *targetDef;
|
||||
{
|
||||
char *propvalue, *newval;
|
||||
bool propfound;
|
||||
|
||||
if (!strncmp(name, "MASKHINTS_", 10))
|
||||
{
|
||||
/* Check if name exists already in the flattened cell */
|
||||
propvalue = (char *)DBPropGet(targetDef, name, &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
/* Append value to the property */
|
||||
newval = mallocMagic(strlen(value) + strlen(propvalue) + 2);
|
||||
sprintf(newval, "%s %s", propvalue, value);
|
||||
}
|
||||
else
|
||||
newval = StrDup((char **)NULL, value);
|
||||
|
||||
DBPropPut(targetDef, name, newval);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFCopyMaskHints --
|
||||
*
|
||||
* Callback function to copy mask hints from one cell into another.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* May modify properties in the target cell.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
CIFCopyMaskHints(sourceDef, targetDef)
|
||||
CellDef *sourceDef;
|
||||
CellDef *targetDef;
|
||||
{
|
||||
DBPropEnum(sourceDef, cifMaskHints, targetDef);
|
||||
}
|
||||
|
||||
/* Structure used by cifFlatMaskHints, below */
|
||||
|
||||
typedef struct _maskHintsData
|
||||
{
|
||||
Transform *mh_trans;
|
||||
CellDef *mh_def;
|
||||
} MaskHintsData;
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifFlatMaskHints --
|
||||
*
|
||||
* Copy a mask hint into a flattened cell by transforming it into the
|
||||
* coordinate system of the flattened cell, and adding it to the
|
||||
* property list of the flattened cell.
|
||||
*
|
||||
* Returns:
|
||||
* 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* Modifies properties of the cell def passed in MaskHintsData.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifFlatMaskHints(name, value, mhd)
|
||||
char *name;
|
||||
char *value;
|
||||
MaskHintsData *mhd;
|
||||
{
|
||||
Rect r, newr;
|
||||
char *vptr, *newval, *lastval, *propvalue;
|
||||
bool propfound;
|
||||
int lastlen;
|
||||
|
||||
if (!strncmp(name, "MASKHINTS_", 10))
|
||||
{
|
||||
newval = (char *)NULL;
|
||||
vptr = value;
|
||||
while (*vptr != '\0')
|
||||
{
|
||||
if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
|
||||
&r.r_xtop, &r.r_ytop) == 4)
|
||||
{
|
||||
/* Transform rectangle to top level coordinates */
|
||||
GeoTransRect(mhd->mh_trans, &r, &newr);
|
||||
lastval = newval;
|
||||
lastlen = (lastval) ? strlen(lastval) : 0;
|
||||
newval = mallocMagic(40 + lastlen);
|
||||
if (lastval)
|
||||
strcpy(newval, lastval);
|
||||
else
|
||||
*newval = '\0';
|
||||
sprintf(newval + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
|
||||
newr.r_xbot, newr.r_ybot, newr.r_xtop, newr.r_ytop);
|
||||
if (lastval) freeMagic(lastval);
|
||||
|
||||
/* Parse through the four values and check if there's more */
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if name exists already in the flattened cell */
|
||||
propvalue = (char *)DBPropGet(mhd->mh_def, name, &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
/* Append newval to the property */
|
||||
lastval = newval;
|
||||
newval = mallocMagic(strlen(lastval) + strlen(propvalue) + 2);
|
||||
sprintf(newval, "%s %s", propvalue, lastval);
|
||||
freeMagic(lastval);
|
||||
}
|
||||
DBPropPut(mhd->mh_def, name, newval);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifHierCopyMaskHints --
|
||||
*
|
||||
* Callback function to copy mask hints from a subcell into a flattened
|
||||
* cell, which is passed in the clientData record.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0 to keep the search alive.
|
||||
*
|
||||
* Side effects:
|
||||
* May modify properties in the flattened cell.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifHierCopyMaskHints(scx, clientData)
|
||||
SearchContext *scx;
|
||||
ClientData clientData;
|
||||
{
|
||||
MaskHintsData mhd;
|
||||
|
||||
mhd.mh_trans = &scx->scx_trans;
|
||||
mhd.mh_def = (CellDef *)clientData;
|
||||
|
||||
DBPropEnum(scx->scx_use->cu_def, cifFlatMaskHints, &mhd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -245,9 +433,8 @@ cifHierCopyFunc(tile, cxp)
|
|||
if (cxp->tc_scx->scx_use->cu_def->cd_flags & CDVENDORGDS)
|
||||
{
|
||||
if (!CIFCurStyle)
|
||||
return 0;
|
||||
else if (!(CIFCurStyle->cs_flags & CWF_SEE_VENDOR))
|
||||
return 0;
|
||||
if (!(CIFCurStyle->cs_flags & CWF_SEE_NO_VENDOR))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ignore space tiles, since they won't do anything anyway. */
|
||||
|
|
@ -320,6 +507,11 @@ cifHierCellFunc(scx)
|
|||
(void) DBTreeSrTiles(&newscx, &CIFCurStyle->cs_yankLayers, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
|
||||
/* Flatten mask hints in the area of interest */
|
||||
CIFCopyMaskHints(scx->scx_use->cu_def, CIFComponentDef);
|
||||
DBTreeSrCells(&newscx, 0, cifHierCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
/* Set CIFErrorDef to NULL to ignore errors here... these will
|
||||
* get reported anyway when the cell is CIF'ed non-hierarchically,
|
||||
* so there's no point in making a second report here.
|
||||
|
|
@ -421,6 +613,44 @@ cifHierCheckFunc(tile, plane)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifHierTempCheckFunc --
|
||||
*
|
||||
* This function is like cifHierCheckFunc() (see above), but is used
|
||||
* for "templayers", where any parent/child disagreement should be
|
||||
* considered a non-issue as far as output is concerned. Only the
|
||||
* actual mask layer will report any problems.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0 to keep the search alive.
|
||||
*
|
||||
* Side effects:
|
||||
* Error messages may be output.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifHierTempCheckFunc(tile, plane)
|
||||
Tile *tile; /* Tile containing CIF. */
|
||||
Plane *plane; /* Plane to check against and modify. */
|
||||
{
|
||||
Rect area;
|
||||
|
||||
TiToRect(tile, &area);
|
||||
|
||||
if (IsSplit(tile))
|
||||
DBNMPaintPlane(plane, TiGetTypeExact(tile), &area, CIFEraseTable,
|
||||
(PaintUndoInfo *) NULL);
|
||||
else
|
||||
DBPaintPlane(plane, &area, CIFEraseTable, (PaintUndoInfo *) NULL);
|
||||
|
||||
CIFTileOps++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -490,9 +720,14 @@ cifCheckAndErase(style)
|
|||
{
|
||||
CIFErrorLayer = i;
|
||||
if (CIFComponentPlanes[i] == NULL) continue;
|
||||
(void) DBSrPaintArea((Tile *) NULL, CIFComponentPlanes[i],
|
||||
&TiPlaneRect, &CIFSolidBits, cifHierCheckFunc,
|
||||
(ClientData) CIFTotalPlanes[i]);
|
||||
if (CIFCurStyle->cs_layers[i]->cl_flags & CIF_TEMP)
|
||||
(void) DBSrPaintArea((Tile *) NULL, CIFComponentPlanes[i],
|
||||
&TiPlaneRect, &CIFSolidBits, cifHierTempCheckFunc,
|
||||
(ClientData) CIFTotalPlanes[i]);
|
||||
else
|
||||
(void) DBSrPaintArea((Tile *) NULL, CIFComponentPlanes[i],
|
||||
&TiPlaneRect, &CIFSolidBits, cifHierCheckFunc,
|
||||
(ClientData) CIFTotalPlanes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -595,6 +830,11 @@ CIFGenSubcells(def, area, output)
|
|||
GEO_EXPAND(&interaction, CIFCurStyle->cs_radius, &scx.scx_area);
|
||||
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFTotalDef);
|
||||
/* Flatten mask hints in the area of interest */
|
||||
CIFCopyMaskHints(def, CIFTotalDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
(ClientData)CIFTotalDef);
|
||||
|
||||
CIFErrorDef = def;
|
||||
CIFGen(CIFTotalDef, def, &interaction, CIFTotalPlanes,
|
||||
&CIFCurStyle->cs_hierLayers, TRUE, TRUE, TRUE,
|
||||
|
|
@ -720,10 +960,16 @@ cifHierElementFunc(use, transform, x, y, checkArea)
|
|||
scx.scx_use = use;
|
||||
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFTotalDef);
|
||||
CIFCopyMaskHints(use->cu_def, CIFTotalDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
(ClientData)CIFTotalDef);
|
||||
|
||||
DBCellClearDef(CIFComponentDef);
|
||||
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
CIFCopyMaskHints(use->cu_def, CIFComponentDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
CIFErrorDef = (CellDef *) NULL;
|
||||
CIFGen(CIFComponentDef, use->cu_def, checkArea, CIFComponentPlanes,
|
||||
|
|
|
|||
11
cif/CIFint.h
11
cif/CIFint.h
|
|
@ -142,6 +142,7 @@ typedef struct cifop
|
|||
* CIFOP_CLOSE - Added 11/25/19---close up areas smaller than indicated
|
||||
* CIFOP_BRIDGE - Added 6/11/20---Bridge across catecorner gaps
|
||||
* CIFOP_BRIDGELIM - Added 27/07/20---Bridge across catecorner gaps, but with limiting layers
|
||||
* CIFOP_MASKHINTS - Added 12/14/20---Add geometry from cell properties, if any.
|
||||
*/
|
||||
|
||||
#define CIFOP_AND 1
|
||||
|
|
@ -166,6 +167,7 @@ typedef struct cifop
|
|||
#define CIFOP_CLOSE 20
|
||||
#define CIFOP_BRIDGE 21
|
||||
#define CIFOP_BRIDGELIM 22
|
||||
#define CIFOP_MASKHINTS 23
|
||||
|
||||
|
||||
/* Added by Tim 10/21/2004 */
|
||||
|
|
@ -224,12 +226,9 @@ typedef struct
|
|||
*
|
||||
* CIF_TEMP: Means that this is a temporary layer used to build
|
||||
* up CIF information. It isn't output in the CIF file.
|
||||
* CIF_BBOX_TOP: Indicates that the bounding box rectangle should
|
||||
* only be generated if the cell is a top-level cell.
|
||||
*/
|
||||
|
||||
#define CIF_TEMP 1
|
||||
#define CIF_BBOX_TOP 2
|
||||
|
||||
/* The following data structure describes a complete set of CIF
|
||||
* layers. The number of CIF layers (MAXCIFLAYERS) must not be
|
||||
|
|
@ -307,8 +306,8 @@ typedef struct cifstyle
|
|||
#define CWF_GROW_SLIVERS 0x02
|
||||
#define CWF_ANGSTROMS 0x04
|
||||
#define CWF_GROW_EUCLIDEAN 0x08
|
||||
#define CWF_SEE_VENDOR 0x10 /* Override vendor GDS flag in cells */
|
||||
#define CWF_NO_ERRORS 0x20 /* Do not generate error msgs and fdbk */
|
||||
#define CWF_SEE_NO_VENDOR 0x10 /* Hide magic's GDS from vendor cells */
|
||||
#define CWF_NO_ERRORS 0x20 /* Do not generate error msgs and fdbk */
|
||||
#define CWF_STRING_LIMIT 0x40 /* Use older Calma format character limit */
|
||||
|
||||
/* procedures */
|
||||
|
|
@ -321,7 +320,9 @@ extern void CIFClearPlanes();
|
|||
extern Plane *CIFGenLayer();
|
||||
extern void CIFInitCells();
|
||||
extern int cifHierCopyFunc();
|
||||
extern int cifHierCopyMaskHints();
|
||||
extern void CIFLoadStyle();
|
||||
extern void CIFCopyMaskHints();
|
||||
|
||||
/* Shared variables and structures: */
|
||||
|
||||
|
|
|
|||
|
|
@ -259,7 +259,8 @@ CIFSetStyle(name)
|
|||
* print out the valid styles.
|
||||
*/
|
||||
{
|
||||
CIFKeep *style, *match;
|
||||
CIFKeep *style, *match, *exactmatch;
|
||||
bool ambiguous = FALSE;
|
||||
int length;
|
||||
|
||||
if (name == NULL) return;
|
||||
|
|
@ -269,18 +270,25 @@ CIFSetStyle(name)
|
|||
|
||||
for (style = CIFStyleList; style != NULL; style = style->cs_next)
|
||||
{
|
||||
if (strncmp(name, style->cs_name, length) == 0)
|
||||
if (!strcmp(name, style->cs_name)) {
|
||||
match = style;
|
||||
ambiguous = FALSE;
|
||||
break;
|
||||
}
|
||||
else if (!strncmp(name, style->cs_name, length))
|
||||
{
|
||||
if (match != NULL)
|
||||
{
|
||||
TxError("CIF output style \"%s\" is ambiguous.\n", name);
|
||||
CIFPrintStyle(FALSE, TRUE, TRUE);
|
||||
return;
|
||||
}
|
||||
if (match != NULL) ambiguous = TRUE;
|
||||
match = style;
|
||||
}
|
||||
}
|
||||
|
||||
if (ambiguous)
|
||||
{
|
||||
TxError("CIF output style \"%s\" is ambiguous.\n", name);
|
||||
CIFPrintStyle(FALSE, TRUE, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (match != NULL)
|
||||
{
|
||||
CIFLoadStyle(match->cs_name);
|
||||
|
|
|
|||
|
|
@ -386,8 +386,10 @@ CIFInputRescale(n, d)
|
|||
}
|
||||
}
|
||||
|
||||
CIFScalePlanes(n, d, cifEditCellPlanes);
|
||||
if (cifEditCellPlanes != cifSubcellPlanes)
|
||||
CIFScalePlanes(n, d, cifCurReadPlanes);
|
||||
if (cifCurReadPlanes != cifEditCellPlanes)
|
||||
CIFScalePlanes(n, d, cifEditCellPlanes);
|
||||
if (cifEditCellPlanes != cifSubcellPlanes && cifCurReadPlanes != cifSubcellPlanes)
|
||||
CIFScalePlanes(n, d, cifSubcellPlanes);
|
||||
|
||||
CIFReadWarning("CIF style %s: units rescaled by factor of %d / %d\n",
|
||||
|
|
@ -603,13 +605,13 @@ CIFPaintCurrent(filetype)
|
|||
Plane **parray;
|
||||
extern char *(cifReadLayers[MAXCIFRLAYERS]);
|
||||
|
||||
/* NOTE: There should be no need to check for cd_client
|
||||
* here as cd_client should not be CLIENTDEFAULT if CDFLATGDS
|
||||
* is set in flags. This condition has occurred, though, and
|
||||
* needs to be debugged.
|
||||
/* NOTE: The condition cd_client == 0 when CDFLATGDS
|
||||
* indicates that the cell was already in memory when the
|
||||
* GDS was read. This condition should be properly caught
|
||||
* and handled.
|
||||
*/
|
||||
if ((cifReadCellDef->cd_flags & CDFLATGDS) &&
|
||||
(cifReadCellDef->cd_client != (ClientData)CLIENTDEFAULT))
|
||||
(cifReadCellDef->cd_client != (ClientData)0))
|
||||
parray = (Plane **)cifReadCellDef->cd_client;
|
||||
else
|
||||
{
|
||||
|
|
@ -1499,7 +1501,7 @@ CIFReadCellCleanup(filetype)
|
|||
UndoDisable();
|
||||
|
||||
/* cifplanes should be valid, but don't crash magic if not */
|
||||
if (cifplanes != (Plane **)CLIENTDEFAULT)
|
||||
if (cifplanes != (Plane **)0)
|
||||
{
|
||||
|
||||
for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++)
|
||||
|
|
@ -1512,7 +1514,7 @@ CIFReadCellCleanup(filetype)
|
|||
}
|
||||
freeMagic((char *)def->cd_client);
|
||||
}
|
||||
def->cd_client = (ClientData)CLIENTDEFAULT;
|
||||
def->cd_client = (ClientData)0;
|
||||
|
||||
#if 0
|
||||
/* If the CDFLATTENED flag was not set, then this geometry */
|
||||
|
|
|
|||
38
cif/CIFsee.c
38
cif/CIFsee.c
|
|
@ -21,6 +21,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#endif /* not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "tiles/tile.h"
|
||||
|
|
@ -162,6 +163,10 @@ CIFPaintLayer(rootDef, area, cifLayer, magicLayer, paintDef)
|
|||
scx.scx_trans = GeoIdentityTransform;
|
||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
CIFCopyMaskHints(rootDef, CIFComponentDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
oldCount = DBWFeedbackCount;
|
||||
|
||||
CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE, FALSE,
|
||||
|
|
@ -278,6 +283,10 @@ CIFSeeLayer(rootDef, area, layer)
|
|||
scx.scx_trans = GeoIdentityTransform;
|
||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
CIFCopyMaskHints(rootDef, CIFComponentDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
oldCount = DBWFeedbackCount;
|
||||
CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE,
|
||||
FALSE, (ClientData)NULL);
|
||||
|
|
@ -414,10 +423,11 @@ typedef struct {
|
|||
} coverstats;
|
||||
|
||||
void
|
||||
CIFCoverageLayer(rootDef, area, layer)
|
||||
CIFCoverageLayer(rootDef, area, layer, dolist)
|
||||
CellDef *rootDef; /* Def in which to compute CIF coverage */
|
||||
Rect *area; /* Area in which to compute coverage */
|
||||
char *layer; /* CIF layer for coverage computation. */
|
||||
bool dolist; /* If TRUE, report only the value, in decimal */
|
||||
{
|
||||
coverstats cstats;
|
||||
int i, scale;
|
||||
|
|
@ -443,6 +453,10 @@ CIFCoverageLayer(rootDef, area, layer)
|
|||
scx.scx_trans = GeoIdentityTransform;
|
||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
CIFCopyMaskHints(rootDef, CIFComponentDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE,
|
||||
FALSE, (ClientData)NULL);
|
||||
DBCellClearDef(CIFComponentDef);
|
||||
|
|
@ -470,12 +484,26 @@ CIFCoverageLayer(rootDef, area, layer)
|
|||
atotal = (long long)(cstats.bounds.r_xtop - cstats.bounds.r_xbot);
|
||||
atotal *= (long long)(cstats.bounds.r_ytop - cstats.bounds.r_ybot);
|
||||
|
||||
TxPrintf("%s Area = %lld CIF units^2\n", doBox ? "Cursor Box" :
|
||||
if (dolist)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_Obj *pobj;
|
||||
|
||||
pobj = Tcl_NewDoubleObj((double)fcover);
|
||||
Tcl_SetObjResult(magicinterp, pobj);
|
||||
#else
|
||||
TxPrintf("%g\n", fcover);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
TxPrintf("%s Area = %lld CIF units^2\n", doBox ? "Cursor Box" :
|
||||
"Cell", btotal);
|
||||
TxPrintf("Layer Bounding Area = %lld CIF units^2\n", atotal);
|
||||
TxPrintf("Layer Total Area = %lld CIF units^2\n", cstats.coverage);
|
||||
TxPrintf("Coverage in %s = %1.1f%%\n", doBox ? "box" :
|
||||
TxPrintf("Layer Bounding Area = %lld CIF units^2\n", atotal);
|
||||
TxPrintf("Layer Total Area = %lld CIF units^2\n", cstats.coverage);
|
||||
TxPrintf("Coverage in %s = %1.1f%%\n", doBox ? "box" :
|
||||
"cell", 100.0 * fcover);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -991,8 +991,8 @@ CIFTechLine(sectionName, argc, argv)
|
|||
CIFCurStyle->cs_flags |= CWF_PERMISSIVE_LABELS;
|
||||
else if (strcmp(argv[i], "grow-euclidean") == 0)
|
||||
CIFCurStyle->cs_flags |= CWF_GROW_EUCLIDEAN;
|
||||
else if (strcmp(argv[i], "see-vendor") == 0)
|
||||
CIFCurStyle->cs_flags |= CWF_SEE_VENDOR;
|
||||
else if (strcmp(argv[i], "see-no-vendor") == 0)
|
||||
CIFCurStyle->cs_flags |= CWF_SEE_NO_VENDOR;
|
||||
else if (strcmp(argv[i], "no-errors") == 0)
|
||||
CIFCurStyle->cs_flags |= CWF_NO_ERRORS;
|
||||
else if (strcmp(argv[i], "string-limit") == 0)
|
||||
|
|
@ -1054,6 +1054,8 @@ CIFTechLine(sectionName, argc, argv)
|
|||
newOp->co_opcode = CIFOP_MAXRECT;
|
||||
else if (strcmp(argv[0], "boundary") == 0)
|
||||
newOp->co_opcode = CIFOP_BOUNDARY;
|
||||
else if (strcmp(argv[0], "mask-hints") == 0)
|
||||
newOp->co_opcode = CIFOP_MASKHINTS;
|
||||
else if (strcmp(argv[0], "close") == 0)
|
||||
newOp->co_opcode = CIFOP_CLOSE;
|
||||
else if (strcmp(argv[0], "bridge") == 0)
|
||||
|
|
@ -1247,6 +1249,11 @@ bloatCheck:
|
|||
&newOp->co_cifMask, FALSE);
|
||||
break;
|
||||
|
||||
case CIFOP_MASKHINTS:
|
||||
if (argc != 2) goto wrongNumArgs;
|
||||
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
|
||||
break;
|
||||
|
||||
case CIFOP_MAXRECT:
|
||||
if (argc == 2)
|
||||
{
|
||||
|
|
@ -1537,10 +1544,12 @@ cifComputeRadii(layer, des)
|
|||
|
||||
for (op = layer->cl_ops; op != NULL; op = op->co_next)
|
||||
{
|
||||
/* BBOX and NET operators should never be used hierarchically */
|
||||
/* so ignore any grow/shrink operators that come after them. */
|
||||
/* BBOX, NET, and MASKHINTS operators should never be used */
|
||||
/* hierarchically so ignore any grow/shrink operators that */
|
||||
/* come after them. */
|
||||
|
||||
if (op->co_opcode == CIFOP_BBOX || op->co_opcode == CIFOP_NET)
|
||||
if (op->co_opcode == CIFOP_BBOX || op->co_opcode == CIFOP_NET ||
|
||||
op->co_opcode == CIFOP_MASKHINTS)
|
||||
break;
|
||||
|
||||
/* If CIF layers are used, switch to the max of current
|
||||
|
|
@ -1565,11 +1574,11 @@ cifComputeRadii(layer, des)
|
|||
|
||||
switch (op->co_opcode)
|
||||
{
|
||||
case CIFOP_AND: break;
|
||||
|
||||
case CIFOP_ANDNOT: break;
|
||||
|
||||
case CIFOP_OR: break;
|
||||
case CIFOP_AND:
|
||||
case CIFOP_ANDNOT:
|
||||
case CIFOP_OR:
|
||||
case CIFOP_MASKHINTS:
|
||||
break;
|
||||
|
||||
case CIFOP_GROW:
|
||||
case CIFOP_GROWMIN:
|
||||
|
|
@ -1850,13 +1859,15 @@ CIFTechFinal()
|
|||
/* Presence of op->co_opcode in CIFOP_OR indicates a copy */
|
||||
/* of the SquaresData pointer from a following operator */
|
||||
/* CIFOP_BBOX and CIFOP_MAXRECT uses the co_client field */
|
||||
/* as a flag field, while CIFOP_NET uses it for a string. */
|
||||
/* as a flag field, while CIFOP_NET and CIFOP_MASKHINTS */
|
||||
/* uses it for a string. */
|
||||
else
|
||||
{
|
||||
switch (op->co_opcode)
|
||||
{
|
||||
case CIFOP_OR:
|
||||
case CIFOP_BBOX:
|
||||
case CIFOP_MASKHINTS:
|
||||
case CIFOP_BOUNDARY:
|
||||
case CIFOP_MAXRECT:
|
||||
case CIFOP_NET:
|
||||
|
|
@ -2388,6 +2399,7 @@ CIFTechOutputScale(n, d)
|
|||
case CIFOP_OR:
|
||||
case CIFOP_BBOX:
|
||||
case CIFOP_BOUNDARY:
|
||||
case CIFOP_MASKHINTS:
|
||||
case CIFOP_MAXRECT:
|
||||
case CIFOP_NET:
|
||||
break;
|
||||
|
|
@ -2425,7 +2437,7 @@ CIFTechOutputScale(n, d)
|
|||
/* Reduce the scale and all distances by the greatest common */
|
||||
/* factor of everything. */
|
||||
|
||||
/* fprintf(stderr, "All CIF units divisible by %d\n", lexpand); */
|
||||
/* fprintf(stderr, "All CIF units divisible by %d\n", lexpand); */
|
||||
/* fflush(stderr); */
|
||||
|
||||
lgcf = FindGCF(ostyle->cs_scaleFactor, ostyle->cs_expander);
|
||||
|
|
@ -2502,9 +2514,10 @@ CIFTechOutputScale(n, d)
|
|||
bridge->br_width /= lexpand;
|
||||
break;
|
||||
default:
|
||||
/* op->co_opcode in CIFOP_OR is a pointer copy */
|
||||
/* and in CIFOP_BBOX and CIFOP_MAXRECT is a */
|
||||
/* flag, and in CIFOP_NET is a string. */
|
||||
/* op->co_opcode in CIFOP_OR is a pointer copy, */
|
||||
/* in CIFOP_BBOX and CIFOP_MAXRECT is a flag, */
|
||||
/* and in CIFOP_NET and CIFOP_MASKHINTS is a */
|
||||
/* string. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,14 +132,18 @@ CIFWrite(rootDef, f)
|
|||
*/
|
||||
|
||||
dummy.cu_def = rootDef;
|
||||
DBCellReadArea(&dummy, &rootDef->cd_bbox);
|
||||
if (DBCellReadArea(&dummy, &rootDef->cd_bbox, TRUE))
|
||||
{
|
||||
TxError("Failure to read in entire subtree of the cell.\n");
|
||||
return (FALSE);
|
||||
}
|
||||
DBFixMismatch();
|
||||
|
||||
if (CIFCurStyle->cs_reducer == 0)
|
||||
{
|
||||
TxError("The current CIF output style can only be used for writing\n");
|
||||
TxError("Calma output. Try picking another output style.\n");
|
||||
return (TRUE);
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
303
commands/CmdCD.c
303
commands/CmdCD.c
|
|
@ -94,18 +94,22 @@ bool cmdDumpParseArgs();
|
|||
#define CALMA_CONTACTS 3
|
||||
#define CALMA_DRCCHECK 4
|
||||
#define CALMA_FLATTEN 5
|
||||
#define CALMA_ORDERING 6
|
||||
#define CALMA_LABELS 7
|
||||
#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_FLATGLOB 6
|
||||
#define CALMA_ORDERING 7
|
||||
#define CALMA_LABELS 8
|
||||
#define CALMA_LIBRARY 9
|
||||
#define CALMA_LOWER 10
|
||||
#define CALMA_MERGE 11
|
||||
#define CALMA_NO_STAMP 12
|
||||
#define CALMA_NO_DUP 13
|
||||
#define CALMA_READ 14
|
||||
#define CALMA_READONLY 15
|
||||
#define CALMA_RESCALE 16
|
||||
#define CALMA_WARNING 17
|
||||
#define CALMA_WRITE 18
|
||||
#define CALMA_POLYS 19
|
||||
#define CALMA_PATHS 20
|
||||
#define CALMA_UNDEFINED 21
|
||||
|
||||
#define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */
|
||||
|
||||
|
|
@ -122,7 +126,9 @@ CmdCalma(w, cmd)
|
|||
extern int CalmaFlattenLimit;
|
||||
|
||||
static char *gdsExts[] = {".gds", ".gds2", ".strm", "", NULL};
|
||||
static char *cmdCalmaYesNo[] = { "no", "false", "off", "yes", "true", "on", 0 };
|
||||
static char *cmdCalmaYesNo[] = {
|
||||
"no", "false", "off", "0", "yes", "true", "on", "1", 0 };
|
||||
static char *cmdCalmaAllowDisallow[] = {"disallow", "0", "allow", "1", 0};
|
||||
static char *cmdCalmaWarnOptions[] = { "default", "none", "align",
|
||||
"limit", "redirect", "help", 0 };
|
||||
static char *cmdCalmaOption[] =
|
||||
|
|
@ -133,11 +139,14 @@ CmdCalma(w, cmd)
|
|||
"contacts [yes|no] optimize output by arraying contacts as subcells",
|
||||
"drccheck [yes|no] mark all cells as needing DRC checking",
|
||||
"flatten [yes|no|limit] flatten simple cells (e.g., contacts) on input",
|
||||
"flatglob [<name>|none] flatten cells by name with glob patterning",
|
||||
"ordering [on|off] cause cells to be read in post-order",
|
||||
"labels [yes|no] cause labels to be output when writing GDS-II",
|
||||
"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",
|
||||
"nodatestamp [yes|no] write a zero value creation date stamp",
|
||||
"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",
|
||||
|
|
@ -149,6 +158,8 @@ CmdCalma(w, cmd)
|
|||
" put non-Manhattan polygons into subcells",
|
||||
"path subcells [yes|no]\n"
|
||||
" put wire paths into individual subcells",
|
||||
"undefined [allow|disallow]\n"
|
||||
" [dis]allow writing of GDS with calls to undefined cells",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -220,15 +231,16 @@ CmdCalma(w, cmd)
|
|||
else if (cmd->tx_argc != 3)
|
||||
{
|
||||
wrongNumArgs:
|
||||
TxError("Wrong number of arguments in \"gds\" command.");
|
||||
TxError(" Try \":gds help\" for help.\n");
|
||||
TxError("Wrong number of arguments in \"%s\" command.",
|
||||
cmd->tx_argv[0]);
|
||||
TxError(" Try \":%s help\" for help.\n", cmd->tx_argv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaDoLabels = (option < 3) ? FALSE : TRUE;
|
||||
CalmaDoLabels = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_LIBRARY:
|
||||
|
|
@ -248,7 +260,7 @@ CmdCalma(w, cmd)
|
|||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaDoLibrary = (option < 3) ? FALSE : TRUE;
|
||||
CalmaDoLibrary = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_ADDENDUM:
|
||||
|
|
@ -268,7 +280,27 @@ CmdCalma(w, cmd)
|
|||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaAddendum = (option < 3) ? FALSE : TRUE;
|
||||
CalmaAddendum = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_UNDEFINED:
|
||||
if (cmd->tx_argc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaAllowUndefined));
|
||||
#else
|
||||
TxPrintf("Writing of GDS file with undefined cells is %sallowed.\n",
|
||||
(CalmaAllowUndefined) ? "" : "dis");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
else if (cmd->tx_argc != 3)
|
||||
goto wrongNumArgs;
|
||||
|
||||
option = Lookup(cmd->tx_argv[2], cmdCalmaAllowDisallow);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaAllowUndefined = (option < 2) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_CONTACTS:
|
||||
|
|
@ -290,7 +322,7 @@ CmdCalma(w, cmd)
|
|||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaContactArrays = (option < 3) ? FALSE : TRUE;
|
||||
CalmaContactArrays = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_DRCCHECK:
|
||||
|
|
@ -310,7 +342,7 @@ CmdCalma(w, cmd)
|
|||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaNoDRCCheck = (option < 3) ? TRUE : FALSE;
|
||||
CalmaNoDRCCheck = (option < 4) ? TRUE : FALSE;
|
||||
return;
|
||||
|
||||
case CALMA_FLATTEN:
|
||||
|
|
@ -341,7 +373,103 @@ CmdCalma(w, cmd)
|
|||
goto wrongNumArgs;
|
||||
}
|
||||
else
|
||||
CalmaFlattenUses = (option < 3) ? FALSE : TRUE;
|
||||
CalmaFlattenUses = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_FLATGLOB:
|
||||
|
||||
if (cmd->tx_argc == 2)
|
||||
{
|
||||
if (CalmaFlattenUsesByName != NULL)
|
||||
{
|
||||
int i = 0;
|
||||
char *pattern;
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_Obj *lobj = Tcl_NewListObj(0, NULL);
|
||||
while (TRUE)
|
||||
{
|
||||
pattern = CalmaFlattenUsesByName[i];
|
||||
if (pattern == NULL) break;
|
||||
i++;
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewStringObj(pattern, -1));
|
||||
}
|
||||
Tcl_SetObjResult(magicinterp, lobj);
|
||||
#else
|
||||
TxPrintf("Glob patterns for cells to flatten:\n");
|
||||
while (TRUE)
|
||||
{
|
||||
pattern = CalmaFlattenUsesByName[i];
|
||||
if (pattern == NULL) break;
|
||||
i++;
|
||||
TxPrintf(" \"%s\"\n", pattern);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (cmd->tx_argc != 3)
|
||||
goto wrongNumArgs;
|
||||
|
||||
if (!strcasecmp(cmd->tx_argv[2], "none"))
|
||||
{
|
||||
int i = 0;
|
||||
if (CalmaFlattenUsesByName == (char **)NULL) return;
|
||||
while (TRUE)
|
||||
{
|
||||
char *pattern = CalmaFlattenUsesByName[i];
|
||||
if (pattern == NULL) break;
|
||||
freeMagic(pattern);
|
||||
i++;
|
||||
}
|
||||
freeMagic(CalmaFlattenUsesByName);
|
||||
CalmaFlattenUsesByName = (char **)NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
char **newpatterns;
|
||||
char *pattern;
|
||||
int i = 0;
|
||||
|
||||
if (CalmaFlattenUsesByName == (char **)NULL)
|
||||
i = 1;
|
||||
else
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
pattern = CalmaFlattenUsesByName[i++];
|
||||
if (pattern == NULL) break;
|
||||
}
|
||||
}
|
||||
newpatterns = (char **)mallocMagic((i + 1) * sizeof(char *));
|
||||
i = 0;
|
||||
if (CalmaFlattenUsesByName != (char **)NULL)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
pattern = CalmaFlattenUsesByName[i];
|
||||
if (pattern == NULL) break;
|
||||
newpatterns[i] = StrDup((char **)NULL, pattern);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
newpatterns[i++] = StrDup((char **)NULL, cmd->tx_argv[2]);
|
||||
newpatterns[i] = (char *)NULL;
|
||||
|
||||
i = 0;
|
||||
if (CalmaFlattenUsesByName != (char **)NULL)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
pattern = CalmaFlattenUsesByName[i];
|
||||
if (pattern == NULL) break;
|
||||
freeMagic(pattern);
|
||||
i++;
|
||||
}
|
||||
freeMagic(CalmaFlattenUsesByName);
|
||||
}
|
||||
CalmaFlattenUsesByName = newpatterns;
|
||||
}
|
||||
return;
|
||||
|
||||
case CALMA_ORDERING:
|
||||
|
|
@ -364,7 +492,7 @@ CmdCalma(w, cmd)
|
|||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaPostOrder = (option < 3) ? FALSE : TRUE;
|
||||
CalmaPostOrder = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_ARRAYS:
|
||||
|
|
@ -384,7 +512,7 @@ CmdCalma(w, cmd)
|
|||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaFlattenArrays = (option < 3) ? FALSE : TRUE;
|
||||
CalmaFlattenArrays = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_LOWER:
|
||||
|
|
@ -404,7 +532,7 @@ CmdCalma(w, cmd)
|
|||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaDoLower = (option < 3) ? FALSE : TRUE;
|
||||
CalmaDoLower = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_MERGE:
|
||||
|
|
@ -426,7 +554,7 @@ CmdCalma(w, cmd)
|
|||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaMergeTiles = (option < 3) ? FALSE : TRUE;
|
||||
CalmaMergeTiles = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_POLYS:
|
||||
|
|
@ -448,7 +576,47 @@ CmdCalma(w, cmd)
|
|||
option = Lookup(cmd->tx_argv[3], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaSubcellPolygons = (option < 3) ? FALSE : TRUE;
|
||||
CalmaSubcellPolygons = (option < 4) ? 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 < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_NO_STAMP:
|
||||
if (cmd->tx_argc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaNoDateStamp));
|
||||
#else
|
||||
TxPrintf("Structures will contain a %s header creation date stamp.\n",
|
||||
(CalmaNoDateStamp) ? "zero" : "valid");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
else if (cmd->tx_argc != 3)
|
||||
goto wrongNumArgs;
|
||||
|
||||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaNoDateStamp = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_PATHS:
|
||||
|
|
@ -470,7 +638,7 @@ CmdCalma(w, cmd)
|
|||
option = Lookup(cmd->tx_argv[3], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaSubcellPaths = (option < 3) ? FALSE : TRUE;
|
||||
CalmaSubcellPaths = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_READONLY:
|
||||
|
|
@ -490,7 +658,7 @@ CmdCalma(w, cmd)
|
|||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaReadOnly = (option < 3) ? FALSE : TRUE;
|
||||
CalmaReadOnly = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_RESCALE:
|
||||
|
|
@ -510,7 +678,7 @@ CmdCalma(w, cmd)
|
|||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CIFRescaleAllow = (option < 3) ? FALSE : TRUE;
|
||||
CIFRescaleAllow = (option < 4) ? FALSE : TRUE;
|
||||
if (!CIFRescaleAllow)
|
||||
CIFWarningLevel = CIF_WARN_LIMIT;
|
||||
return;
|
||||
|
|
@ -667,8 +835,10 @@ CmdCellname(w, cmd)
|
|||
"window list top-level cell of a layout window",
|
||||
"create create a new cell definition",
|
||||
"delete delete the named cell definition",
|
||||
"dereference reload the named cell from the search paths",
|
||||
"filepath list the full path of the file for the cell",
|
||||
"flags list option flags of the indicated cell definition",
|
||||
"timestamp list the cell timestamp",
|
||||
"lock lock the named cell (prevent changes to cell use)",
|
||||
"unlock unlock the named cell (allow changes to cell use)",
|
||||
"property list or set cell definition properties",
|
||||
|
|
@ -681,10 +851,11 @@ CmdCellname(w, cmd)
|
|||
};
|
||||
typedef enum { IDX_CHILDREN, IDX_PARENTS, IDX_EXISTS, IDX_SELF,
|
||||
IDX_INSTANCE, IDX_CHILDINST, IDX_CELLDEF, IDX_ALLCELLS,
|
||||
IDX_TOPCELLS, IDX_IN_WINDOW, IDX_CREATE,
|
||||
IDX_DELETE, IDX_FILEPATH, IDX_FLAGS, IDX_LOCK, IDX_UNLOCK,
|
||||
IDX_PROPERTY, IDX_ABUTMENT, IDX_ORIENTATION, IDX_RENAME,
|
||||
IDX_READWRITE, IDX_MODIFIED } optionType;
|
||||
IDX_TOPCELLS, IDX_IN_WINDOW, IDX_CREATE, IDX_DELETE,
|
||||
IDX_DEREFERENCE, IDX_FILEPATH, IDX_FLAGS, IDX_TIMESTAMP,
|
||||
IDX_LOCK, IDX_UNLOCK, IDX_PROPERTY, IDX_ABUTMENT,
|
||||
IDX_ORIENTATION, IDX_RENAME, IDX_READWRITE,
|
||||
IDX_MODIFIED } optionType;
|
||||
|
||||
if (strstr(cmd->tx_argv[0], "in"))
|
||||
is_cellname = FALSE;
|
||||
|
|
@ -721,8 +892,9 @@ CmdCellname(w, cmd)
|
|||
if (option < 0) goto badusage;
|
||||
|
||||
if ((locargc > 3) && (option != IDX_RENAME) && (option != IDX_DELETE) &&
|
||||
(option != IDX_READWRITE) && (option != IDX_PROPERTY) &&
|
||||
(option != IDX_FILEPATH) && (option != IDX_ORIENTATION))
|
||||
(option != IDX_DEREFERENCE) && (option != IDX_READWRITE) &&
|
||||
(option != IDX_PROPERTY) && (option != IDX_FILEPATH) &&
|
||||
(option != IDX_ORIENTATION) && (option != IDX_TIMESTAMP))
|
||||
goto badusage;
|
||||
|
||||
if ((locargc > 4) && (option != IDX_PROPERTY))
|
||||
|
|
@ -768,6 +940,7 @@ CmdCellname(w, cmd)
|
|||
return;
|
||||
case IDX_IN_WINDOW: case IDX_READWRITE: case IDX_FLAGS:
|
||||
case IDX_PROPERTY: case IDX_FILEPATH: case IDX_MODIFIED:
|
||||
case IDX_DEREFERENCE: case IDX_TIMESTAMP:
|
||||
TxError("Function unimplemented for instances.\n");
|
||||
return;
|
||||
case IDX_DELETE:
|
||||
|
|
@ -845,6 +1018,30 @@ CmdCellname(w, cmd)
|
|||
TxError("Delete cell command missing cellname\n");
|
||||
break;
|
||||
|
||||
case IDX_DEREFERENCE:
|
||||
/* Unload the cell definition and re-read with search paths */
|
||||
if (locargc == 3)
|
||||
{
|
||||
void cmdFlushCell();
|
||||
|
||||
if (cellname == NULL)
|
||||
cellDef = EditRootDef;
|
||||
else
|
||||
cellDef = DBCellLookDef(cellname);
|
||||
|
||||
/* Reload cell with dereferencing */
|
||||
if (cellDef == NULL)
|
||||
{
|
||||
TxError("No such cell \"%s\"\n", cellname);
|
||||
break;
|
||||
}
|
||||
cmdFlushCell(cellDef, TRUE);
|
||||
SelectClear();
|
||||
}
|
||||
else
|
||||
TxError("Dereference cell command missing cellname\n");
|
||||
break;
|
||||
|
||||
case IDX_READWRITE:
|
||||
if (cellname == NULL)
|
||||
cellDef = EditRootDef;
|
||||
|
|
@ -994,6 +1191,35 @@ CmdCellname(w, cmd)
|
|||
}
|
||||
break;
|
||||
|
||||
case IDX_TIMESTAMP:
|
||||
if (cellname == NULL)
|
||||
cellDef = EditRootDef;
|
||||
else
|
||||
cellDef = DBCellLookDef(cellname);
|
||||
if (cellDef == (CellDef *) NULL)
|
||||
{
|
||||
TxError("Unknown cell %s\n", cellname);
|
||||
break;
|
||||
}
|
||||
if ((locargc == 3) || (locargc == 2 && cellname == NULL))
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(cellDef->cd_timestamp));
|
||||
#else
|
||||
TxPrintf("Timestamp for cell %s = %d\n", cellname, cellDef->cd_timestamp);
|
||||
#endif
|
||||
}
|
||||
else if (locargc == 4 || (locargc == 3 && cellname == NULL))
|
||||
{
|
||||
int timestamp = atoi(cmd->tx_argv[2 + ((cellname == NULL) ? 0 : 1)]);
|
||||
if (timestamp != cellDef->cd_timestamp)
|
||||
{
|
||||
cellDef->cd_timestamp = timestamp;
|
||||
cellDef->cd_flags &= ~CDGETNEWSTAMP;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IDX_FLAGS:
|
||||
if (cellname == NULL)
|
||||
cellDef = EditRootDef;
|
||||
|
|
@ -1133,6 +1359,7 @@ CmdCif(w, cmd)
|
|||
bool doforall = FALSE;
|
||||
float curscale;
|
||||
int argc = cmd->tx_argc;
|
||||
int argshift;
|
||||
char **argv = cmd->tx_argv;
|
||||
|
||||
static char *cmdCifWarnOptions[] = { "default", "none", "align",
|
||||
|
|
@ -1288,10 +1515,10 @@ CmdCif(w, cmd)
|
|||
TxError("Box requested but no cursor box exists\n");
|
||||
return;
|
||||
}
|
||||
CIFCoverageLayer(rootDef, &box, argv[2]);
|
||||
CIFCoverageLayer(rootDef, &box, argv[2], dolist);
|
||||
}
|
||||
else if (argc == 3)
|
||||
CIFCoverageLayer(rootDef, &rootDef->cd_bbox, argv[2]);
|
||||
CIFCoverageLayer(rootDef, &rootDef->cd_bbox, argv[2], dolist);
|
||||
else
|
||||
goto wrongNumArgs;
|
||||
|
||||
|
|
@ -3454,7 +3681,7 @@ CmdDrc(w, cmd)
|
|||
}
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
if (count_total >= 0)
|
||||
if ((count_total >= 0) || (!dolist))
|
||||
{
|
||||
if (dolist)
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(count_total));
|
||||
|
|
|
|||
|
|
@ -951,7 +951,7 @@ CmdExtract(w, cmd)
|
|||
"style [stylename] set current extraction parameter style",
|
||||
"unique [option] generate unique names when different nodes\n\
|
||||
have the same name",
|
||||
"warn [ [no] option] enable/disable reporting of non-fatal errors",
|
||||
"warn [ [no] option] enable/disable reporting of non-serious errors",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
|||
144
commands/CmdFI.c
144
commands/CmdFI.c
|
|
@ -726,6 +726,45 @@ usage:
|
|||
TxError("Usage: findbox [zoom]\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cmdFindLabelFunc --
|
||||
*
|
||||
* Callback function from CmdFindLabel. Return 1 to stop the search on the
|
||||
* Nth instance of the label named "label", where N is passed through the
|
||||
* client data as lsr_occur.
|
||||
*
|
||||
* The client data record lsr_rect is left pointing to the label location
|
||||
* when the Nth label instance is found.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
typedef struct _labsearchrec
|
||||
{
|
||||
Rect lsr_rect;
|
||||
int lsr_occur;
|
||||
} LabSearchRec;
|
||||
|
||||
|
||||
int cmdFindLabelFunc(rect, name, label, cdarg)
|
||||
Rect *rect;
|
||||
char *name;
|
||||
Label *label;
|
||||
LabSearchRec *cdarg;
|
||||
{
|
||||
if (cdarg->lsr_occur == 0)
|
||||
{
|
||||
cdarg->lsr_rect = *rect;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
cdarg->lsr_occur--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -747,16 +786,6 @@ usage:
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int cmdFindLabelFunc(rect, name, label, cdarg)
|
||||
Rect *rect;
|
||||
char *name;
|
||||
Label *label;
|
||||
Rect *cdarg;
|
||||
{
|
||||
*cdarg = *rect;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
CmdFindLabel(w, cmd)
|
||||
MagWindow *w;
|
||||
|
|
@ -764,17 +793,30 @@ CmdFindLabel(w, cmd)
|
|||
{
|
||||
CellDef *boxDef;
|
||||
CellUse *labUse;
|
||||
Rect box, cmdFindLabelRect;
|
||||
Rect box;
|
||||
char *labname;
|
||||
int found;
|
||||
int found, occur, plainargs;
|
||||
bool doglob = FALSE; /* csh-style glob matching (see utils/match.c) */
|
||||
LabSearchRec lsr;
|
||||
int dbListLabels(); /* forward declaration */
|
||||
|
||||
if ((cmd->tx_argc == 3) && !strncmp(cmd->tx_argv[1], "-glob", 5))
|
||||
plainargs = cmd->tx_argc;
|
||||
if ((plainargs > 2) && !strncmp(cmd->tx_argv[1], "-glob", 5))
|
||||
{
|
||||
plainargs--;
|
||||
doglob = TRUE;
|
||||
else if (cmd->tx_argc != 2)
|
||||
}
|
||||
if ((plainargs != 2) && (plainargs != 3))
|
||||
goto usage;
|
||||
|
||||
occur = 0;
|
||||
if (plainargs == 3)
|
||||
{
|
||||
char *occurstr = cmd->tx_argv[plainargs - 1];
|
||||
if (StrIsInt(occurstr))
|
||||
occur = atoi(occurstr);
|
||||
}
|
||||
|
||||
if (w == NULL)
|
||||
{
|
||||
TxError("Point to a window first.\n");
|
||||
|
|
@ -794,7 +836,7 @@ CmdFindLabel(w, cmd)
|
|||
return;
|
||||
};
|
||||
|
||||
labname = (cmd->tx_argc == 3) ? cmd->tx_argv[2] : cmd->tx_argv[1];
|
||||
labname = cmd->tx_argv[1 + (doglob) ? 1 : 0];
|
||||
labUse = EditCellUse;
|
||||
if (labUse == NULL) labUse = (CellUse *)w->w_surfaceID;
|
||||
|
||||
|
|
@ -815,15 +857,17 @@ CmdFindLabel(w, cmd)
|
|||
{
|
||||
/* Exact-match label search (corrected by Nishit, 10/14/04) */
|
||||
|
||||
lsr.lsr_occur = occur;
|
||||
|
||||
found = DBSrLabelLoc(labUse, labname, cmdFindLabelFunc,
|
||||
(ClientData) &cmdFindLabelRect);
|
||||
(ClientData) &lsr);
|
||||
if (found) {
|
||||
if (cmdFindLabelRect.r_xbot == cmdFindLabelRect.r_xtop)
|
||||
cmdFindLabelRect.r_xtop++;
|
||||
if (cmdFindLabelRect.r_ybot == cmdFindLabelRect.r_ytop)
|
||||
cmdFindLabelRect.r_ytop++;
|
||||
ToolMoveBox(TOOL_BL,&cmdFindLabelRect.r_ll,FALSE,labUse->cu_def);
|
||||
ToolMoveCorner(TOOL_TR,&cmdFindLabelRect.r_ur,FALSE,labUse->cu_def);
|
||||
if (lsr.lsr_rect.r_xbot == lsr.lsr_rect.r_xtop)
|
||||
lsr.lsr_rect.r_xtop++;
|
||||
if (lsr.lsr_rect.r_ybot == lsr.lsr_rect.r_ytop)
|
||||
lsr.lsr_rect.r_ytop++;
|
||||
ToolMoveBox(TOOL_BL, &lsr.lsr_rect.r_ll, FALSE, labUse->cu_def);
|
||||
ToolMoveCorner(TOOL_TR, &lsr.lsr_rect.r_ur, FALSE, labUse->cu_def);
|
||||
} else {
|
||||
TxError("Couldn't find label %s\n", labname);
|
||||
}
|
||||
|
|
@ -869,10 +913,12 @@ dbListLabels(scx, label, tpath, cdarg)
|
|||
* Implement the "flush" command.
|
||||
* Throw away all changes made within magic to the specified cell,
|
||||
* and re-read it from disk. If no cell is specified, the default
|
||||
* is the current edit cell.
|
||||
* is the current edit cell. If "-dereference" is specified as an
|
||||
* option, then re-read the cell from the search path instead of
|
||||
* the file path that has been associated with the cell.
|
||||
*
|
||||
* Usage:
|
||||
* flush [cellname]
|
||||
* flush [cellname] [-dereference]
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
|
|
@ -893,10 +939,17 @@ CmdFlush(w, cmd)
|
|||
int action;
|
||||
static char *actionNames[] = { "no", "yes", 0 };
|
||||
char *prompt;
|
||||
bool dereference = FALSE;
|
||||
|
||||
if (!strncmp(cmd->tx_argv[cmd->tx_argc - 1], "-deref", 6))
|
||||
{
|
||||
dereference = TRUE;
|
||||
cmd->tx_argc--;
|
||||
}
|
||||
|
||||
if (cmd->tx_argc > 2)
|
||||
{
|
||||
TxError("Usage: flush [cellname]\n");
|
||||
TxError("Usage: flush [cellname] [dereference]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -926,7 +979,7 @@ CmdFlush(w, cmd)
|
|||
return;
|
||||
}
|
||||
|
||||
cmdFlushCell(def);
|
||||
cmdFlushCell(def, dereference);
|
||||
SelectClear();
|
||||
TxPrintf("[Flushed]\n");
|
||||
}
|
||||
|
|
@ -1565,8 +1618,8 @@ CmdFindNetProc(nodename, use, rect, warn_not_found)
|
|||
/* go to that point (transformed to the top level of the design */
|
||||
/* hierarchy). */
|
||||
|
||||
/* see extract/extractInt.h for the format of the node, found in */
|
||||
/* extMakeNodeNumPrint(), which is a macro, not a subroutine. */
|
||||
/* see extract/extBasic.c for the format of the node, found */
|
||||
/* in extMakeNodeNumPrint(). */
|
||||
|
||||
locvalid = FALSE;
|
||||
if ((xstr = strchr(s, '_')) != NULL)
|
||||
|
|
@ -1816,6 +1869,9 @@ flatCopyAllLabels(scx, lab, tpath, targetUse)
|
|||
char labelname[1024];
|
||||
char *n, *f, c;
|
||||
|
||||
/* Ignore null labels */
|
||||
if (*lab->lab_text == '\0') return 0;
|
||||
|
||||
def = targetUse->cu_def;
|
||||
if (!GEO_LABEL_IN_AREA(&lab->lab_rect, &(scx->scx_area))) return 0;
|
||||
GeoTransRect(&scx->scx_trans, &lab->lab_rect, &labTargetRect);
|
||||
|
|
@ -1876,7 +1932,7 @@ CmdFlatten(w, cmd)
|
|||
TxCommand *cmd;
|
||||
{
|
||||
int rval, xMask;
|
||||
bool dolabels, toplabels, invert;
|
||||
bool dolabels, dobox, toplabels, invert;
|
||||
char *destname;
|
||||
CellDef *newdef;
|
||||
CellUse *newuse;
|
||||
|
|
@ -1887,6 +1943,7 @@ CmdFlatten(w, cmd)
|
|||
xMask = CU_DESCEND_ALL;
|
||||
dolabels = TRUE;
|
||||
toplabels = FALSE;
|
||||
dobox = FALSE;
|
||||
|
||||
rval = 0;
|
||||
if (cmd->tx_argc > 2)
|
||||
|
|
@ -1912,6 +1969,9 @@ CmdFlatten(w, cmd)
|
|||
{
|
||||
switch(cmd->tx_argv[i][3])
|
||||
{
|
||||
case 'b':
|
||||
dobox = (invert) ? FALSE : TRUE;
|
||||
break;
|
||||
case 'l':
|
||||
dolabels = (invert) ? FALSE : TRUE;
|
||||
break;
|
||||
|
|
@ -1926,7 +1986,7 @@ CmdFlatten(w, cmd)
|
|||
break;
|
||||
default:
|
||||
TxError("options are: -nolabels, -nosubcircuits "
|
||||
"-novendor, -dotoplabels\n");
|
||||
"-novendor, -dotoplabels, -dobox\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1953,7 +2013,6 @@ CmdFlatten(w, cmd)
|
|||
(void) StrDup(&(newuse->cu_id), "Flattened cell");
|
||||
DBSetTrans(newuse, &GeoIdentityTransform);
|
||||
newuse->cu_expandMask = CU_DESCEND_SPECIAL;
|
||||
UndoDisable();
|
||||
flatDestUse = newuse;
|
||||
|
||||
if (EditCellUse)
|
||||
|
|
@ -1961,9 +2020,28 @@ CmdFlatten(w, cmd)
|
|||
else
|
||||
scx.scx_use = (CellUse *)w->w_surfaceID;
|
||||
|
||||
scx.scx_area = scx.scx_use->cu_def->cd_bbox;
|
||||
if (dobox)
|
||||
{
|
||||
CellDef *boxDef;
|
||||
|
||||
if (!ToolGetBox(&boxDef, &scx.scx_area))
|
||||
{
|
||||
TxError("Put the box in a window first.\n");
|
||||
return;
|
||||
}
|
||||
else if (boxDef != scx.scx_use->cu_def)
|
||||
{
|
||||
TxError("The box is not in the edit cell!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
scx.scx_area = scx.scx_use->cu_def->cd_bbox;
|
||||
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
|
||||
UndoDisable();
|
||||
|
||||
DBCellCopyAllPaint(&scx, &DBAllButSpaceAndDRCBits, xMask, flatDestUse);
|
||||
if (dolabels)
|
||||
FlatCopyAllLabels(&scx, &DBAllTypeBits, xMask, flatDestUse);
|
||||
|
|
@ -1980,5 +2058,3 @@ CmdFlatten(w, cmd)
|
|||
|
||||
UndoEnable();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -309,6 +309,10 @@ CmdLabel(w, cmd)
|
|||
CmdLabelProc(p, font, size, rotate, offx, offy, pos, sticky, type);
|
||||
}
|
||||
|
||||
#define LOAD_NOWINDOW 0
|
||||
#define LOAD_DEREFERENCE 1
|
||||
#define LOAD_FORCE 2
|
||||
#define LOAD_QUIET 3
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
|
|
@ -318,7 +322,7 @@ CmdLabel(w, cmd)
|
|||
* Implement the "load" command.
|
||||
*
|
||||
* Usage:
|
||||
* load [name [scaled n [d]]] [-force] [-nowindow] [-dereference]
|
||||
* load [name [scaled n [d]]] [-force] [-nowindow] [-dereference] [-quiet]
|
||||
*
|
||||
* If name is supplied, then the window containing the point tool is
|
||||
* remapped so as to edit the cell with the given name.
|
||||
|
|
@ -354,29 +358,52 @@ CmdLoad(w, cmd)
|
|||
{
|
||||
int n = 1;
|
||||
int d = 1;
|
||||
int option;
|
||||
int locargc = cmd->tx_argc;
|
||||
bool ignoreTech = FALSE;
|
||||
bool noWindow = FALSE;
|
||||
bool dereference = FALSE;
|
||||
bool beQuiet = FALSE;
|
||||
bool saveVerbose;
|
||||
int keepGoing(); /* forward declaration */
|
||||
extern bool DBVerbose; /* from DBio.c */
|
||||
|
||||
saveVerbose = DBVerbose;
|
||||
|
||||
static char *cmdLoadOption[] =
|
||||
{
|
||||
"-nowindow load file but do not display in the layout window",
|
||||
"-dereference use search paths and ignore embedded cell paths in file",
|
||||
"-force load file even if tech in header does not match",
|
||||
"-quiet no alert if file does not exist",
|
||||
NULL
|
||||
};
|
||||
|
||||
while (cmd->tx_argv[locargc - 1][0] == '-')
|
||||
{
|
||||
option = Lookup(cmd->tx_argv[locargc - 1], cmdLoadOption);
|
||||
switch (option)
|
||||
{
|
||||
case LOAD_NOWINDOW:
|
||||
noWindow = TRUE;
|
||||
break;
|
||||
case LOAD_DEREFERENCE:
|
||||
dereference = TRUE;
|
||||
break;
|
||||
case LOAD_FORCE:
|
||||
ignoreTech = TRUE;
|
||||
break;
|
||||
case LOAD_QUIET:
|
||||
beQuiet = TRUE;
|
||||
break;
|
||||
default:
|
||||
TxError("No such option \"%s\".\n", cmd->tx_argv[locargc - 1]);
|
||||
}
|
||||
locargc--;
|
||||
}
|
||||
|
||||
if (locargc > 2)
|
||||
{
|
||||
if (!strncmp(cmd->tx_argv[locargc - 1], "-nowindow", 8))
|
||||
{
|
||||
locargc--;
|
||||
noWindow = TRUE;
|
||||
}
|
||||
if (!strncmp(cmd->tx_argv[locargc - 1], "-deref", 5))
|
||||
{
|
||||
locargc--;
|
||||
dereference = TRUE;
|
||||
}
|
||||
if (!strncmp(cmd->tx_argv[locargc - 1], "-force", 6))
|
||||
{
|
||||
locargc--;
|
||||
ignoreTech = TRUE;
|
||||
}
|
||||
if ((locargc >= 4) && !strncmp(cmd->tx_argv[2], "scale", 5) &&
|
||||
StrIsInt(cmd->tx_argv[3]))
|
||||
{
|
||||
|
|
@ -397,7 +424,7 @@ CmdLoad(w, cmd)
|
|||
else if (!ignoreTech && !noWindow && !dereference)
|
||||
{
|
||||
TxError("Usage: %s name [scaled n [d]] [-force] "
|
||||
"[-nowindow] [-dereference]\n",
|
||||
"[-nowindow] [-dereference] [-quiet]\n",
|
||||
cmd->tx_argv[0]);
|
||||
return;
|
||||
}
|
||||
|
|
@ -422,8 +449,10 @@ CmdLoad(w, cmd)
|
|||
*(cmd->tx_argv[1] + strlen(cmd->tx_argv[1]) - 1) = '\0';
|
||||
}
|
||||
#endif
|
||||
DBVerbose = !beQuiet;
|
||||
DBWloadWindow((noWindow == TRUE) ? NULL : w, cmd->tx_argv[1],
|
||||
ignoreTech, FALSE, dereference);
|
||||
DBVerbose = saveVerbose;
|
||||
|
||||
if ((n > 1) || (d > 1))
|
||||
{
|
||||
|
|
@ -456,7 +485,12 @@ CmdLoad(w, cmd)
|
|||
ReduceFraction(&DBLambda[0], &DBLambda[1]);
|
||||
}
|
||||
}
|
||||
else DBWloadWindow(w, (char *) NULL, TRUE, FALSE, FALSE);
|
||||
else
|
||||
{
|
||||
DBVerbose = !beQuiet;
|
||||
DBWloadWindow(w, (char *) NULL, TRUE, FALSE, FALSE);
|
||||
DBVerbose = saveVerbose;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1298,7 +1332,7 @@ CmdPort(w, cmd)
|
|||
char **msg;
|
||||
int argstart;
|
||||
int i, refidx, idx, pos, type, option, argc;
|
||||
unsigned short dirmask;
|
||||
unsigned int dirmask;
|
||||
bool found;
|
||||
bool nonEdit = FALSE;
|
||||
Label *lab, *sl;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
|
|
@ -53,6 +54,61 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
|
||||
extern void DisplayWindow();
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CmdRandom
|
||||
*
|
||||
* Generate a random integer or set the random seed. This is mainly
|
||||
* used for seeding the random number generator for the GDS write
|
||||
* routine when GDS write is assigning a random prefix to ensure
|
||||
* uniqueness of names in a GDS library read from a file instead of
|
||||
* generated from the database.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
CmdRandom(w, cmd)
|
||||
MagWindow *w;
|
||||
TxCommand *cmd;
|
||||
{
|
||||
int value;
|
||||
|
||||
if (cmd->tx_argc == 1)
|
||||
{
|
||||
/* Return a random number */
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(random()));
|
||||
#else
|
||||
TxPrintf("%d", random());
|
||||
#endif
|
||||
}
|
||||
else if ((cmd->tx_argc >= 2) && (!strcmp(cmd->tx_argv[1], "seed")))
|
||||
{
|
||||
if (cmd->tx_argc == 3)
|
||||
{
|
||||
value = atoi(cmd->tx_argv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = (int)time(NULL);
|
||||
}
|
||||
srandom(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
TxPrintf("usage: random [seed [<value>]]\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(NO_SIM_MODULE) && defined(RSIM_MODULE)
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -285,12 +285,15 @@ CmdInit()
|
|||
*/
|
||||
|
||||
void
|
||||
cmdFlushCell(def)
|
||||
cmdFlushCell(def, force_deref)
|
||||
CellDef *def;
|
||||
bool force_deref;
|
||||
{
|
||||
CellUse *parentUse;
|
||||
bool dereference;
|
||||
|
||||
if (def == NULL) return;
|
||||
|
||||
/* Disallow flushing a cell that contains the edit cell as a child */
|
||||
if (EditCellUse && (EditCellUse->cu_parent == def))
|
||||
{
|
||||
|
|
@ -300,6 +303,15 @@ cmdFlushCell(def)
|
|||
}
|
||||
|
||||
UndoFlush();
|
||||
|
||||
if (force_deref)
|
||||
{
|
||||
/* Force dereferencing */
|
||||
def->cd_flags |= CDDEREFERENCE;
|
||||
freeMagic(def->cd_file);
|
||||
def->cd_file = NULL;
|
||||
}
|
||||
|
||||
DBWAreaChanged(def, &def->cd_bbox, DBW_ALLWINDOWS,
|
||||
(TileTypeBitMask *) NULL);
|
||||
for (parentUse = def->cd_parents; parentUse != NULL;
|
||||
|
|
|
|||
|
|
@ -1818,7 +1818,7 @@ cmdWriteallFunc(def, cmd)
|
|||
cmdSaveCell(def, (char *) NULL, FALSE, TRUE);
|
||||
break;
|
||||
case 1: /* Flush */
|
||||
cmdFlushCell(def);
|
||||
cmdFlushCell(def, FALSE);
|
||||
break;
|
||||
case 2: /* Skip */
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ static PaintResultType (*dbCurPaintTbl)[NT][NT] = DBPaintResultTbl;
|
|||
* such as the design-rule checker that need to use, for example,
|
||||
* DBPaintPlaneMark instead of the standard version.
|
||||
*/
|
||||
static void (*dbCurPaintPlane)() = DBPaintPlaneWrapper;
|
||||
static int (*dbCurPaintPlane)() = DBPaintPlaneWrapper;
|
||||
|
||||
/* Structure passed to DBTreeSrTiles() */
|
||||
struct copyAllArg
|
||||
|
|
@ -56,6 +56,7 @@ struct copyAllArg
|
|||
TileTypeBitMask *caa_mask; /* Mask of tile types to be copied */
|
||||
Rect caa_rect; /* Clipping rect in target coords */
|
||||
CellUse *caa_targetUse; /* Use to which tiles are copied */
|
||||
void (*caa_func)(); /* Callback function for off-grid points */
|
||||
Rect *caa_bbox; /* Bbox of material copied (in
|
||||
* targetUse coords). Used only when
|
||||
* copying cells.
|
||||
|
|
@ -96,7 +97,7 @@ struct copyLabelArg
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
int
|
||||
DBPaintPlaneWrapper(def, pNum, type, area, undo)
|
||||
CellDef *def;
|
||||
int pNum;
|
||||
|
|
@ -106,12 +107,14 @@ DBPaintPlaneWrapper(def, pNum, type, area, undo)
|
|||
{
|
||||
TileType loctype = type & TT_LEFTMASK;
|
||||
Rect expand;
|
||||
int result;
|
||||
|
||||
undo->pu_pNum = pNum;
|
||||
DBNMPaintPlane(def->cd_planes[pNum], type, area,
|
||||
result = DBNMPaintPlane(def->cd_planes[pNum], type, area,
|
||||
dbCurPaintTbl[pNum][loctype], undo);
|
||||
GEO_EXPAND(area, 1, &expand);
|
||||
DBMergeNMTiles(def->cd_planes[pNum], &expand, undo);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -126,7 +129,7 @@ DBPaintPlaneWrapper(def, pNum, type, area, undo)
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
int
|
||||
DBPaintPlaneMark(def, pNum, type, area, undo)
|
||||
CellDef *def;
|
||||
int pNum;
|
||||
|
|
@ -137,7 +140,7 @@ DBPaintPlaneMark(def, pNum, type, area, undo)
|
|||
TileType loctype = type & TT_LEFTMASK;
|
||||
|
||||
undo->pu_pNum = pNum;
|
||||
DBNMPaintPlane0(def->cd_planes[pNum], type, area,
|
||||
return DBNMPaintPlane0(def->cd_planes[pNum], type, area,
|
||||
dbCurPaintTbl[pNum][loctype], undo, (unsigned char)PAINT_MARK);
|
||||
}
|
||||
|
||||
|
|
@ -147,7 +150,7 @@ DBPaintPlaneMark(def, pNum, type, area, undo)
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
int
|
||||
DBPaintPlaneXor(def, pNum, type, area, undo)
|
||||
CellDef *def;
|
||||
int pNum;
|
||||
|
|
@ -158,7 +161,7 @@ DBPaintPlaneXor(def, pNum, type, area, undo)
|
|||
TileType loctype = type & TT_LEFTMASK;
|
||||
|
||||
undo->pu_pNum = pNum;
|
||||
DBNMPaintPlane0(def->cd_planes[pNum], type, area,
|
||||
return DBNMPaintPlane0(def->cd_planes[pNum], type, area,
|
||||
dbCurPaintTbl[pNum][loctype], undo, (unsigned char)PAINT_XOR);
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +178,7 @@ DBPaintPlaneXor(def, pNum, type, area, undo)
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
int
|
||||
DBPaintPlaneActive(def, pNum, type, area, undo)
|
||||
CellDef *def;
|
||||
int pNum;
|
||||
|
|
@ -200,11 +203,13 @@ DBPaintPlaneActive(def, pNum, type, area, undo)
|
|||
DBPaintPlaneWrapper(def, pNum, t | (type &
|
||||
(TT_SIDE | TT_DIRECTION | TT_DIAGONAL)),
|
||||
area, undo);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (TTMaskHasType(&DBActiveLayerBits, loctype))
|
||||
DBPaintPlaneWrapper(def, pNum, type, area, undo);
|
||||
return DBPaintPlaneWrapper(def, pNum, type, area, undo);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -241,6 +246,7 @@ DBCellCopyManhattanPaint(scx, mask, xMask, targetUse)
|
|||
|
||||
arg.caa_mask = mask;
|
||||
arg.caa_targetUse = targetUse;
|
||||
arg.caa_func = NULL;
|
||||
GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &arg.caa_rect);
|
||||
|
||||
(void) DBTreeSrTiles(scx, mask, xMask, dbCopyManhattanPaint, (ClientData) &arg);
|
||||
|
|
@ -281,6 +287,52 @@ DBCellCopyAllPaint(scx, mask, xMask, targetUse)
|
|||
|
||||
arg.caa_mask = mask;
|
||||
arg.caa_targetUse = targetUse;
|
||||
arg.caa_func = NULL;
|
||||
GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &arg.caa_rect);
|
||||
|
||||
/* Add any stacking types for the search (but not to mask passed as arg!) */
|
||||
locMask = *mask;
|
||||
DBMaskAddStacking(&locMask);
|
||||
|
||||
DBTreeSrTiles(scx, &locMask, xMask, dbCopyAllPaint, (ClientData) &arg);
|
||||
}
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* DBCellCheckCopyAllPaint --
|
||||
*
|
||||
* Copy paint from the tree rooted at scx->scx_use to the paint planes
|
||||
* of targetUse, transforming according to the transform in scx.
|
||||
* Only the types specified by typeMask are copied.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Updates the paint planes in targetUse.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func)
|
||||
SearchContext *scx; /* Describes root cell to search, area to
|
||||
* copy, transform from root cell to coords
|
||||
* of targetUse.
|
||||
*/
|
||||
TileTypeBitMask *mask; /* Types of tiles to be yanked/stuffed */
|
||||
int xMask; /* Expansion state mask to be used in search */
|
||||
CellUse *targetUse; /* Cell into which material is to be stuffed */
|
||||
void (*func)(); /* Function to call on tile split error */
|
||||
{
|
||||
TileTypeBitMask locMask;
|
||||
struct copyAllArg arg;
|
||||
int dbCopyAllPaint();
|
||||
|
||||
arg.caa_mask = mask;
|
||||
arg.caa_targetUse = targetUse;
|
||||
arg.caa_func = func;
|
||||
GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &arg.caa_rect);
|
||||
|
||||
/* Add any stacking types for the search (but not to mask passed as arg!) */
|
||||
|
|
@ -441,7 +493,7 @@ DBCellCopyPaint(scx, mask, xMask, targetUse)
|
|||
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
|
||||
if (PlaneMaskHasPlane(planeMask, pNum))
|
||||
{
|
||||
cxp.tc_plane = pNum; /* not used? */
|
||||
cxp.tc_plane = pNum;
|
||||
(void) DBSrPaintArea((Tile *) NULL,
|
||||
scx->scx_use->cu_def->cd_planes[pNum], &scx->scx_area,
|
||||
mask, dbCopyAllPaint, (ClientData) &cxp);
|
||||
|
|
@ -590,6 +642,7 @@ dbCopyAllPaint(tile, cxp)
|
|||
CellDef *def;
|
||||
TileType type = TiGetTypeExact(tile);
|
||||
int pNum = cxp->tc_plane;
|
||||
int result;
|
||||
TileTypeBitMask *typeMask;
|
||||
|
||||
/*
|
||||
|
|
@ -752,7 +805,12 @@ topbottom:
|
|||
|
||||
splitdone:
|
||||
|
||||
(*dbCurPaintPlane)(def, pNum, dinfo | type, &targetRect, &ui);
|
||||
result = (*dbCurPaintPlane)(def, pNum, dinfo | type, &targetRect, &ui);
|
||||
if ((result != 0) && (arg->caa_func != NULL))
|
||||
{
|
||||
/* result == 1 used exclusively for DRC off-grid error flagging */
|
||||
DRCOffGridError(&targetRect);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1013,11 +1071,11 @@ DBNewPaintTable(newTable))[NT][NT]
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
VoidProc
|
||||
IntProc
|
||||
DBNewPaintPlane(newProc)
|
||||
void (*newProc)(); /* Address of new procedure */
|
||||
int (*newProc)(); /* Address of new procedure */
|
||||
{
|
||||
void (*oldProc)() = dbCurPaintPlane;
|
||||
int (*oldProc)() = dbCurPaintPlane;
|
||||
dbCurPaintPlane = newProc;
|
||||
return (oldProc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#endif /* not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/malloc.h"
|
||||
|
|
@ -767,6 +768,9 @@ cleanup:
|
|||
* remaining elements of the current array are skipped, but the
|
||||
* search is not aborted.
|
||||
*
|
||||
* NOTE: Unlike DBTreeSrTiles and DBTreeSrLabels, the function is not
|
||||
* applied to the top level cell, only to descendents.
|
||||
*
|
||||
* Each element of an array is returned separately.
|
||||
*
|
||||
* Results:
|
||||
|
|
@ -847,9 +851,8 @@ dbTreeCellSrFunc(scx, fp)
|
|||
|
||||
if ((fp->tf_xmask == CU_DESCEND_NO_LOCK) && (use->cu_flags & CU_LOCKED))
|
||||
return 2;
|
||||
else if ((!DBDescendSubcell(use, fp->tf_xmask)) ||
|
||||
(fp->tf_xmask == CU_DESCEND_ALL))
|
||||
result = (*fp->tf_func)(scx, fp->tf_arg);
|
||||
else if (!DBDescendSubcell(use, fp->tf_xmask))
|
||||
return (*fp->tf_func)(scx, fp->tf_arg);
|
||||
else
|
||||
{
|
||||
if ((use->cu_def->cd_flags & CDAVAILABLE) == 0)
|
||||
|
|
@ -858,9 +861,15 @@ dbTreeCellSrFunc(scx, fp)
|
|||
if (!DBCellRead(use->cu_def, (char *) NULL, TRUE, dereference, NULL))
|
||||
return 0;
|
||||
}
|
||||
result = DBCellSrArea(scx, dbTreeCellSrFunc, (ClientData) fp);
|
||||
}
|
||||
return result;
|
||||
if (fp->tf_xmask == CU_DESCEND_ALL)
|
||||
{
|
||||
result = (*fp->tf_func)(scx, fp->tf_arg);
|
||||
if (result != 0) return result;
|
||||
}
|
||||
|
||||
/* Run recursively on children in search area */
|
||||
return DBCellSrArea(scx, dbTreeCellSrFunc, (ClientData) fp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1775,6 +1784,149 @@ DBSrCellUses(cellDef, func, arg)
|
|||
return retval;
|
||||
}
|
||||
|
||||
/* Structure used by dbScaleProp() and dbMoveProp() */
|
||||
typedef struct _cellpropstruct {
|
||||
Point cps_point;
|
||||
CellDef *cps_def;
|
||||
} CellPropStruct;
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* dbScaleProp --
|
||||
*
|
||||
* Callback function for dbScaleCell. Finds properties that represent
|
||||
* internal geometry (FIXED_BBOX and MASKHINTS_*) and scale the values
|
||||
* by the numerator / denominator values passed as a pointer to a Point
|
||||
* structure, where p_x is the numerator value and p_y is the denominator
|
||||
* value.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int dbScaleProp(name, value, cps)
|
||||
char *name;
|
||||
char *value;
|
||||
CellPropStruct *cps;
|
||||
{
|
||||
int scalen, scaled;
|
||||
char *newvalue, *vptr;
|
||||
Rect r;
|
||||
|
||||
if (!strcmp(name, "FIXED_BBOX"))
|
||||
{
|
||||
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
|
||||
&r.r_xtop, &r.r_ytop) == 4)
|
||||
{
|
||||
/* Scale numerator held in point X value, */
|
||||
/* scale denominator held in point Y value */
|
||||
|
||||
scalen = cps->cps_point.p_x;
|
||||
scaled = cps->cps_point.p_y;
|
||||
|
||||
DBScalePoint(&r.r_ll, scalen, scaled);
|
||||
DBScalePoint(&r.r_ur, scalen, scaled);
|
||||
|
||||
newvalue = (char *)mallocMagic(40);
|
||||
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
|
||||
r.r_xtop, r.r_ytop);
|
||||
DBPropPut(cps->cps_def, name, newvalue);
|
||||
}
|
||||
}
|
||||
else if (!strncmp(name, "MASKHINTS_", 10))
|
||||
{
|
||||
char *vptr, *lastval;
|
||||
int lastlen;
|
||||
|
||||
newvalue = (char *)NULL;
|
||||
vptr = value;
|
||||
while (*vptr != '\0')
|
||||
{
|
||||
if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
|
||||
&r.r_xtop, &r.r_ytop) == 4)
|
||||
{
|
||||
/* Scale numerator held in point X value, */
|
||||
/* scale denominator held in point Y value */
|
||||
|
||||
scalen = cps->cps_point.p_x;
|
||||
scaled = cps->cps_point.p_y;
|
||||
|
||||
DBScalePoint(&r.r_ll, scalen, scaled);
|
||||
DBScalePoint(&r.r_ur, scalen, scaled);
|
||||
|
||||
lastval = newvalue;
|
||||
lastlen = (lastval) ? strlen(lastval) : 0;
|
||||
newvalue = mallocMagic(40 + lastlen);
|
||||
|
||||
if (lastval)
|
||||
strcpy(newvalue, lastval);
|
||||
else
|
||||
*newvalue = '\0';
|
||||
|
||||
sprintf(newvalue + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
|
||||
r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
|
||||
if (lastval) freeMagic(lastval);
|
||||
|
||||
/* Parse through the four values and check if there's more */
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
if (newvalue)
|
||||
DBPropPut(cps->cps_def, name, newvalue);
|
||||
}
|
||||
return 0; /* Keep enumerating through properties */
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* dbMoveProp --
|
||||
*
|
||||
* Callback function for ??. Finds properties that represent
|
||||
* internal geometry (FIXED_BBOX and MASKHINTS_*) and modifies the values
|
||||
* by the X, Y values passed as a pointer to a Point structure in ClientData.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int dbMoveProp(name, value, cps)
|
||||
char *name;
|
||||
char *value;
|
||||
CellPropStruct *cps;
|
||||
{
|
||||
int origx, origy;
|
||||
char *newvalue;
|
||||
Rect r;
|
||||
|
||||
if (!strcmp(name, "FIXED_BBOX") || !strncmp(name, "MASKHINTS_", 10))
|
||||
{
|
||||
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
|
||||
&r.r_xtop, &r.r_ytop) == 4)
|
||||
{
|
||||
origx = cps->cps_point.p_x;
|
||||
origy = cps->cps_point.p_y;
|
||||
|
||||
DBMovePoint(&r.r_ll, origx, origy);
|
||||
DBMovePoint(&r.r_ur, origx, origy);
|
||||
|
||||
newvalue = (char *)mallocMagic(40);
|
||||
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
|
||||
r.r_xtop, r.r_ytop);
|
||||
DBPropPut(cps->cps_def, name, newvalue);
|
||||
}
|
||||
}
|
||||
return 0; /* Keep enumerating through properties */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -1799,6 +1951,7 @@ dbScaleCell(cellDef, scalen, scaled)
|
|||
LinkedCellUse *luhead, *lu;
|
||||
Plane *newplane;
|
||||
BPlane *cellPlane, *cellPlaneOrig;
|
||||
CellPropStruct cps;
|
||||
|
||||
/* DBCellEnum() attempts to read unavailable celldefs. We don't */
|
||||
/* want to do that here, so check CDAVAILABLE flag first. */
|
||||
|
|
@ -1936,6 +2089,18 @@ donecell:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check all properties for ones with keys beginning with "MASKHINTS_"
|
||||
* or the key "FIXED_BBOX", and scale them by the same amount as all
|
||||
* the geometry.
|
||||
*/
|
||||
|
||||
|
||||
cps.cps_point.p_x = scalen;
|
||||
cps.cps_point.p_y = scaled;
|
||||
cps.cps_def = cellDef;
|
||||
DBPropEnum(cellDef, dbScaleProp, &cps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2023,6 +2188,7 @@ DBMoveCell(cellDef, origx, origy)
|
|||
LinkedCellUse *luhead, *lu;
|
||||
Plane *newplane;
|
||||
BPlane *cellPlane, *cellPlaneOrig;
|
||||
CellPropStruct cps;
|
||||
|
||||
/* Unlike dbScaleCell(), this routine is only run on valid edit defs */
|
||||
|
||||
|
|
@ -2120,31 +2286,15 @@ donecell:
|
|||
DBMovePoint(&cellDef->cd_extended.r_ll, origx, origy);
|
||||
DBMovePoint(&cellDef->cd_extended.r_ur, origx, origy);
|
||||
|
||||
/* If the cell is an abstract view with a fixed bounding box, then */
|
||||
/* adjust the bounding box property to match the new scale. */
|
||||
/* Check all properties for ones with keys beginning with "MASKHINTS_"
|
||||
* or the key "FIXED_BBOX", and move them by the same amount as all
|
||||
* the geometry.
|
||||
*/
|
||||
|
||||
if ((cellDef->cd_flags & CDFIXEDBBOX) != 0)
|
||||
{
|
||||
Rect r;
|
||||
bool found;
|
||||
char *propval;
|
||||
|
||||
propval = (char *)DBPropGet(cellDef, "FIXED_BBOX", &found);
|
||||
if (found)
|
||||
{
|
||||
if (sscanf(propval, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
|
||||
&r.r_xtop, &r.r_ytop) == 4)
|
||||
{
|
||||
DBMovePoint(&r.r_ll, origx, origy);
|
||||
DBMovePoint(&r.r_ur, origx, origy);
|
||||
|
||||
propval = (char *)mallocMagic(40);
|
||||
sprintf(propval, "%d %d %d %d", r.r_xbot, r.r_ybot,
|
||||
r.r_xtop, r.r_ytop);
|
||||
DBPropPut(cellDef, "FIXED_BBOX", propval);
|
||||
}
|
||||
}
|
||||
}
|
||||
cps.cps_point.p_x = origx;
|
||||
cps.cps_point.p_y = origy;
|
||||
cps.cps_def = cellDef;
|
||||
DBPropEnum(cellDef, dbMoveProp, &cps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -275,7 +275,8 @@ dbUnexpandFunc(scx, arg)
|
|||
* the given rectangle.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
* If "halt_on_error" is TRUE, then return 1 if any subcell could not
|
||||
* be read. Otherwise, return 0.
|
||||
*
|
||||
* Side effects:
|
||||
* May make new cells known to the database. Sets the CDAVAILABLE
|
||||
|
|
@ -284,10 +285,11 @@ dbUnexpandFunc(scx, arg)
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
DBCellReadArea(rootUse, rootRect)
|
||||
int
|
||||
DBCellReadArea(rootUse, rootRect, halt_on_error)
|
||||
CellUse *rootUse; /* Root cell use from which search begins */
|
||||
Rect *rootRect; /* Area to be read, in root coordinates */
|
||||
bool halt_on_error; /* If TRUE, failure to find a cell causes a halt */
|
||||
{
|
||||
int dbReadAreaFunc();
|
||||
SearchContext scontext;
|
||||
|
|
@ -295,30 +297,39 @@ DBCellReadArea(rootUse, rootRect)
|
|||
scontext.scx_use = rootUse;
|
||||
scontext.scx_trans = GeoIdentityTransform;
|
||||
scontext.scx_area = *rootRect;
|
||||
(void) dbReadAreaFunc(&scontext);
|
||||
if (dbReadAreaFunc(&scontext, halt_on_error) == 1)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
dbReadAreaFunc(scx)
|
||||
dbReadAreaFunc(scx, halt_on_error)
|
||||
SearchContext *scx; /* Pointer to context specifying
|
||||
* the cell use to be read in, and
|
||||
* an area to be recursively read in
|
||||
* coordinates of the cell use's def.
|
||||
*/
|
||||
bool halt_on_error; /* If TURE, failure to find a cell causes a halt */
|
||||
{
|
||||
CellDef *def = scx->scx_use->cu_def;
|
||||
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
{
|
||||
bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
(void) DBCellRead(def, (char *) NULL, TRUE, dereference, NULL);
|
||||
if (DBCellRead(def, (char *)NULL, TRUE, dereference, NULL) == FALSE)
|
||||
if (halt_on_error)
|
||||
return 1;
|
||||
|
||||
/* Note: we don't have to invoke DBReComputeBbox here because
|
||||
* if the bbox changed then there was a timestamp mismatch and
|
||||
* the timestamp code will take care of the bounding box later.
|
||||
*/
|
||||
}
|
||||
|
||||
(void) DBCellSrArea(scx, dbReadAreaFunc, (ClientData) NULL);
|
||||
if (DBCellSrArea(scx, dbReadAreaFunc, (ClientData)halt_on_error))
|
||||
if (halt_on_error)
|
||||
return 1;
|
||||
|
||||
/* Be clever about handling arrays: if the search area covers this
|
||||
* whole definition, then there's no need to look at any other
|
||||
|
|
@ -328,5 +339,6 @@ dbReadAreaFunc(scx)
|
|||
|
||||
if (GEO_SURROUND(&scx->scx_area, &scx->scx_use->cu_def->cd_bbox))
|
||||
return 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
156
database/DBio.c
156
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"
|
||||
|
|
@ -898,7 +899,7 @@ DBReadBackup(name)
|
|||
*
|
||||
* DBCellRead --
|
||||
*
|
||||
* This is the wrapper for DBCellReadDef. The routine has been divided into
|
||||
* This is the wrapper for dbCellReadDef. The routine has been divided into
|
||||
* parts so that a single backup file can be made and recovered, and in
|
||||
* preparation for allowing certain cell definitions to be in-lined into the
|
||||
* output file (such as polygonXXXXX cells generated by the gds read-in).
|
||||
|
|
@ -989,6 +990,11 @@ DBCellRead(cellDef, name, ignoreTech, dereference, errptr)
|
|||
* CDAVAILABLE, with the CDNOTFOUND bit clear, if we
|
||||
* were successful.
|
||||
*
|
||||
* Notes:
|
||||
* Global variable DBVerbose determines whether or not error
|
||||
* messages are generated by this routine. This can be controlled
|
||||
* by "load -quiet".
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -1061,15 +1067,20 @@ dbReadOpen(cellDef, name, setFileName, errptr)
|
|||
/* somewhere else in the search paths. */
|
||||
|
||||
if (pptr != NULL) *pptr = '.';
|
||||
TxError("Warning: Parent cell lists instance of \"%s\" at bad file "
|
||||
"path %s.\n", cellDef->cd_name, cellDef->cd_file);
|
||||
if (DBVerbose)
|
||||
TxError("Warning: Parent cell lists instance of \"%s\" at "
|
||||
"bad file path %s.\n",
|
||||
cellDef->cd_name, cellDef->cd_file);
|
||||
|
||||
/* Write the new path to cd_file or else magic will */
|
||||
/* generate another error later. */
|
||||
StrDup(&cellDef->cd_file, filename);
|
||||
|
||||
TxError("The cell exists in the search paths at %s.\n", filename);
|
||||
TxError("The discovered version will be used.\n");
|
||||
if (DBVerbose)
|
||||
{
|
||||
TxError("The cell exists in the search paths at %s.\n", filename);
|
||||
TxError("The discovered version will be used.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1090,17 +1101,24 @@ dbReadOpen(cellDef, name, setFileName, errptr)
|
|||
return ((FILE *) NULL);
|
||||
|
||||
if (name != (char *) NULL)
|
||||
TxError("File %s%s couldn't be read\n", name, DBSuffix);
|
||||
{
|
||||
if (DBVerbose)
|
||||
TxError("File %s%s couldn't be read\n", name, DBSuffix);
|
||||
}
|
||||
else if (cellDef->cd_file != (char *) NULL)
|
||||
TxError("File %s couldn't be read\n", cellDef->cd_file);
|
||||
{
|
||||
if (DBVerbose)
|
||||
TxError("File %s couldn't be read\n", cellDef->cd_file);
|
||||
}
|
||||
else {
|
||||
TxError("Cell %s couldn't be read\n", cellDef->cd_name);
|
||||
if (DBVerbose)
|
||||
TxError("Cell %s couldn't be read\n", cellDef->cd_name);
|
||||
realname = (char *) mallocMagic((unsigned) (strlen(cellDef->cd_name)
|
||||
+ strlen(DBSuffix) + 1));
|
||||
(void) sprintf(realname, "%s%s", cellDef->cd_name, DBSuffix);
|
||||
StrDup(&cellDef->cd_file, realname);
|
||||
}
|
||||
if (errptr) TxError("%s\n", strerror(*errptr));
|
||||
if (errptr && DBVerbose) TxError("%s\n", strerror(*errptr));
|
||||
|
||||
cellDef->cd_flags |= CDNOTFOUND;
|
||||
return ((FILE *) NULL);
|
||||
|
|
@ -1373,7 +1391,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 +1400,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. */
|
||||
|
|
@ -2902,7 +2947,8 @@ DBCellWrite(cellDef, fileName)
|
|||
{
|
||||
bool dereference = (cellDef->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
/* Re-aquire the lock on the new file by opening it. */
|
||||
DBCellRead(cellDef, NULL, TRUE, dereference, NULL);
|
||||
if (DBCellRead(cellDef, NULL, TRUE, dereference, NULL) == FALSE)
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -3146,6 +3192,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 +3244,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);
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ dbJoinUndo(tile, splitx, undo)
|
|||
* 'undo' can be NULL.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
* Always return 0.
|
||||
*
|
||||
* Side effects:
|
||||
* Modifies the database plane that contains the given tile.
|
||||
|
|
@ -236,7 +236,7 @@ dbJoinUndo(tile, splitx, undo)
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
int
|
||||
DBPaintPlane0(plane, area, resultTbl, undo, method)
|
||||
Plane *plane; /* Plane whose paint is to be modified */
|
||||
Rect *area; /* Area to be changed */
|
||||
|
|
@ -262,7 +262,7 @@ DBPaintPlane0(plane, area, resultTbl, undo, method)
|
|||
bool haschanged;
|
||||
|
||||
if (area->r_xtop <= area->r_xbot || area->r_ytop <= area->r_ybot)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The following is a modified version of the area enumeration
|
||||
|
|
@ -697,6 +697,7 @@ enum2:
|
|||
|
||||
done2:
|
||||
plane->pl_hint = tile;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1442,7 +1443,7 @@ typedef struct
|
|||
* paint quadrangular (clipped triangle) areas.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
* 0 on success, 1 on error splitting a non-manhattan tile
|
||||
*
|
||||
* Side Effects:
|
||||
* Plane is painted with a diagonal. The plane may be hacked up
|
||||
|
|
@ -1452,7 +1453,7 @@ typedef struct
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
int
|
||||
DBNMPaintPlane0(plane, exacttype, area, resultTbl, undo, method)
|
||||
Plane *plane; /* Plane whose paint is to be modified */
|
||||
TileType exacttype; /* diagonal info for tile to be changed */
|
||||
|
|
@ -1478,6 +1479,7 @@ DBNMPaintPlane0(plane, exacttype, area, resultTbl, undo, method)
|
|||
int xc, yc, width, height;
|
||||
dlong xref, yref; /* xref, yref can easily exceed 32 bits */
|
||||
int resstate;
|
||||
int result = 0;
|
||||
|
||||
if (exacttype & TT_DIAGONAL)
|
||||
{
|
||||
|
|
@ -1532,7 +1534,7 @@ DBNMPaintPlane0(plane, exacttype, area, resultTbl, undo, method)
|
|||
if (resultTbl[oldType] == oldType)
|
||||
{
|
||||
freeMagic((char *) lr);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1544,7 +1546,7 @@ DBNMPaintPlane0(plane, exacttype, area, resultTbl, undo, method)
|
|||
if (newType == oldType)
|
||||
{
|
||||
freeMagic((char *) lr);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Watch for the worst-case scenario of attempting to */
|
||||
|
|
@ -1560,9 +1562,9 @@ DBNMPaintPlane0(plane, exacttype, area, resultTbl, undo, method)
|
|||
{
|
||||
if ((width == 1) || (height == 1))
|
||||
{
|
||||
DBPaintPlane(plane, &(lr->r_r), resultTbl, undo);
|
||||
result = DBPaintPlane(plane, &(lr->r_r), resultTbl, undo);
|
||||
freeMagic((char *) lr);
|
||||
return;
|
||||
return 1; /* Flag the error by returning 1 */
|
||||
}
|
||||
|
||||
/* lr->r_r is drawn & quartered */
|
||||
|
|
@ -1605,7 +1607,7 @@ DBNMPaintPlane0(plane, exacttype, area, resultTbl, undo, method)
|
|||
|
||||
if (newType & TT_DIAGONAL)
|
||||
{
|
||||
DBPaintPlane(plane, &(lr->r_r), DBSpecialPaintTbl,
|
||||
result = DBPaintPlane(plane, &(lr->r_r), DBSpecialPaintTbl,
|
||||
(PaintUndoInfo *)NULL);
|
||||
tile = plane->pl_hint;
|
||||
GOTOPOINT(tile, &(lr->r_r.r_ll));
|
||||
|
|
@ -1620,14 +1622,14 @@ DBNMPaintPlane0(plane, exacttype, area, resultTbl, undo, method)
|
|||
{
|
||||
PaintResultType tempTbl;
|
||||
tempTbl = newType;
|
||||
DBPaintPlane0(plane, &(lr->r_r), &tempTbl, undo, method);
|
||||
result = DBPaintPlane0(plane, &(lr->r_r), &tempTbl,
|
||||
undo, method);
|
||||
}
|
||||
else
|
||||
DBPaintPlane(plane, &(lr->r_r), resultTbl, undo);
|
||||
result = DBPaintPlane(plane, &(lr->r_r), resultTbl, undo);
|
||||
|
||||
freeMagic((char *) lr);
|
||||
/* goto nmmerge; */
|
||||
return;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1755,11 +1757,12 @@ paintrect:
|
|||
if (resstate == RES_DIAG)
|
||||
{
|
||||
/* Recursive call to self on sub-area */
|
||||
DBNMPaintPlane0(plane, exacttype, &(lr->r_r), resultTbl, undo, method);
|
||||
result |= DBNMPaintPlane0(plane, exacttype, &(lr->r_r), resultTbl,
|
||||
undo, method);
|
||||
}
|
||||
else if ((resstate == RES_LEFT && !dinfo.side) ||
|
||||
(resstate == RES_RIGHT && dinfo.side)) {
|
||||
DBPaintPlane(plane, &(lr->r_r), resultTbl, undo);
|
||||
result |= DBPaintPlane(plane, &(lr->r_r), resultTbl, undo);
|
||||
}
|
||||
/* else: Rectangle does not contain type and should be ignored. */
|
||||
nextrect:
|
||||
|
|
@ -1774,8 +1777,10 @@ nextrect:
|
|||
}
|
||||
}
|
||||
else
|
||||
DBPaintPlane0(plane, area, resultTbl, undo, (method == PAINT_MARK) ?
|
||||
result = DBPaintPlane0(plane, area, resultTbl, undo, (method == PAINT_MARK) ?
|
||||
method : PAINT_NORMAL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2547,7 +2552,7 @@ dbMergeType(tile, newType, plane, mergeFlags, undo, client)
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
int
|
||||
DBPaintPlaneVert(plane, area, resultTbl, undo)
|
||||
Plane *plane; /* Plane whose paint is to be modified */
|
||||
Rect *area; /* Area to be changed */
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
|
||||
/* ----------------------------------------------------------------------------
|
||||
*
|
||||
*DBPropPut --
|
||||
* DBPropPut --
|
||||
*
|
||||
* Put a property onto a celldef.
|
||||
*
|
||||
|
|
@ -57,8 +57,15 @@ DBPropPut(cellDef, name, value)
|
|||
HashEntry *entry;
|
||||
char *oldvalue;
|
||||
|
||||
/* Honor the NOEDIT flag */
|
||||
if (cellDef->cd_flags & CDNOEDIT) return;
|
||||
/* Honor the NOEDIT flag. Note that the caller always assumes that */
|
||||
/* the value would be saved in the hash table, so if it is not */
|
||||
/* being used, then it must be freed here. */
|
||||
|
||||
if (cellDef->cd_flags & CDNOEDIT)
|
||||
{
|
||||
freeMagic((char *)value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cellDef->cd_props == (ClientData) NULL)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -204,9 +204,57 @@ DBTechSetVersion(sectionName, argc, argv)
|
|||
}
|
||||
return TRUE;
|
||||
}
|
||||
if (strcmp(argv[0], "requires") == 0)
|
||||
{
|
||||
/* Version requirement check. If the techfile has "requires" followed
|
||||
* by a magic version number in the form [magic-]<major>.<minor>.<revision>,
|
||||
* then the version of magic is checked against this, and the tech
|
||||
* loading will fail if there is a version incompatibility.
|
||||
*/
|
||||
|
||||
int major, minor, rev;
|
||||
int rmajor, rminor, rrev;
|
||||
bool goodversion = FALSE;
|
||||
char *vstring;
|
||||
|
||||
vstring = argv[1];
|
||||
while ((*vstring != '\0') && !isdigit(*vstring)) vstring++;
|
||||
|
||||
major = minor = rev = 0;
|
||||
rmajor = rminor = rrev = 0;
|
||||
|
||||
if (sscanf(vstring, "%d.%d.%d", &rmajor, &rminor, &rrev) == 0)
|
||||
{
|
||||
TechError("Badly formed magic version string, should be major.minor.rev\n");
|
||||
return FALSE;
|
||||
}
|
||||
sscanf(MagicVersion, "%d.%d", &major, &minor);
|
||||
sscanf(MagicRevision, "%d", &rev);
|
||||
if (major > rmajor)
|
||||
goodversion = TRUE;
|
||||
else if (major == rmajor)
|
||||
{
|
||||
if (minor > rminor)
|
||||
goodversion = TRUE;
|
||||
else if (minor == rminor)
|
||||
{
|
||||
if (rev >= rrev)
|
||||
goodversion = TRUE;
|
||||
}
|
||||
}
|
||||
if (goodversion == FALSE)
|
||||
{
|
||||
TechError("Error: Magic version %d.%d.%d is required by this "
|
||||
"techfile, but this version of magic is %d.%d.%d.\n",
|
||||
rmajor, rminor, rrev, major, minor, rev);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
usage:
|
||||
TechError("Badly formed version line\nUsage: {version text}|{description text}\n");
|
||||
TechError("Badly formed version line\n"
|
||||
"Usage: {version text}|{description text}|{requires text}\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -265,42 +265,46 @@ typedef struct label
|
|||
* Label flags bit fields
|
||||
*/
|
||||
|
||||
#define PORT_NUM_MASK 0x0fff /* Mask of port number (up to 4096) */
|
||||
#define PORT_NUM_MASK 0x003fff /* Mask of port number (up to 16384) */
|
||||
|
||||
#define PORT_DIR_MASK 0xf000 /* Mask of all port directions */
|
||||
#define PORT_DIR_NORTH 0x1000 /* Port allows connection to north */
|
||||
#define PORT_DIR_EAST 0x2000 /* Port allows connection to east */
|
||||
#define PORT_DIR_SOUTH 0x4000 /* Port allows connection to south */
|
||||
#define PORT_DIR_WEST 0x8000 /* Port allows connection to west */
|
||||
#define PORT_DIR_MASK 0x03c000 /* Mask of all port directions */
|
||||
#define PORT_DIR_NORTH 0x004000 /* Port allows connection to north */
|
||||
#define PORT_DIR_EAST 0x008000 /* Port allows connection to east */
|
||||
#define PORT_DIR_SOUTH 0x010000 /* Port allows connection to south */
|
||||
#define PORT_DIR_WEST 0x020000 /* Port allows connection to west */
|
||||
|
||||
#define PORT_CLASS_MASK 0x70000 /* Mask of all port classes */
|
||||
#define PORT_CLASS_DEFAULT 0x00000 /* Port takes default class */
|
||||
#define PORT_CLASS_INPUT 0x10000 /* Port is a digital input */
|
||||
#define PORT_CLASS_OUTPUT 0x20000 /* Port is a digital output */
|
||||
#define PORT_CLASS_TRISTATE 0x30000 /* Port is a tri-state output */
|
||||
#define PORT_CLASS_BIDIRECTIONAL 0x40000 /* Port is analog or digital */
|
||||
/* bidirectional */
|
||||
#define PORT_CLASS_FEEDTHROUGH 0x50000 /* Port touches no active */
|
||||
/* devices */
|
||||
#define PORT_CLASS_MASK 0x1c0000 /* Mask of all port classes */
|
||||
#define PORT_CLASS_DEFAULT 0x000000 /* Port takes default class */
|
||||
#define PORT_CLASS_INPUT 0x040000 /* Port is a digital input */
|
||||
#define PORT_CLASS_OUTPUT 0x080000 /* Port is a digital output */
|
||||
#define PORT_CLASS_TRISTATE 0x0c0000 /* Port is a tri-state output */
|
||||
#define PORT_CLASS_BIDIRECTIONAL 0x100000 /* Port is analog or digital */
|
||||
/* bidirectional */
|
||||
#define PORT_CLASS_FEEDTHROUGH 0x140000 /* Port touches no active */
|
||||
/* devices */
|
||||
|
||||
#define PORT_USE_MASK 0x0700000 /* Mask of all port uses */
|
||||
#define PORT_USE_DEFAULT 0x0000000 /* Port takes default use */
|
||||
#define PORT_USE_SIGNAL 0x0100000 /* Port is a digital signal */
|
||||
#define PORT_USE_ANALOG 0x0200000 /* Port is an analog signal */
|
||||
#define PORT_USE_POWER 0x0300000 /* Port is a power rail */
|
||||
#define PORT_USE_GROUND 0x0400000 /* Port is a ground rail */
|
||||
#define PORT_USE_CLOCK 0x0500000 /* Port is a digital clock */
|
||||
/* signal */
|
||||
#define PORT_SHAPE_MASK 0x1800000 /* Mask of all port shapes */
|
||||
#define PORT_SHAPE_DEFAULT 0x0000000 /* Port takes default shape */
|
||||
#define PORT_SHAPE_ABUT 0x0800000 /* Port is an abutment shape */
|
||||
#define PORT_SHAPE_RING 0x1000000 /* Port is a ring shape */
|
||||
#define PORT_SHAPE_THRU 0x1800000 /* Port is a feedthrough shape */
|
||||
#define PORT_VISITED 0x2000000 /* Bit for checking if a port */
|
||||
#define PORT_USE_MASK 0x03c00000 /* Mask of all port uses */
|
||||
#define PORT_USE_DEFAULT 0x00000000 /* Port takes default use */
|
||||
#define PORT_USE_SIGNAL 0x00400000 /* Port is a digital signal */
|
||||
#define PORT_USE_ANALOG 0x00800000 /* Port is an analog signal */
|
||||
#define PORT_USE_POWER 0x00c00000 /* Port is a power rail */
|
||||
#define PORT_USE_GROUND 0x01000000 /* Port is a ground rail */
|
||||
#define PORT_USE_CLOCK 0x01400000 /* Port is a digital clock */
|
||||
#define PORT_USE_RESET 0x01800000 /* Port is a digital reset */
|
||||
#define PORT_USE_SCAN 0x01c00000 /* Port is a digital scan */
|
||||
#define PORT_USE_TIEOFF 0x02000000 /* Port is a tie-off */
|
||||
|
||||
#define PORT_SHAPE_MASK 0x0c000000 /* Mask of all port shapes */
|
||||
#define PORT_SHAPE_DEFAULT 0x00000000 /* Port takes default shape */
|
||||
#define PORT_SHAPE_ABUT 0x04000000 /* Port is an abutment shape */
|
||||
#define PORT_SHAPE_RING 0x08000000 /* Port is a ring shape */
|
||||
#define PORT_SHAPE_THRU 0x0c000000 /* Port is a feedthrough shape */
|
||||
|
||||
#define PORT_VISITED 0x10000000 /* Bit for checking if a port */
|
||||
/* has been previously visited. */
|
||||
|
||||
#define LABEL_STICKY 0x4000000 /* Label does not change layers */
|
||||
#define LABEL_GENERATE 0x8000000 /* Auto-generated label */
|
||||
#define LABEL_STICKY 0x20000000 /* Label does not change layers */
|
||||
#define LABEL_GENERATE 0x40000000 /* Auto-generated label */
|
||||
|
||||
/*
|
||||
* Macros for dealing with label rectangles.
|
||||
|
|
@ -652,7 +656,7 @@ typedef struct treeFilter
|
|||
#define TF_LABEL_ATTACH_CORNER 0x3C /* Mask of the four types above */
|
||||
|
||||
/* To do: Make the tpath entries dynamically allocated */
|
||||
#define FLATTERMSIZE 1024 /* Used for generating flattened labels */
|
||||
#define FLATTERMSIZE 4096 /* Used for generating flattened labels */
|
||||
|
||||
/* -------------- Undo information passed to DBPaintPlane ------------- */
|
||||
|
||||
|
|
@ -692,13 +696,13 @@ typedef struct
|
|||
extern void DBPaint();
|
||||
extern void DBErase();
|
||||
extern int DBSrPaintArea();
|
||||
extern void DBPaintPlane0();
|
||||
extern void DBPaintPlaneActive();
|
||||
extern void DBPaintPlaneWrapper();
|
||||
extern void DBPaintPlaneMark();
|
||||
extern void DBPaintPlaneXor();
|
||||
extern void DBPaintPlaneByProc();
|
||||
extern void DBPaintPlaneMergeOnce();
|
||||
extern int DBPaintPlane0();
|
||||
extern int DBPaintPlaneActive();
|
||||
extern int DBPaintPlaneWrapper();
|
||||
extern int DBPaintPlaneMark();
|
||||
extern int DBPaintPlaneXor();
|
||||
extern int DBPaintPlaneByProc();
|
||||
extern int DBPaintPlaneMergeOnce();
|
||||
extern void DBPaintMask();
|
||||
extern void DBEraseMask();
|
||||
extern void DBClearPaintPlane();
|
||||
|
|
@ -708,7 +712,7 @@ extern void DBUnlockContact();
|
|||
#define DBPaintPlane(a, b, c, d) DBPaintPlane0(a, b, c, d, PAINT_NORMAL)
|
||||
#define DBMergeNMTiles(a, b, c) DBMergeNMTiles0(a, b, c, FALSE)
|
||||
|
||||
extern void DBNMPaintPlane0();
|
||||
extern int DBNMPaintPlane0();
|
||||
#define DBNMPaintPlane(a, b, c, d, e) DBNMPaintPlane0(a, b, c, d, e, PAINT_NORMAL)
|
||||
|
||||
/* I/O */
|
||||
|
|
@ -716,7 +720,7 @@ extern bool DBCellRead();
|
|||
extern bool DBTestOpen();
|
||||
extern char *DBGetTech();
|
||||
extern bool DBCellWrite();
|
||||
extern void DBCellReadArea();
|
||||
extern int DBCellReadArea();
|
||||
extern void DBFileRecovery();
|
||||
extern bool DBWriteBackup();
|
||||
extern bool DBReadBackup();
|
||||
|
|
@ -812,6 +816,7 @@ extern char *DBPrintUseId();
|
|||
/* Massive copying */
|
||||
extern void DBCellCopyPaint();
|
||||
extern void DBCellCopyAllPaint();
|
||||
extern void DBCellCheckCopyAllPaint();
|
||||
extern void DBCellCopyLabels();
|
||||
extern void DBCellCopyAllLabels();
|
||||
extern void DBCellCopyCells();
|
||||
|
|
@ -841,8 +846,8 @@ extern void DBEnumerateTypes();
|
|||
extern Plane *DBNewPlane();
|
||||
|
||||
extern PaintResultType (*DBNewPaintTable())[TT_MAXTYPES][TT_MAXTYPES];
|
||||
typedef void (*VoidProc)();
|
||||
VoidProc DBNewPaintPlane();
|
||||
typedef int (*IntProc)();
|
||||
IntProc DBNewPaintPlane();
|
||||
|
||||
/* Diagnostic */
|
||||
extern void DBTechPrintTypes();
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ extern void CmdGetcell(), CmdGrid(), CmdIdentify();
|
|||
extern void CmdLabel(), CmdLoad();
|
||||
extern void CmdMove(), CmdNetlist(), CmdOrient(), CmdPaint(), CmdPath();
|
||||
extern void CmdPlow(), CmdPolygon(), CmdPort(), CmdProperty();
|
||||
extern void CmdSave(), CmdScaleGrid(), CmdSee();
|
||||
extern void CmdRandom(), CmdSave(), CmdScaleGrid(), CmdSee();
|
||||
extern void CmdSelect(), CmdSetLabel(), CmdSideways();
|
||||
extern void CmdShell(), CmdSnap();
|
||||
extern void CmdStretch(), CmdStraighten();
|
||||
|
|
@ -407,6 +407,9 @@ DBWInitCommands()
|
|||
WindAddCommand(DBWclientID,
|
||||
"rotate [+/-][deg] rotate selection and box (counter)clockwise",
|
||||
CmdClockwise, FALSE); /* "rotate" is alias for "clockwise" */
|
||||
WindAddCommand(DBWclientID,
|
||||
"random [seed [value]] generate random number or set random seed",
|
||||
CmdRandom, FALSE);
|
||||
WindAddCommand(DBWclientID,
|
||||
"save [filename] save edit cell on disk",
|
||||
CmdSave, FALSE);
|
||||
|
|
|
|||
|
|
@ -620,6 +620,16 @@ drcTile (tile, arg)
|
|||
drcCheckRectSize(tile, arg, cptr);
|
||||
continue;
|
||||
}
|
||||
/* Off-grid checks apply only to edge */
|
||||
if (cptr->drcc_flags & DRC_OFFGRID)
|
||||
{
|
||||
errRect.r_ytop = edgeTop;
|
||||
errRect.r_ybot = edgeBot;
|
||||
errRect.r_xtop = errRect.r_xbot = edgeX;
|
||||
arg->dCD_cptr = cptr;
|
||||
drcCheckOffGrid(&errRect, arg, cptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
arg->dCD_radial = 0;
|
||||
|
|
@ -983,13 +993,22 @@ checkbottom:
|
|||
}
|
||||
continue;
|
||||
}
|
||||
else if (cptr->drcc_flags & (DRC_AREA | DRC_RECTSIZE
|
||||
| DRC_MAXWIDTH))
|
||||
else if (cptr->drcc_flags & (DRC_AREA | DRC_RECTSIZE | DRC_MAXWIDTH))
|
||||
{
|
||||
/* only have to do these checks in one direction */
|
||||
if (trigpending) cptr = cptr->drcc_next;
|
||||
continue;
|
||||
}
|
||||
/* Off-grid checks apply only to edge */
|
||||
if (cptr->drcc_flags & DRC_OFFGRID)
|
||||
{
|
||||
errRect.r_xtop = edgeRight;
|
||||
errRect.r_xbot = edgeLeft;
|
||||
errRect.r_ytop = errRect.r_ybot = edgeY;
|
||||
arg->dCD_cptr = cptr;
|
||||
drcCheckOffGrid(&errRect, arg, cptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
arg->dCD_radial = 0;
|
||||
|
|
|
|||
|
|
@ -197,12 +197,7 @@ DRCCheckThis (celldef, operation, area)
|
|||
* of CellDefs waiting for DRC
|
||||
*/
|
||||
|
||||
/* Ignore internal GDS cells. */
|
||||
/* Note that this rescinds the former behavior of ignoring DRC on */
|
||||
/* vendor and read-only cells. Such cells will be flattened in */
|
||||
/* interaction areas and show errors anyway, so not showing errors */
|
||||
/* in the cell is just confusing. */
|
||||
|
||||
/* Ignore internal cells. */
|
||||
if (celldef->cd_flags & CDINTERNAL) return;
|
||||
|
||||
/* Insert celldef into list of Defs waiting to be checked, unless */
|
||||
|
|
|
|||
|
|
@ -70,6 +70,50 @@ drcCheckAngles(tile, arg, cptr)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* drcCheckOffGrid- checks to see that an edge is on the specified
|
||||
* grid pitch.
|
||||
*
|
||||
* Results: none
|
||||
*
|
||||
* Side Effects: may cause errors to be painted.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
drcCheckOffGrid(edgeRect, arg, cptr)
|
||||
Rect *edgeRect;
|
||||
struct drcClientData *arg;
|
||||
DRCCookie *cptr;
|
||||
{
|
||||
Rect rect;
|
||||
int gtest;
|
||||
|
||||
if (cptr->drcc_dist <= 1) return; /* No error by definition */
|
||||
|
||||
rect = *edgeRect;
|
||||
GeoClip(&rect, arg->dCD_clip);
|
||||
|
||||
/* Expand rect to nearest pitch */
|
||||
gtest = (rect.r_xbot / cptr->drcc_dist) * cptr->drcc_dist;
|
||||
if (gtest < rect.r_xbot) rect.r_xbot = gtest;
|
||||
gtest = (rect.r_xtop / cptr->drcc_dist) * cptr->drcc_dist;
|
||||
if (gtest > rect.r_xtop) rect.r_xtop = gtest;
|
||||
gtest = (rect.r_ybot / cptr->drcc_dist) * cptr->drcc_dist;
|
||||
if (gtest < rect.r_ybot) rect.r_ybot = gtest;
|
||||
gtest = (rect.r_ytop / cptr->drcc_dist) * cptr->drcc_dist;
|
||||
if (gtest > rect.r_ytop) rect.r_ytop = gtest;
|
||||
|
||||
if (!GEO_RECTNULL(&rect)) {
|
||||
(*(arg->dCD_function)) (arg->dCD_celldef, &rect,
|
||||
arg->dCD_cptr, arg->dCD_clientData);
|
||||
(*(arg->dCD_errors))++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -144,10 +188,6 @@ drcCheckArea(starttile,arg,cptr)
|
|||
if (!GEO_RECTNULL(&rect)) {
|
||||
(*(arg->dCD_function)) (arg->dCD_celldef, &rect,
|
||||
arg->dCD_cptr, arg->dCD_clientData);
|
||||
/***
|
||||
DBWAreaChanged(arg->dCD_celldef,&rect, DBW_ALLWINDOWS,
|
||||
&DBAllButSpaceBits);
|
||||
***/
|
||||
(*(arg->dCD_errors))++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -664,7 +664,11 @@ DRCCheck(use, area)
|
|||
SearchContext scx;
|
||||
extern int drcCheckFunc(); /* Forward reference. */
|
||||
|
||||
DBCellReadArea(use, area);
|
||||
if (DBCellReadArea(use, area, TRUE))
|
||||
{
|
||||
TxError("Failure to read in entire subtree of cell.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
scx.scx_use = use;
|
||||
scx.scx_x = use->cu_xlo;
|
||||
|
|
@ -702,8 +706,8 @@ drcCheckFunc(scx, cdarg)
|
|||
|
||||
DRCCheckThis(def, TT_CHECKPAINT, (Rect *) NULL);
|
||||
|
||||
/* New behavior: Don't search children, instead propagate errors up. */
|
||||
/* (void) DBCellSrArea(scx, drcCheckFunc, (ClientData) NULL); */
|
||||
/* Search children */
|
||||
(void) DBCellSrArea(scx, drcCheckFunc, (ClientData) NULL);
|
||||
|
||||
/* As a special performance hack, if the complete cell area is
|
||||
* handled here, don't bother to look at any more array elements.
|
||||
|
|
|
|||
|
|
@ -74,7 +74,22 @@ static DRCCookie drcInSubCookie = {
|
|||
(DRCCookie *) NULL
|
||||
};
|
||||
|
||||
/* The following DRC cookie is used when flattening non-Manhattan
|
||||
* shapes results in a non-integer coordinate. Because the non-
|
||||
* integer coordinate cannot be represented in magic, the position
|
||||
* is flagged as a DRC error.
|
||||
*/
|
||||
|
||||
static DRCCookie drcOffGridCookie = {
|
||||
0, 0, 0, 0,
|
||||
{ 0 }, { 0 },
|
||||
0, 0, 0,
|
||||
DRC_OFFGRID_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
||||
extern int DRCErrorType;
|
||||
extern CellDef *DRCErrorDef;
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
|
|
@ -604,6 +619,37 @@ drcExactOverlapTile(tile, cxp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* DRCOffGridError ---
|
||||
*
|
||||
* Function to call when a call to DBCellCheckCopyAllPaint() flags an error
|
||||
* indicating that a subcell overlap of non-Manhattan geometry resolves to
|
||||
* an off-grid intersection point. Note that this is different from the
|
||||
* DRC off-grid check, which checks for geometry that does not match the
|
||||
* manufacturing grid pitch. This checks for the case of geometry that
|
||||
* is finer than the underlying database grid, which can only happen for
|
||||
* two non-Manhattan shapes interacting between two different cells, and
|
||||
* can only be caught during the process of flattening the cell contents.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Creates a DRC error or prints the DRC error message, depending on
|
||||
* the value of drcSubFunc.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
DRCOffGridError(rect)
|
||||
Rect *rect; /* Area of error */
|
||||
{
|
||||
(*drcSubFunc)(DRCErrorDef, rect, &drcOffGridCookie, drcSubClientData);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -809,7 +855,8 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
savedPaintTable = DBNewPaintTable(DRCCurStyle->DRCPaintTable);
|
||||
savedPaintPlane = DBNewPaintPlane(DBPaintPlaneMark);
|
||||
|
||||
(void) DBCellCopyAllPaint(&scx, &DBAllButSpaceBits, 0, DRCuse);
|
||||
(void) DBCellCheckCopyAllPaint(&scx, &DBAllButSpaceBits, 0,
|
||||
DRCuse, func);
|
||||
|
||||
(void) DBNewPaintTable(savedPaintTable);
|
||||
(void) DBNewPaintPlane(savedPaintPlane);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ static int DRCtag = 0;
|
|||
int drcWidth(), drcSpacing(), drcEdge(), drcNoOverlap();
|
||||
int drcExactOverlap(), drcExtend();
|
||||
int drcSurround(), drcRectOnly(), drcOverhang();
|
||||
int drcStepSize(), drcOption();
|
||||
int drcStepSize(), drcOption(), drcOffGrid();
|
||||
int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles();
|
||||
int drcCifSetStyle(), drcCifWidth(), drcCifSpacing();
|
||||
int drcCifMaxwidth(), drcCifArea();
|
||||
|
|
@ -587,6 +587,11 @@ DRCTechStyleInit()
|
|||
/* (see DRCsubcell.c). */
|
||||
drcWhyCreate("See error definition in the subcell");
|
||||
|
||||
/* Fifth DRC entry is associated with the statically-allocated */
|
||||
/* drcOffGridCookie and has a tag of DRC_OFFGRID_TAG = 5 */
|
||||
/* (see DRCsubcell.c). */
|
||||
drcWhyCreate("This position does not align with the manufacturing grid");
|
||||
|
||||
DRCTechHalo = 0;
|
||||
|
||||
/* Put a dummy rule at the beginning of the rules table for each entry */
|
||||
|
|
@ -922,7 +927,8 @@ drcCifAssign(cookie, dist, next, mask, corner, tag, cdist, flags, planeto, plane
|
|||
int dist, cdist;
|
||||
TileTypeBitMask *mask, *corner;
|
||||
int tag;
|
||||
int flags, planeto, planefrom;
|
||||
unsigned short flags;
|
||||
int planeto, planefrom;
|
||||
{
|
||||
(cookie)->drcc_dist = dist;
|
||||
(cookie)->drcc_next = next;
|
||||
|
|
@ -946,7 +952,8 @@ drcAssign(cookie, dist, next, mask, corner, why, cdist, flags, planeto, planefro
|
|||
int dist, cdist;
|
||||
TileTypeBitMask *mask, *corner;
|
||||
int why;
|
||||
int flags, planeto, planefrom;
|
||||
unsigned short flags;
|
||||
int planeto, planefrom;
|
||||
{
|
||||
/* Diagnostic */
|
||||
if (planeto >= DBNumPlanes)
|
||||
|
|
@ -1040,6 +1047,8 @@ DRCTechAddRule(sectionName, argc, argv)
|
|||
"layers1 width layers2 separation adjacency why",
|
||||
"area", 5, 5, drcArea,
|
||||
"layers area horizon why",
|
||||
"off_grid", 4, 4, drcOffGrid,
|
||||
"layers pitch why",
|
||||
"maxwidth", 4, 5, drcMaxwidth,
|
||||
"layers maxwidth bends why",
|
||||
"cifstyle", 2, 2, drcCifSetStyle,
|
||||
|
|
@ -1434,6 +1443,85 @@ drcArea(argc, argv)
|
|||
return (horizon);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* drcOffGrid --
|
||||
*
|
||||
* Process an off-grid rule.
|
||||
* This is of the form:
|
||||
*
|
||||
* off_grid layers pitch why
|
||||
*
|
||||
* e.g,
|
||||
*
|
||||
* off_grid m1 5 "metal shapes must be on %d grid"
|
||||
*
|
||||
* "pitch" is the grid pitch that shapes must be aligned to.
|
||||
*
|
||||
* Results:
|
||||
* Returns pitch (the halo for detecting off-grid errors).
|
||||
*
|
||||
* Side effects:
|
||||
* Updates the DRC technology variables.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
drcOffGrid(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
char *layers = argv[1];
|
||||
int pitch = atoi(argv[2]);
|
||||
int why = drcWhyCreate(argv[3]);
|
||||
TileTypeBitMask set, setC;
|
||||
DRCCookie *dp, *dpnew;
|
||||
TileType i, j;
|
||||
PlaneMask pset;
|
||||
int plane;
|
||||
|
||||
DBTechNoisyNameMask(layers, &set);
|
||||
TTMaskCom2(&setC, &set);
|
||||
|
||||
for (i = 0; i < DBNumTypes; i++)
|
||||
{
|
||||
for (j = 0; j < DBNumTypes; j++)
|
||||
{
|
||||
if (i == j) continue;
|
||||
/*
|
||||
* Must have types in 'set' for at least 'distance'
|
||||
* to the right of any edge between a type in '~set'
|
||||
* and a type in 'set'.
|
||||
*/
|
||||
if (pset = (DBTypesOnSamePlane(i, j)))
|
||||
{
|
||||
if (TTMaskHasType(&setC, i) && TTMaskHasType(&set, j))
|
||||
{
|
||||
plane = LowestMaskBit(pset);
|
||||
|
||||
/* find bucket preceding the new one we wish to insert */
|
||||
dp = drcFindBucket(i, j, pitch);
|
||||
dpnew = (DRCCookie *) mallocMagic(sizeof (DRCCookie));
|
||||
drcAssign(dpnew, pitch, dp->drcc_next, &set, &set, why,
|
||||
0, DRC_OFFGRID|DRC_FORWARD, plane, plane);
|
||||
dp->drcc_next = dpnew;
|
||||
|
||||
/* opposite edge also needs to be checked */
|
||||
dp = drcFindBucket(j, i, pitch);
|
||||
dpnew = (DRCCookie *) mallocMagic(sizeof (DRCCookie));
|
||||
drcAssign(dpnew, pitch, dp->drcc_next, &set, &set, why,
|
||||
0, DRC_OFFGRID|DRC_REVERSE, plane, plane);
|
||||
dp->drcc_next = dpnew;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (pitch);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
|
|||
30
drc/drc.h
30
drc/drc.h
|
|
@ -48,6 +48,7 @@ typedef struct drccookie
|
|||
#define DRC_OVERLAP_TAG 2
|
||||
#define DRC_SUBCELL_OVERLAP_TAG 3
|
||||
#define DRC_IN_SUBCELL_TAG 4
|
||||
#define DRC_OFFGRID_TAG 5
|
||||
|
||||
/* *This is size "int" because it holds an area for DRC_AREA rules, */
|
||||
/* and therefore may have twice the bit length of a normal rule distance. */
|
||||
|
|
@ -63,20 +64,22 @@ typedef struct drccookie
|
|||
* edge processing.
|
||||
*/
|
||||
|
||||
#define DRC_FORWARD 0x00
|
||||
#define DRC_REVERSE 0x01
|
||||
#define DRC_BOTHCORNERS 0x02
|
||||
#define DRC_TRIGGER 0x04
|
||||
#define DRC_BENDS 0x08
|
||||
#define DRC_OUTSIDE 0x08 // Note: Shared with DRC_BENDS
|
||||
#define DRC_AREA 0x10
|
||||
#define DRC_MAXWIDTH 0x20
|
||||
#define DRC_RECTSIZE 0x40
|
||||
#define DRC_ANGLES 0x80
|
||||
#define DRC_NONSTANDARD (DRC_AREA|DRC_MAXWIDTH|DRC_RECTSIZE|DRC_ANGLES)
|
||||
#define DRC_FORWARD 0x000
|
||||
#define DRC_REVERSE 0x001
|
||||
#define DRC_BOTHCORNERS 0x002
|
||||
#define DRC_TRIGGER 0x004
|
||||
#define DRC_BENDS 0x008
|
||||
#define DRC_OUTSIDE 0x010
|
||||
#define DRC_AREA 0x020
|
||||
#define DRC_OFFGRID 0x040
|
||||
#define DRC_MAXWIDTH 0x080
|
||||
#define DRC_RECTSIZE 0x100
|
||||
#define DRC_ANGLES 0x200
|
||||
#define DRC_NONSTANDARD (DRC_AREA|DRC_MAXWIDTH|DRC_RECTSIZE\
|
||||
|DRC_ANGLES|DRC_OFFGRID)
|
||||
|
||||
/* More flags for indicating what the rule type represents */
|
||||
#define DRC_CIFRULE 0x100
|
||||
#define DRC_CIFRULE 0x400
|
||||
|
||||
#define DRC_PENDING 0
|
||||
#define DRC_UNPROCESSED CLIENTDEFAULT
|
||||
|
|
@ -165,7 +168,7 @@ typedef struct drcstyle
|
|||
int DRCScaleFactorD; /* Multiply dist by this to get magic units */
|
||||
int DRCTechHalo; /* largest action distance of design rules */
|
||||
int DRCStepSize; /* chunk size for decomposing large areas */
|
||||
char DRCFlags; /* Option flags */
|
||||
unsigned short DRCFlags; /* Option flags */
|
||||
char **DRCWhyList; /* Indexed list of "why" text strings */
|
||||
int DRCWhySize; /* Length of DRCWhyList */
|
||||
PaintResultType DRCPaintTable[NP][NT][NT];
|
||||
|
|
@ -271,6 +274,7 @@ extern int DRCFind();
|
|||
extern void DRCCatchUp();
|
||||
extern bool DRCFindInteractions();
|
||||
extern int DRCBasicCheck();
|
||||
extern void DRCOffGridError();
|
||||
|
||||
extern void DRCPrintStyle();
|
||||
extern void DRCSetStyle();
|
||||
|
|
|
|||
|
|
@ -350,6 +350,13 @@ esOutputHierResistor(hc, dev, scale, term1, term2, has_model, l, w, dscale)
|
|||
/* term1=gate term2=source by the above code. */
|
||||
/* extracted units are Ohms; output is in Ohms */
|
||||
|
||||
if ((term1->dterm_node == NULL) || (term2->dterm_node == NULL))
|
||||
{
|
||||
TxError("Error: Resistor %s missing terminal node!\n",
|
||||
EFDevTypes[dev->dev_type]);
|
||||
return;
|
||||
}
|
||||
|
||||
spcdevOutNode(hc->hc_hierName, term1->dterm_node->efnode_name->efnn_hier,
|
||||
"res_top", esSpiceF);
|
||||
spcdevOutNode(hc->hc_hierName, term2->dterm_node->efnode_name->efnn_hier,
|
||||
|
|
@ -405,6 +412,7 @@ subcktHierVisit(use, hierName, is_top)
|
|||
EFNode *snode;
|
||||
EFNodeName *nodeName;
|
||||
bool hasports = FALSE;
|
||||
bool isStub;
|
||||
|
||||
/* Avoid generating records for circuits that have no ports. */
|
||||
/* These are already absorbed into the parent. All other */
|
||||
|
|
@ -431,6 +439,13 @@ subcktHierVisit(use, hierName, is_top)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Same considerations as at line 1831 for determining if the cell */
|
||||
/* has been folded into the parent and should not be output. */
|
||||
|
||||
isStub = ((def->def_flags & DEF_ABSTRACT) && esDoBlackBox) ? TRUE : FALSE;
|
||||
if ((!is_top) && (def->def_flags & DEF_NODEVICES) && (!isStub))
|
||||
return 0;
|
||||
|
||||
if (hasports || is_top)
|
||||
return subcktVisit(use, hierName, is_top);
|
||||
else if (def->def_flags & DEF_NODEVICES)
|
||||
|
|
@ -1557,6 +1572,7 @@ devDistJunctHierVisit(hc, dev, scale)
|
|||
* for each connection to it. Note that this generates an arbitrary
|
||||
* port order for each cell. To have a specific port order, it is
|
||||
* necessary to generate ports for each cell.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -1570,6 +1586,7 @@ esMakePorts(hc, cdata)
|
|||
Use *use;
|
||||
HashEntry *he;
|
||||
EFNodeName *nn;
|
||||
|
||||
char *name, *portname, *tptr, *aptr, *locname;
|
||||
int j;
|
||||
|
||||
|
|
|
|||
|
|
@ -1635,6 +1635,11 @@ subcktUndef(use, hierName, is_top)
|
|||
* subcircuit, and implicit substrate connections should not be
|
||||
* output.
|
||||
*
|
||||
* NOTE: The cookie-cutter method for extraction can result in multiple
|
||||
* connections to the same port if the net spans multiple extraction regions.
|
||||
* Because of this, it is necessary to make sure that the same port name is
|
||||
* not output twice.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -1646,13 +1651,16 @@ topVisit(def, doStub)
|
|||
EFNode *snode, *basenode;
|
||||
EFNodeName *sname, *nodeName;
|
||||
HashSearch hs;
|
||||
HashEntry *he;
|
||||
HashEntry *he, *hep;
|
||||
HashTable portNameTable;
|
||||
int portorder, portmax, tchars;
|
||||
DevParam *plist, *pptr;
|
||||
char *instname;
|
||||
char *subcktname;
|
||||
char *pname;
|
||||
|
||||
HashInit(&portNameTable, 32, HT_STRINGKEYS);
|
||||
|
||||
/* SPICE subcircuit names must begin with A-Z. This will also be */
|
||||
/* enforced when writing X subcircuit calls. */
|
||||
subcktname = def->def_name;
|
||||
|
|
@ -1698,19 +1706,25 @@ topVisit(def, doStub)
|
|||
if (snode->efnode_flags & EF_PORT)
|
||||
{
|
||||
pname = nodeSpiceName(snode->efnode_name->efnn_hier, &basenode);
|
||||
if (basenode->efnode_name->efnn_port < 0)
|
||||
if (HashLookOnly(&portNameTable, pname) == NULL)
|
||||
{
|
||||
if (tchars > 80)
|
||||
hep = HashFind(&portNameTable, pname);
|
||||
if (basenode->efnode_name->efnn_port < 0)
|
||||
{
|
||||
/* Line continuation */
|
||||
fprintf(esSpiceF, "\n+");
|
||||
tchars = 1;
|
||||
if (tchars > 80)
|
||||
{
|
||||
/* Line continuation */
|
||||
fprintf(esSpiceF, "\n+");
|
||||
tchars = 1;
|
||||
}
|
||||
fprintf(esSpiceF, " %s", pname);
|
||||
tchars += strlen(pname) + 1;
|
||||
basenode->efnode_name->efnn_port = portorder++;
|
||||
}
|
||||
fprintf(esSpiceF, " %s", pname);
|
||||
tchars += strlen(pname) + 1;
|
||||
basenode->efnode_name->efnn_port = portorder++;
|
||||
snode->efnode_name->efnn_port = basenode->efnode_name->efnn_port;
|
||||
HashSetValue(hep,
|
||||
(ClientData)(pointertype)snode->efnode_name->efnn_port);
|
||||
}
|
||||
snode->efnode_name->efnn_port = basenode->efnode_name->efnn_port;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1757,8 +1771,24 @@ topVisit(def, doStub)
|
|||
}
|
||||
else
|
||||
pname = nodeSpiceName(snode->efnode_name->efnn_hier, NULL);
|
||||
fprintf(esSpiceF, " %s", pname);
|
||||
tchars += strlen(pname) + 1;
|
||||
|
||||
if (HashLookOnly(&portNameTable, pname) == NULL)
|
||||
{
|
||||
hep = HashFind(&portNameTable, pname);
|
||||
HashSetValue(hep,
|
||||
(ClientData)(pointertype)nodeName->efnn_port);
|
||||
fprintf(esSpiceF, " %s", pname);
|
||||
tchars += strlen(pname) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Node that was unassigned has been found to be
|
||||
// a repeat (see NOTE at top), so make sure its
|
||||
// port number is set correctly.
|
||||
|
||||
hep = HashFind(&portNameTable, pname);
|
||||
nodeName->efnn_port = (int)(pointertype)HashGetValue(hep);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (portidx < 0)
|
||||
|
|
@ -1779,6 +1809,7 @@ topVisit(def, doStub)
|
|||
portorder++;
|
||||
}
|
||||
}
|
||||
HashKill(&portNameTable);
|
||||
|
||||
/* Add all implicitly-defined local substrate node names */
|
||||
|
||||
|
|
|
|||
|
|
@ -397,6 +397,7 @@ efHierDevKilled(hc, dev, prefix)
|
|||
|
||||
for (n = 0; n < dev->dev_nterm; n++)
|
||||
{
|
||||
if (dev->dev_terms[n].dterm_node == NULL) continue;
|
||||
suffix = dev->dev_terms[n].dterm_node->efnode_name->efnn_hier;
|
||||
he = HashLookOnly(&efNodeHashTable, (char *)suffix);
|
||||
if (he && (nn = (EFNodeName *) HashGetValue(he))
|
||||
|
|
|
|||
|
|
@ -286,6 +286,7 @@ extern Def *EFRootDef();
|
|||
/* HierName manipulation */
|
||||
extern HierName *efHNFromUse();
|
||||
extern char *efHNToStrFunc();
|
||||
extern bool EFHNBest();
|
||||
|
||||
/* Functions for hashing of HierNames */
|
||||
extern int efHNCompare();
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ bool efDevKilled();
|
|||
* (*subProc)(use, hierName, is_top)
|
||||
* Use *use;
|
||||
* HierName *hierName;
|
||||
* Boolean is_top;
|
||||
* bool is_top;
|
||||
* {
|
||||
* }
|
||||
*
|
||||
|
|
|
|||
|
|
@ -606,7 +606,12 @@ extArrayInterFunc(use, trans, x, y, ha)
|
|||
extHierConnections(ha, extArrayPrimary, oneFlat);
|
||||
|
||||
/* Process substrate connection */
|
||||
extHierSubstrate(ha, use, x, y);
|
||||
if (use->cu_xlo == use->cu_xhi)
|
||||
extHierSubstrate(ha, use, -1, y);
|
||||
else if (use->cu_ylo == use->cu_yhi)
|
||||
extHierSubstrate(ha, use, x, -1);
|
||||
else
|
||||
extHierSubstrate(ha, use, x, y);
|
||||
|
||||
ha->ha_cumFlat.et_nodes = (NodeRegion *) NULL;
|
||||
if (ExtOptions & EXT_DOADJUST)
|
||||
|
|
|
|||
|
|
@ -67,7 +67,8 @@ char *extDevTable[] = {"fet", "mosfet", "asymmetric", "bjt", "devres",
|
|||
* used to compute the resistance of each node. Each is
|
||||
* indexed by sheet resistivity class.
|
||||
*/
|
||||
int extResistPerim[NT], extResistArea[NT];
|
||||
int extResistPerim[NT];
|
||||
dlong extResistArea[NT];
|
||||
|
||||
/*
|
||||
* The following structure is used in extracting transistors.
|
||||
|
|
@ -575,7 +576,8 @@ void
|
|||
extSetResist(reg)
|
||||
NodeRegion *reg;
|
||||
{
|
||||
int n, perim, area;
|
||||
int n, perim;
|
||||
dlong area;
|
||||
float s, fperim, v;
|
||||
|
||||
for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
|
||||
|
|
@ -704,7 +706,7 @@ extOutputNodes(nodeList, outFile)
|
|||
|
||||
/* Output its area and perimeter for each resistivity class */
|
||||
for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
|
||||
fprintf(outFile, " %d %d", reg->nreg_pa[n].pa_area,
|
||||
fprintf(outFile, " %"DLONG_PREFIX"d %d", reg->nreg_pa[n].pa_area,
|
||||
reg->nreg_pa[n].pa_perim);
|
||||
(void) putc('\n', outFile);
|
||||
|
||||
|
|
@ -738,6 +740,139 @@ extOutputNodes(nodeList, outFile)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ---------------------------------------------------------------------
|
||||
*
|
||||
* extSubsName --
|
||||
*
|
||||
* Return the name of the substrate node, if the node belongs to
|
||||
* the substrate region and a global substrate node name has been
|
||||
* specified by the tech file. If the substrate node name is a
|
||||
* Tcl variable name, then perform the variable substitution.
|
||||
*
|
||||
* Results:
|
||||
* Pointer to a character string.
|
||||
*
|
||||
* Side Effects:
|
||||
* None.
|
||||
*
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
extSubsName(node)
|
||||
LabRegion *node;
|
||||
{
|
||||
char *subsName;
|
||||
|
||||
/* If the techfile specifies a global name for the substrate, use */
|
||||
/* that in preference to the default "p_x_y#" name. Use this name */
|
||||
/* only to substitute for nodes with tiles at -(infinity). */
|
||||
|
||||
if (ExtCurStyle->exts_globSubstrateName != NULL)
|
||||
{
|
||||
if (node->lreg_ll.p_x <= (MINFINITY + 3))
|
||||
{
|
||||
if (ExtCurStyle->exts_globSubstrateName[0] == '$' &&
|
||||
ExtCurStyle->exts_globSubstrateName[1] != '$')
|
||||
{
|
||||
// If subsName is a Tcl variable (begins with "$"), make the
|
||||
// variable substitution, if one exists. Ignore double-$.
|
||||
// If the variable is undefined in the interpreter, then
|
||||
// strip the "$" from the front as this is not legal in most
|
||||
// netlist formats.
|
||||
|
||||
char *varsub = (char *)Tcl_GetVar(magicinterp,
|
||||
&ExtCurStyle->exts_globSubstrateName[1],
|
||||
TCL_GLOBAL_ONLY);
|
||||
return (varsub != NULL) ? varsub : ExtCurStyle->exts_globSubstrateName
|
||||
+ 1;
|
||||
}
|
||||
else
|
||||
return ExtCurStyle->exts_globSubstrateName;
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* extMakeNodeNumPrint --
|
||||
*
|
||||
* Construct a node name from the plane number "plane" and lower left Point
|
||||
* "coord", and place it in the string "buf" (which must be large enough).
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side Effects:
|
||||
* Fills in string "buf".
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
extMakeNodeNumPrint(buf, lreg)
|
||||
char *buf;
|
||||
LabRegion *lreg;
|
||||
{
|
||||
int plane = lreg->lreg_pnum;
|
||||
Point *p = &lreg->lreg_ll;
|
||||
char *subsName;
|
||||
|
||||
subsName = extSubsName(lreg);
|
||||
if (subsName != NULL)
|
||||
strcpy(buf, subsName);
|
||||
else
|
||||
sprintf(buf, "%s_%s%d_%s%d#",
|
||||
DBPlaneShortName(plane),
|
||||
(p->p_x < 0) ? "n": "", abs(p->p_x),
|
||||
(p->p_y < 0) ? "n": "", abs(p->p_y));
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* extNodeName --
|
||||
*
|
||||
* Given a pointer to a LabRegion, return a pointer to a string
|
||||
* that can be printed as the name of the node. If the LabRegion
|
||||
* has a list of attached labels, use one of the labels; otherwise,
|
||||
* use its node number.
|
||||
*
|
||||
* Results:
|
||||
* Returns a pointer to a string. If the node had a label, this
|
||||
* is a pointer to the lab_text field of the first label on the
|
||||
* label list for the node; otherwise, it is a pointer to a static
|
||||
* buffer into which we have printed the node number.
|
||||
*
|
||||
* Side effects:
|
||||
* May overwrite the static buffer used to hold the printable
|
||||
* version of a node number.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
extNodeName(node)
|
||||
LabRegion *node;
|
||||
{
|
||||
static char namebuf[256]; /* Big enough to hold a generated nodename */
|
||||
LabelList *ll;
|
||||
|
||||
if (node == (LabRegion *) NULL || SigInterruptPending)
|
||||
return ("(none)");
|
||||
|
||||
for (ll = node->lreg_labels; ll; ll = ll->ll_next)
|
||||
if (extLabType(ll->ll_label->lab_text, LABTYPE_NAME))
|
||||
return (ll->ll_label->lab_text);
|
||||
|
||||
extMakeNodeNumPrint(namebuf, node);
|
||||
return (namebuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -805,8 +940,7 @@ extFindDuplicateLabels(def, nreg)
|
|||
{
|
||||
r.r_ll = r.r_ur = ll2->ll_label->lab_rect.r_ll;
|
||||
r.r_xbot--, r.r_ybot--, r.r_xtop++, r.r_ytop++;
|
||||
extMakeNodeNumPrint(name,
|
||||
np2->nreg_pnum, np2->nreg_ll);
|
||||
extMakeNodeNumPrint(name, np2);
|
||||
(void) sprintf(message, badmesg, text, name);
|
||||
DBWFeedbackAdd(&r, message, def,
|
||||
1, STYLE_PALEHIGHLIGHTS);
|
||||
|
|
@ -825,69 +959,6 @@ extFindDuplicateLabels(def, nreg)
|
|||
HashKill(&labelHash);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* extNodeName --
|
||||
*
|
||||
* Given a pointer to a LabRegion, return a pointer to a string
|
||||
* that can be printed as the name of the node. If the LabRegion
|
||||
* has a list of attached labels, use one of the labels; otherwise,
|
||||
* use its node number.
|
||||
*
|
||||
* Results:
|
||||
* Returns a pointer to a string. If the node had a label, this
|
||||
* is a pointer to the lab_text field of the first label on the
|
||||
* label list for the node; otherwise, it is a pointer to a static
|
||||
* buffer into which we have printed the node number.
|
||||
*
|
||||
* Side effects:
|
||||
* May overwrite the static buffer used to hold the printable
|
||||
* version of a node number.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
extNodeName(node)
|
||||
LabRegion *node;
|
||||
{
|
||||
static char namebuf[256]; /* Big enough to hold a generated nodename */
|
||||
LabelList *ll;
|
||||
|
||||
if (node == (LabRegion *) NULL || SigInterruptPending)
|
||||
return ("(none)");
|
||||
|
||||
for (ll = node->lreg_labels; ll; ll = ll->ll_next)
|
||||
if (extLabType(ll->ll_label->lab_text, LABTYPE_NAME))
|
||||
return (ll->ll_label->lab_text);
|
||||
|
||||
/* If the techfile specifies a global name for the substrate, use */
|
||||
/* that in preference to the default "p_x_y#" name. */
|
||||
|
||||
if (((NodeRegion *)node == glob_subsnode) || ((NodeRegion *)node == temp_subsnode))
|
||||
{
|
||||
if (ExtCurStyle->exts_globSubstrateName != NULL)
|
||||
{
|
||||
if (ExtCurStyle->exts_globSubstrateName[0] == '$' &&
|
||||
ExtCurStyle->exts_globSubstrateName[1] != '$')
|
||||
{
|
||||
// If subsName is a Tcl variable (begins with "$"), make the
|
||||
// variable substitution, if one exists. Ignore double-$.
|
||||
|
||||
char *varsub = (char *)Tcl_GetVar(magicinterp,
|
||||
&ExtCurStyle->exts_globSubstrateName[1],
|
||||
TCL_GLOBAL_ONLY);
|
||||
return (varsub != NULL) ? varsub : ExtCurStyle->exts_globSubstrateName;
|
||||
}
|
||||
else
|
||||
return ExtCurStyle->exts_globSubstrateName;
|
||||
}
|
||||
}
|
||||
extMakeNodeNumPrint(namebuf, node->lreg_pnum, node->lreg_ll);
|
||||
return (namebuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* ---------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -1730,10 +1801,6 @@ extOutputDevices(def, transList, outFile)
|
|||
if (TTMaskIsZero(tmask)) {
|
||||
if (termcount < nsd) {
|
||||
ExtDevice *devcheck;
|
||||
/* See if there is another matching device record with */
|
||||
/* a different number of terminals, and try again. */
|
||||
devcheck = extDevFindMatch(devptr, t);
|
||||
if (devcheck != NULL) devptr = devcheck;
|
||||
|
||||
/* Not finding another device record just means that */
|
||||
/* terminals are tied together on the same net, such as */
|
||||
|
|
@ -1741,11 +1808,37 @@ extOutputDevices(def, transList, outFile)
|
|||
}
|
||||
break; /* End of SD terminals */
|
||||
}
|
||||
else if (!TTMaskIntersect(tmask, &DBPlaneTypes[reg->treg_pnum]))
|
||||
else if (!TTMaskIntersect(tmask, &DBPlaneTypes[reg->treg_pnum])
|
||||
|| (TTMaskHasType(tmask, TT_SPACE)))
|
||||
{
|
||||
node = NULL;
|
||||
|
||||
/* First try to find a region under the device */
|
||||
extTransFindSubs(reg->treg_tile, t, tmask, def, &node, NULL);
|
||||
if (node == NULL) {
|
||||
|
||||
if ((node == NULL) && (TTMaskHasType(tmask, TT_SPACE))) {
|
||||
/* Device node is possibly the substrate. But: Note */
|
||||
/* that TT_SPACE in the mask covers all planes, and it */
|
||||
/* is not possible to specify TT_SPACE in a single */
|
||||
/* plane. So it is necessary to check for any */
|
||||
/* shielding types that block the substrate. */
|
||||
|
||||
if (!TTMaskIsZero(&ExtCurStyle->exts_globSubstrateShieldTypes))
|
||||
{
|
||||
extTransFindSubs(reg->treg_tile, t,
|
||||
&ExtCurStyle->exts_globSubstrateShieldTypes,
|
||||
def, &node, NULL);
|
||||
}
|
||||
if ((glob_subsnode == NULL) || (node != NULL)) {
|
||||
/* See if there is another matching device record */
|
||||
/* with a different terminal type, and try again. */
|
||||
devptr = extDevFindMatch(devptr, t);
|
||||
break;
|
||||
}
|
||||
else if ((node == NULL) && (glob_subsnode != NULL))
|
||||
node = glob_subsnode;
|
||||
}
|
||||
else if (node == NULL) {
|
||||
/* See if there is another matching device record */
|
||||
/* with a different terminal type, and try again. */
|
||||
devptr = extDevFindMatch(devptr, t);
|
||||
|
|
@ -1754,17 +1847,6 @@ extOutputDevices(def, transList, outFile)
|
|||
extTransRec.tr_devmatch |= (MATCH_TERM << termcount);
|
||||
extTransRec.tr_termnode[termcount] = node;
|
||||
}
|
||||
else if (TTMaskHasType(tmask, TT_SPACE)) {
|
||||
/* Device node is specified as being the substrate */
|
||||
if (glob_subsnode == NULL) {
|
||||
/* See if there is another matching device record */
|
||||
/* with a different terminal type, and try again. */
|
||||
devptr = extDevFindMatch(devptr, t);
|
||||
break;
|
||||
}
|
||||
extTransRec.tr_devmatch |= (MATCH_TERM << termcount);
|
||||
extTransRec.tr_termnode[termcount] = glob_subsnode;
|
||||
}
|
||||
else {
|
||||
/* Determine if there is another matching device record */
|
||||
/* that has fewer required terminals. */
|
||||
|
|
@ -3093,8 +3175,9 @@ extSpecialPerimFunc(bp, sense)
|
|||
break;
|
||||
if (thisterm >= extTransRec.tr_nterm)
|
||||
{
|
||||
if (toutside == TT_SPACE)
|
||||
TxError("Internal Error in Transistor Perimeter Boundary Search!\n");
|
||||
/* This is not necessarily an error; e.g., happens for */
|
||||
/* a device like a diode with TT_SPACE in the source/ */
|
||||
/* drain list. */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -3759,7 +3842,8 @@ extNodeAreaFunc(tile, arg)
|
|||
Tile *tile;
|
||||
FindRegion *arg;
|
||||
{
|
||||
int tilePlaneNum, pNum, len, area, resistClass, n, nclasses;
|
||||
int tilePlaneNum, pNum, len, resistClass, n, nclasses;
|
||||
dlong area;
|
||||
PlaneMask pMask;
|
||||
CapValue capval;
|
||||
TileTypeBitMask *mask, *resMask;
|
||||
|
|
@ -3855,9 +3939,9 @@ extNodeAreaFunc(tile, arg)
|
|||
{
|
||||
TITORECT(tile, &r);
|
||||
GEOCLIP(&r, extNodeClipArea);
|
||||
area = (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot);
|
||||
area = (dlong)(r.r_xtop - r.r_xbot) * (dlong)(r.r_ytop - r.r_ybot);
|
||||
}
|
||||
else area = TILEAREA(tile);
|
||||
else area = (dlong)(TOP(tile) - BOTTOM(tile)) * (dlong)(RIGHT(tile) - LEFT(tile));
|
||||
|
||||
if (IsSplit(tile)) area /= 2; /* Split tiles are 1/2 area! */
|
||||
|
||||
|
|
|
|||
|
|
@ -406,22 +406,7 @@ extHardGenerateLabel(scx, reg, arg)
|
|||
Rect r;
|
||||
Point p;
|
||||
|
||||
// Modification 9/9/2014 by Tim:
|
||||
// Convert the treg_ll value up to top-level coordinates.
|
||||
// Otherwise you end up with a node that is apparently in
|
||||
// "canonical coordinates", but if you try to find the
|
||||
// location of the node using the name, you'll end up in
|
||||
// a random place. It also allows the low-probability
|
||||
// but possible conflict between this node and another with
|
||||
// the same name in the parent cell.
|
||||
//
|
||||
// Reverted 10/30/2014: Apparently this causes worse
|
||||
// problems.
|
||||
//
|
||||
// GeoTransPoint(&scx->scx_trans, ®->treg_ll, &r.r_ll);
|
||||
// extMakeNodeNumPrint(gen, reg->treg_pnum, r.r_ll);
|
||||
|
||||
extMakeNodeNumPrint(gen, reg->treg_pnum, reg->treg_ll);
|
||||
extMakeNodeNumPrint(gen, (LabRegion *)reg);
|
||||
|
||||
prefixlen = tpath->tp_next - tpath->tp_first;
|
||||
len = strlen(gen) + prefixlen;
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ extern FILE *extFileOpen();
|
|||
/*
|
||||
* See extract.h for the bit flags that may be set in the following.
|
||||
* If any are set, the corresponding warnings get generated, leaving
|
||||
* feedback messages. If this word is zero, only fatal errors are
|
||||
* feedback messages. If this word is zero, only errors are
|
||||
* reported.
|
||||
*/
|
||||
int ExtDoWarn = EXTWARN_DUP|EXTWARN_FETS;
|
||||
|
|
@ -179,7 +179,11 @@ ExtAll(rootUse)
|
|||
CellUse *rootUse;
|
||||
{
|
||||
/* Make sure the entire subtree is read in */
|
||||
DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox);
|
||||
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
|
||||
{
|
||||
TxError("Failure to read entire subtree of cell.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fix up bounding boxes if they've changed */
|
||||
DBFixMismatch();
|
||||
|
|
@ -264,7 +268,11 @@ ExtUnique(rootUse, option)
|
|||
int nwarn;
|
||||
|
||||
/* Make sure the entire subtree is read in */
|
||||
DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox);
|
||||
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
|
||||
{
|
||||
TxError("Failure to read entire subtree of cell.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fix up bounding boxes if they've changed */
|
||||
DBFixMismatch();
|
||||
|
|
@ -526,7 +534,11 @@ ExtIncremental(rootUse)
|
|||
CellUse *rootUse;
|
||||
{
|
||||
/* Make sure the entire subtree is read in */
|
||||
DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox);
|
||||
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
|
||||
{
|
||||
TxError("Failure to read entire subtree of cell.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fix up bounding boxes if they've changed */
|
||||
DBFixMismatch();
|
||||
|
|
@ -663,7 +675,7 @@ extExtractStack(stack, doExtract, rootDef)
|
|||
else
|
||||
{
|
||||
if (fatal > 0)
|
||||
TxError("Total of %d fatal error%s.\n",
|
||||
TxError("Total of %d error%s (check feedback entries).\n",
|
||||
fatal, fatal != 1 ? "s" : "");
|
||||
if (warnings > 0)
|
||||
TxError("Total of %d warning%s.\n",
|
||||
|
|
|
|||
|
|
@ -2202,10 +2202,13 @@ ExtTechLine(sectionName, argc, argv)
|
|||
termtypes[1] = DBZeroTypeBits; /* Make it symmetric */
|
||||
else if (!TTMaskIsZero(&termtypes[2]))
|
||||
{
|
||||
class = DEV_ASYMMETRIC;
|
||||
TechError("Device mosfet %s has overlapping drain"
|
||||
" and source types!\n", transName);
|
||||
/* Should this device be disabled? */
|
||||
}
|
||||
else
|
||||
class = DEV_ASYMMETRIC;
|
||||
termtypes[2] = DBZeroTypeBits;
|
||||
if (strcmp(argv[6], "None"))
|
||||
DBTechNoisyNameMask(argv[6], &subsTypes); /* substrate */
|
||||
|
|
@ -2213,7 +2216,6 @@ ExtTechLine(sectionName, argc, argv)
|
|||
if (argc > 8) gscap = aToCap(argv[8]);
|
||||
if (argc > 9) gccap = aToCap(argv[9]);
|
||||
nterm = 2;
|
||||
class = DEV_ASYMMETRIC;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -169,7 +169,11 @@ ExtTimes(rootUse, f)
|
|||
HashEntry *he;
|
||||
|
||||
/* Make sure this cell is read in */
|
||||
DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox);
|
||||
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
|
||||
{
|
||||
TxError("Failure to read entire subtree of cell.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize cumulative statistics */
|
||||
extCumInit(&cumFetsPerSecPaint);
|
||||
|
|
@ -1020,7 +1024,11 @@ ExtInterCount(rootUse, halo, f)
|
|||
double inter;
|
||||
|
||||
/* Make sure this cell is read in */
|
||||
DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox);
|
||||
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
|
||||
{
|
||||
TxError("Failure to read entire subtree of cell.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize cumulative statistics */
|
||||
extCumInit(&cumPercentInteraction);
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ extMakeUnique(def, ll, lreg, lregList, labelHash, option)
|
|||
int nsuffix, nwarn;
|
||||
Label saveLab, *lab;
|
||||
Rect r;
|
||||
int flags;
|
||||
|
||||
/*
|
||||
* Make a pass through all labels for all nodes.
|
||||
|
|
@ -207,7 +208,7 @@ extMakeUnique(def, ll, lreg, lregList, labelHash, option)
|
|||
nwarn++;
|
||||
r.r_ll = r.r_ur = ll2->ll_label->lab_rect.r_ll;
|
||||
GEO_EXPAND(&r, 1, &r);
|
||||
extMakeNodeNumPrint(name, lp2->lreg_pnum, lp2->lreg_ll);
|
||||
extMakeNodeNumPrint(name, lp2);
|
||||
(void) sprintf(message, badmesg, text, name);
|
||||
DBWFeedbackAdd(&r, message, def, 1, STYLE_MEDIUMHIGHLIGHTS);
|
||||
}
|
||||
|
|
@ -258,13 +259,32 @@ makeUnique:
|
|||
nsuffix++;
|
||||
}
|
||||
|
||||
/* If the label is a port, then the port needs a unique ID */
|
||||
/* for the unique name. */
|
||||
|
||||
flags = ll2->ll_label->lab_flags;
|
||||
if (flags & PORT_DIR_MASK) {
|
||||
int idx;
|
||||
int portno = -1;
|
||||
/* Find the last port index used in the cell def */
|
||||
for (lab = def->cd_labels; lab != NULL; lab = lab->lab_next)
|
||||
{
|
||||
idx = lab->lab_flags & PORT_NUM_MASK;
|
||||
if (idx > portno) portno = idx;
|
||||
}
|
||||
portno++;
|
||||
flags &= ~PORT_NUM_MASK;
|
||||
flags |= portno;
|
||||
}
|
||||
|
||||
lab = ll2->ll_label;
|
||||
saveLab = *lab;
|
||||
|
||||
DBRemoveLabel(def, lab);
|
||||
(void) DBPutFontLabel(def, &saveLab.lab_rect,
|
||||
saveLab.lab_font, saveLab.lab_size, saveLab.lab_rotate,
|
||||
&saveLab.lab_offset, saveLab.lab_just, name2,
|
||||
saveLab.lab_type, saveLab.lab_flags);
|
||||
saveLab.lab_type, flags);
|
||||
ll2->ll_label = (Label *) NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ typedef struct lreg
|
|||
typedef struct
|
||||
{
|
||||
int pa_perim;
|
||||
int pa_area;
|
||||
dlong pa_area;
|
||||
} PerimArea;
|
||||
|
||||
typedef struct nreg
|
||||
|
|
@ -239,28 +239,6 @@ typedef struct {
|
|||
CapValue subcap_adjust;
|
||||
} SubCapAdjust;
|
||||
|
||||
/*
|
||||
* The following constructs a node name from the plane number 'n'
|
||||
* and lower left Point l, and places it in the string 's' (which must
|
||||
* be large enough).
|
||||
*/
|
||||
#define extMakeNodeNumPrint(buf, plane, coord) \
|
||||
(void) sprintf((buf), "%s_%s%d_%s%d#", DBPlaneShortName(plane), \
|
||||
((coord).p_x < 0) ? "n": "", abs((coord).p_x), \
|
||||
((coord).p_y < 0) ? "n": "", abs((coord).p_y))
|
||||
|
||||
/* Old way: cryptic numbers, but a bit shorter
|
||||
*
|
||||
* #define extMakeNodeNumPrint(s, n, l) \
|
||||
* (void) sprintf((s), "%d_%d_%d#", (n), extCoord((l).p_x), extCoord((l).p_y))
|
||||
*
|
||||
* The following is used to map the full coordinate space into
|
||||
* the positive integers, for constructing internally generated
|
||||
* node names.
|
||||
*
|
||||
* #define extCoord(x) (((x) < 0) ? (1 - ((x) << 1)) : ((x) << 1))
|
||||
*/
|
||||
|
||||
/*
|
||||
* Argument passed to filter functions for finding regions.
|
||||
*/
|
||||
|
|
@ -1076,6 +1054,7 @@ extern NodeRegion *extFindNodes();
|
|||
extern ExtTree *extHierNewOne();
|
||||
extern int extNbrPushFunc();
|
||||
extern TileType extGetDevType();
|
||||
extern void extMakeNodeNumPrint();
|
||||
|
||||
/* --------------------- Miscellaneous globals ------------------------ */
|
||||
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ GAGenChans(chanType, area, f)
|
|||
Rect *area;
|
||||
FILE *f;
|
||||
{
|
||||
extern void DBPaintPlane0(), DBPaintPlaneVert();
|
||||
extern int DBPaintPlane0(), DBPaintPlaneVert();
|
||||
int gaSplitFunc(), gaSplitOut();
|
||||
static CellDef *genDef = (CellDef *) NULL;
|
||||
static CellUse *genUse = (CellUse *) NULL;
|
||||
|
|
@ -201,7 +201,7 @@ GAGenChans(chanType, area, f)
|
|||
}
|
||||
|
||||
/* Make sure everything in 'area' is read */
|
||||
(void) DBCellReadArea(EditCellUse, area);
|
||||
(void) DBCellReadArea(EditCellUse, area, FALSE);
|
||||
DBFixMismatch();
|
||||
|
||||
/* Start with a clean slate */
|
||||
|
|
|
|||
|
|
@ -281,5 +281,8 @@ nullSetDisplay(dispType, outFileName, mouseFileName)
|
|||
GrScreenRect.r_xtop = 511;
|
||||
GrScreenRect.r_ytop = 483;
|
||||
|
||||
/* Set GrDisplayStatus to force graphics updates to be suspended */
|
||||
GrDisplayStatus = DISPLAY_SUSPEND;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -527,6 +527,7 @@ GrTkInit(dispType)
|
|||
TxPrintf("None of TrueColor 15, 16 or 24, or PseudoColor 8 found. "
|
||||
"Cannot initialize DISPLAY %s\n", getenv("DISPLAY"));
|
||||
XFree(grvisual_get);
|
||||
GrClosePtr = NULL;
|
||||
MainExit(1);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -683,7 +683,7 @@ DefReadNets(f, rootDef, sname, oscale, special, dolabels, total)
|
|||
NULL
|
||||
};
|
||||
|
||||
defLayerMap = defMakeInverseLayerMap();
|
||||
defLayerMap = defMakeInverseLayerMap(LAYER_MAP_VIAS);
|
||||
|
||||
while ((token = LefNextToken(f, TRUE)) != NULL)
|
||||
{
|
||||
|
|
@ -942,6 +942,7 @@ DefReadPins(f, rootDef, sname, oscale, total)
|
|||
int keyword, subkey, values, flags;
|
||||
int processed = 0;
|
||||
int pinDir = PORT_CLASS_DEFAULT;
|
||||
int pinUse = PORT_USE_DEFAULT;
|
||||
int pinNum = 0;
|
||||
TileType curlayer = -1;
|
||||
Rect *currect, topRect;
|
||||
|
|
@ -978,6 +979,19 @@ DefReadPins(f, rootDef, sname, oscale, total)
|
|||
NULL
|
||||
};
|
||||
|
||||
static char *pin_uses[] = {
|
||||
"DEFAULT",
|
||||
"SIGNAL",
|
||||
"POWER",
|
||||
"GROUND",
|
||||
"CLOCK",
|
||||
"RESET",
|
||||
"ANALOG",
|
||||
"SCAN",
|
||||
"TIEOFF",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int lef_class_to_bitmask[] = {
|
||||
PORT_CLASS_DEFAULT,
|
||||
PORT_CLASS_INPUT,
|
||||
|
|
@ -987,6 +1001,20 @@ DefReadPins(f, rootDef, sname, oscale, total)
|
|||
PORT_CLASS_FEEDTHROUGH
|
||||
};
|
||||
|
||||
static int lef_use_to_bitmask[] = {
|
||||
PORT_USE_DEFAULT,
|
||||
PORT_USE_SIGNAL,
|
||||
PORT_USE_POWER,
|
||||
PORT_USE_GROUND,
|
||||
PORT_USE_CLOCK,
|
||||
PORT_USE_RESET,
|
||||
PORT_USE_ANALOG,
|
||||
PORT_USE_SCAN,
|
||||
PORT_USE_TIEOFF
|
||||
};
|
||||
|
||||
flags = 0;
|
||||
|
||||
while ((token = LefNextToken(f, TRUE)) != NULL)
|
||||
{
|
||||
keyword = Lookup(token, pin_keys);
|
||||
|
|
@ -1058,6 +1086,13 @@ DefReadPins(f, rootDef, sname, oscale, total)
|
|||
hasports = TRUE;
|
||||
break;
|
||||
case DEF_PINS_PROP_USE:
|
||||
token = LefNextToken(f, TRUE);
|
||||
subkey = Lookup(token, pin_uses);
|
||||
if (subkey < 0)
|
||||
LefError(DEF_ERROR, "Unknown pin use \"%s\"\n", token);
|
||||
else
|
||||
pinUse = lef_use_to_bitmask[subkey];
|
||||
break;
|
||||
case DEF_PINS_PROP_NET:
|
||||
/* Get the net name, but ignore it */
|
||||
token = LefNextToken(f, TRUE);
|
||||
|
|
@ -1066,7 +1101,7 @@ DefReadPins(f, rootDef, sname, oscale, total)
|
|||
token = LefNextToken(f, TRUE);
|
||||
subkey = Lookup(token, pin_classes);
|
||||
if (subkey < 0)
|
||||
LefError(DEF_ERROR, "Unknown pin class\n");
|
||||
LefError(DEF_ERROR, "Unknown pin class \"%s\"\n", token);
|
||||
else
|
||||
pinDir = lef_class_to_bitmask[subkey];
|
||||
break;
|
||||
|
|
@ -1086,7 +1121,7 @@ DefReadPins(f, rootDef, sname, oscale, total)
|
|||
GeoTransRect(&t, currect, &topRect);
|
||||
DBPaint(rootDef, &topRect, curlayer);
|
||||
DBPutLabel(rootDef, &topRect, -1, pinname, curlayer,
|
||||
pinNum | pinDir | flags);
|
||||
pinNum | pinDir | pinUse | flags);
|
||||
pending = FALSE;
|
||||
pinNum++;
|
||||
}
|
||||
|
|
@ -1109,7 +1144,7 @@ DefReadPins(f, rootDef, sname, oscale, total)
|
|||
GeoTransRect(&t, currect, &topRect);
|
||||
DBPaint(rootDef, &topRect, curlayer);
|
||||
DBPutLabel(rootDef, &topRect, -1, pinname, curlayer,
|
||||
pinNum | pinDir | flags);
|
||||
pinNum | pinDir | pinUse | flags);
|
||||
pinNum++;
|
||||
}
|
||||
break;
|
||||
|
|
@ -1666,7 +1701,7 @@ enum def_sections {DEF_VERSION = 0, DEF_NAMESCASESENSITIVE,
|
|||
DEF_HISTORY, DEF_DIEAREA, DEF_COMPONENTS, DEF_VIAS,
|
||||
DEF_PINS, DEF_PINPROPERTIES, DEF_SPECIALNETS,
|
||||
DEF_NETS, DEF_IOTIMINGS, DEF_SCANCHAINS,
|
||||
DEF_CONSTRAINTS, DEF_GROUPS, DEF_EXTENSION,
|
||||
DEF_CONSTRAINTS, DEF_GROUPS, DEF_EXTENSION, DEF_BLOCKAGES,
|
||||
DEF_END};
|
||||
|
||||
void
|
||||
|
|
@ -1708,6 +1743,7 @@ DefRead(inName, dolabels)
|
|||
"CONSTRAINTS",
|
||||
"GROUPS",
|
||||
"BEGINEXT",
|
||||
"BLOCKAGES",
|
||||
"END",
|
||||
NULL
|
||||
};
|
||||
|
|
@ -1873,6 +1909,9 @@ DefRead(inName, dolabels)
|
|||
case DEF_EXTENSION:
|
||||
LefSkipSection(f, sections[DEF_EXTENSION]);
|
||||
break;
|
||||
case DEF_BLOCKAGES:
|
||||
LefSkipSection(f, sections[DEF_BLOCKAGES]);
|
||||
break;
|
||||
case DEF_END:
|
||||
if (!LefParseEndStatement(token, "DESIGN"))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1143,7 +1143,8 @@ defNetGeometryFunc(tile, plane, defdata)
|
|||
/* residue of the contact as the route layer */
|
||||
/* type. */
|
||||
|
||||
rName = defGetType((rtype == TT_SPACE) ? r2type : rtype, NULL);
|
||||
rName = defGetType((rtype == TT_SPACE) ? r2type : rtype, NULL,
|
||||
LAYER_MAP_VIAS);
|
||||
|
||||
/* The first layer in a record may not be a via name */
|
||||
|
||||
|
|
@ -1534,9 +1535,10 @@ defCountViaFunc(tile, cviadata)
|
|||
*/
|
||||
|
||||
char *
|
||||
defGetType(ttype, lefptr)
|
||||
defGetType(ttype, lefptr, do_vias)
|
||||
TileType ttype;
|
||||
lefLayer **lefptr;
|
||||
bool do_vias;
|
||||
{
|
||||
HashSearch hs;
|
||||
HashEntry *he;
|
||||
|
|
@ -1552,6 +1554,10 @@ defGetType(ttype, lefptr)
|
|||
while (he = HashNext(&LefInfo, &hs))
|
||||
{
|
||||
lefl = (lefLayer *)HashGetValue(he);
|
||||
if (lefl && (do_vias == FALSE) && (contact == CLASS_VIA) &&
|
||||
(lefl->info.via.lr != NULL))
|
||||
continue; /* Skip VIA definitions if do_vias is FALSE */
|
||||
|
||||
if (lefl && ((contact == lefl->lefClass) ||
|
||||
((contact == CLASS_ROUTE) && (lefl->lefClass == CLASS_MASTER))))
|
||||
if ((lefl->type == ttype) || (lefl->obsType == ttype))
|
||||
|
|
@ -1870,7 +1876,8 @@ defComponentFunc(cellUse, defdata)
|
|||
*/
|
||||
|
||||
LefMapping *
|
||||
defMakeInverseLayerMap()
|
||||
defMakeInverseLayerMap(do_vias)
|
||||
bool do_vias;
|
||||
{
|
||||
LefMapping *lefMagicToLefLayer;
|
||||
lefLayer *lefl;
|
||||
|
|
@ -1882,7 +1889,7 @@ defMakeInverseLayerMap()
|
|||
memset(lefMagicToLefLayer, 0, sizeof(LefMapping) * TT_TECHDEPBASE);
|
||||
for (i = TT_TECHDEPBASE; i < DBNumTypes; i++)
|
||||
{
|
||||
lefname = defGetType(i, &lefl);
|
||||
lefname = defGetType(i, &lefl, do_vias);
|
||||
lefMagicToLefLayer[i].lefName = lefname;
|
||||
lefMagicToLefLayer[i].lefInfo = lefl;
|
||||
}
|
||||
|
|
@ -1969,7 +1976,7 @@ DefWriteCell(def, outName, allSpecial, units)
|
|||
|
||||
defWriteHeader(def, f, scale, units);
|
||||
|
||||
lefMagicToLefLayer = defMakeInverseLayerMap();
|
||||
lefMagicToLefLayer = defMakeInverseLayerMap(LAYER_MAP_VIAS);
|
||||
|
||||
/* Vias---magic contact areas are reported as vias. */
|
||||
total = defCountVias(def, lefMagicToLefLayer, scale);
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ CmdLef(w, cmd)
|
|||
{
|
||||
"read [filename] read a LEF file filename[.lef]\n"
|
||||
" read [filename] -import read a LEF file; import cells from .mag files\n"
|
||||
" read [filename] -annotate read a LEF file for cell annotation only."
|
||||
" read [filename] -annotate read a LEF file for cell annotation only.",
|
||||
"write [filename] [-tech] write LEF for current cell\n"
|
||||
" write [filename] -hide hide all details other than ports\n"
|
||||
" write [filename] -hide <d> hide details in area set back distance <d>",
|
||||
|
|
@ -129,7 +129,7 @@ CmdLef(w, cmd)
|
|||
static char *cmdDefOption[] =
|
||||
{
|
||||
"read [filename] read a DEF file filename[.def]",
|
||||
"write [cell] [-allspecial] write DEF for current or indicated cell\n",
|
||||
"write [cell] [-allspecial] write DEF for current or indicated cell\n"
|
||||
"write -labels label every net in NETS with the net name",
|
||||
"writeall (use \"flatten -nosubckt\" + \"def"
|
||||
" write\" instead)",
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ typedef struct
|
|||
#define DO_SPECIAL 1
|
||||
#define ALL_SPECIAL 2 /* treat all nets as SPECIALNETS */
|
||||
|
||||
/* Used with defMakeInverseLayerMap() */
|
||||
#define LAYER_MAP_NO_VIAS FALSE
|
||||
#define LAYER_MAP_VIAS TRUE
|
||||
|
||||
/* For a linked list of rectangular areas, use the LinkedRect structure */
|
||||
/* defined in utils/geometry.h. */
|
||||
|
||||
|
|
|
|||
|
|
@ -1385,6 +1385,7 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale, is_imported)
|
|||
int pinUse = PORT_USE_DEFAULT;
|
||||
int pinShape = PORT_SHAPE_DEFAULT;
|
||||
Label *firstlab;
|
||||
bool firstport = TRUE;
|
||||
|
||||
static char *pin_keys[] = {
|
||||
"DIRECTION",
|
||||
|
|
@ -1636,13 +1637,14 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale, is_imported)
|
|||
|
||||
if (needRect)
|
||||
{
|
||||
if (lab == NULL)
|
||||
if ((lab == NULL) && (firstport == TRUE))
|
||||
DBEraseLabelsByContent(lefMacro, NULL, -1, testpin);
|
||||
LefReadPort(lefMacro, f, testpin, pinNum, pinDir, pinUse,
|
||||
pinShape, oscale, lab);
|
||||
}
|
||||
else
|
||||
LefSkipSection(f, NULL);
|
||||
firstport = FALSE;
|
||||
}
|
||||
else
|
||||
LefReadPort(lefMacro, f, testpin, pinNum, pinDir, pinUse,
|
||||
|
|
|
|||
|
|
@ -1171,7 +1171,7 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster)
|
|||
|
||||
lc.file = f;
|
||||
lc.oscale = scale;
|
||||
lc.lefMagicMap = defMakeInverseLayerMap();
|
||||
lc.lefMagicMap = defMakeInverseLayerMap(LAYER_MAP_NO_VIAS);
|
||||
lc.lastType = TT_SPACE;
|
||||
lc.lefFlat = lefFlatDef;
|
||||
|
||||
|
|
@ -1674,7 +1674,7 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster)
|
|||
freeMagic(thislll);
|
||||
}
|
||||
|
||||
if (setback > 0)
|
||||
if (setback >= 0)
|
||||
{
|
||||
/* For -hide with setback, yank everything in the area outside */
|
||||
/* the setback. */
|
||||
|
|
@ -1982,7 +1982,11 @@ LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, lefDoMaster, r
|
|||
rootdef = rootUse->cu_def;
|
||||
|
||||
/* Make sure the entire subtree is read in */
|
||||
DBCellReadArea(rootUse, &rootdef->cd_bbox);
|
||||
if (DBCellReadArea(rootUse, &rootdef->cd_bbox, TRUE))
|
||||
{
|
||||
TxError("Could not read entire subtree of the cell.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fix up bounding boxes if they've changed */
|
||||
DBFixMismatch();
|
||||
|
|
|
|||
|
|
@ -167,6 +167,8 @@ macro XK_KP_Prior "move ne 1"
|
|||
# Scroll wheel bindings
|
||||
macro XK_Pointer_Button4 "scroll u .05 w"
|
||||
macro XK_Pointer_Button5 "scroll d .05 w"
|
||||
macro Shift_XK_Pointer_Button4 "scroll l .05 w"
|
||||
macro Shift_XK_Pointer_Button5 "scroll r .05 w"
|
||||
# Quick macro function keys for scmos tech (X11 versions only)
|
||||
macro XK_F1 "paint ndiff"
|
||||
macro XK_F2 "paint pdiff"
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ FILES = mos.7bit.dstyle mos.7bit.std.cmap \
|
|||
mos.7bit.mraster_dstyle mos.7bit.mraster.cmap \
|
||||
mos.OpenGL.dstyle mos.OpenGL.std.cmap
|
||||
TECHFILES = minimum.tech gdsquery.tech scmos.tech scmos-tm.tech \
|
||||
scmos-sub.tech scmosWR.tech
|
||||
scmos-sub.tech scmosWR.tech nmos.tech
|
||||
|
||||
CIFin = cif_template/objs/CIFin
|
||||
CIFout = cif_template/objs/CIFout
|
||||
|
|
@ -87,6 +87,9 @@ minimum.tech: minimum.tech.in
|
|||
gdsquery.tech: gdsquery.tech.in
|
||||
$(SC_PP) gdsquery.tech.in > gdsquery.tech
|
||||
|
||||
nmos.tech: nmos.tech.in
|
||||
$(CP) nmos.tech.in nmos.tech
|
||||
|
||||
$(CIFin):
|
||||
$(CIFout):
|
||||
$(ICIFin):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,473 @@
|
|||
#
|
||||
# nmos.tech --
|
||||
#
|
||||
# Defines the MOSIS 4.0 micron NMOS technology for Magic. Some
|
||||
# of the characteristics of this technology are:
|
||||
#
|
||||
# 1. 1 level of metal.
|
||||
# 2. Buried contacts.
|
||||
# 3. No butting contacts.
|
||||
#
|
||||
# Copyright (C) 1985 Regents of the University of California
|
||||
# All rights reserved.
|
||||
#
|
||||
# sccsid @(#)nmos.tech 3.73 MAGIC (Berkeley) 11/22/85
|
||||
#
|
||||
|
||||
tech
|
||||
format 35
|
||||
nmos
|
||||
end
|
||||
|
||||
version
|
||||
version 0
|
||||
description "MOSIS 4.0 micron NMOS"
|
||||
requires magic-8.3.0
|
||||
end
|
||||
|
||||
planes
|
||||
active,diff,poly_diff
|
||||
metal
|
||||
end
|
||||
|
||||
types
|
||||
active polysilicon,poly,red
|
||||
active diffusion,diff,green
|
||||
metal metal,blue
|
||||
active poly_metal_contact,pmc
|
||||
active diff_metal_contact,dmc
|
||||
active enhancement_fet,efet
|
||||
active depletion_fet,dfet
|
||||
active depletion_capacitor,dcap
|
||||
active buried_contact,bc
|
||||
metal glass_contact,glass
|
||||
end
|
||||
|
||||
styles
|
||||
styletype mos
|
||||
|
||||
polysilicon 1
|
||||
diffusion 2
|
||||
metal 20
|
||||
enhancement_fet 6
|
||||
enhancement_fet 7
|
||||
depletion_fet 6
|
||||
depletion_fet 10
|
||||
depletion_capacitor 6
|
||||
depletion_capacitor 11
|
||||
buried_contact 6
|
||||
buried_contact 33
|
||||
poly_metal_contact 1
|
||||
poly_metal_contact 20
|
||||
poly_metal_contact 32
|
||||
diff_metal_contact 2
|
||||
diff_metal_contact 20
|
||||
diff_metal_contact 32
|
||||
glass_contact 20
|
||||
glass_contact 34
|
||||
|
||||
error_s 42
|
||||
error_p 42
|
||||
error_ps 42
|
||||
|
||||
# Hint layers
|
||||
magnet 39
|
||||
fence 38
|
||||
rotate 37
|
||||
end
|
||||
|
||||
contact
|
||||
pmc poly metal
|
||||
dmc diff metal
|
||||
end
|
||||
|
||||
aliases
|
||||
|
||||
allDiff diff,dmc,bc,efet,dfet,dcap
|
||||
allPoly poly,pmc,bc,efet,dfet,dcap
|
||||
tran efet,dfet
|
||||
allMetal metal,pmc,dmc,glass
|
||||
spP (space,poly,pmc)/a
|
||||
sdD (space,diff,dmc)/a
|
||||
notDmc space,metal,pmc,glass
|
||||
notPmc space,metal,dmc,glass
|
||||
allButFet (space,diff,poly,dmc,pmc,bc)/a
|
||||
allpdTypes (space,diff,poly,dmc,pmc,bc,dfet,dcap,efet)/a
|
||||
|
||||
end
|
||||
|
||||
compose
|
||||
# The following rule allows transistors to be built up of poly and diff */
|
||||
compose efet poly diff
|
||||
|
||||
# The following rules allow poly or diff to be erased from fets or bcs */
|
||||
decompose dfet poly diff
|
||||
decompose dcap poly diff
|
||||
decompose bc poly diff
|
||||
|
||||
# The following lets us erase metal from a glass_contact to get space */
|
||||
erase glass metal space
|
||||
end
|
||||
|
||||
#
|
||||
# Electrical connectivity. Each tile in the group on the left
|
||||
# is considered to be connected to each tile in the group on
|
||||
# the right. Tiles within the groups are not necessarily
|
||||
# connected to each other.
|
||||
#
|
||||
|
||||
connect
|
||||
poly pmc,efet,dfet,dcap,bc
|
||||
diff bc,dmc
|
||||
efet pmc,dmc,bc,dfet,dcap
|
||||
dfet pmc,dmc,bc,dcap
|
||||
dcap pmc,dmc,bc
|
||||
pmc dmc,bc
|
||||
dmc bc
|
||||
metal glass,pmc,dmc
|
||||
glass pmc,dmc
|
||||
end
|
||||
|
||||
# Information used to generate CIF files. The only tricky business
|
||||
# is to merge necks between adjacent implants or buried windows.
|
||||
# The grow-shrink does this. Also, note that labels on Magic layers
|
||||
# get attached to the first CIF layer containing that Magic layer
|
||||
# in an "or" or "bloat-or" statement. This makes order important
|
||||
# (for example, we want transistor labels to attach to the poly gate).
|
||||
#
|
||||
|
||||
cifoutput
|
||||
style lambda=2
|
||||
scalefactor 200 100
|
||||
layer NP poly,pmc,efet,dfet,dcap,bc
|
||||
labels poly,efet,dfet,dcap,bc
|
||||
calma 1 1
|
||||
layer ND diff,dmc,efet,dfet,dcap,bc
|
||||
labels diff
|
||||
calma 2 1
|
||||
layer NM metal,pmc,dmc,glass
|
||||
labels metal,pmc,dmc,glass
|
||||
calma 3 1
|
||||
layer NI
|
||||
bloat-or dfet,dcap * 200 diff,bc 400
|
||||
grow 100
|
||||
shrink 100
|
||||
calma 4 1
|
||||
layer NC dmc
|
||||
squares 400
|
||||
calma 5 1
|
||||
layer NC pmc
|
||||
squares 400
|
||||
calma 6 1
|
||||
layer NG glass
|
||||
calma 7 1
|
||||
layer NB
|
||||
bloat-or bc * 200 diff,dmc 400 dfet 0
|
||||
grow 100
|
||||
shrink 100
|
||||
calma 8 1
|
||||
end
|
||||
|
||||
# Information on how to read CIF files. Read in all the CIF layers,
|
||||
# then perform geometric operations to get the Magic layers. The
|
||||
# order in which the Magic layers are generated is important!
|
||||
#
|
||||
|
||||
cifinput
|
||||
style lambda=2
|
||||
scalefactor 200
|
||||
layer poly NP
|
||||
labels NP
|
||||
layer diff ND
|
||||
labels ND
|
||||
layer metal NM
|
||||
labels NM
|
||||
layer efet NP
|
||||
and ND
|
||||
layer dfet NI
|
||||
and NP
|
||||
and ND
|
||||
layer pmc NC
|
||||
grow 200
|
||||
and NM
|
||||
and NP
|
||||
layer dmc NC
|
||||
grow 200
|
||||
and NM
|
||||
and ND
|
||||
# Buried contacts must be generated after transistors, since they
|
||||
# override transistors.
|
||||
#
|
||||
layer bc NB
|
||||
and NP
|
||||
and ND
|
||||
layer glass NG
|
||||
end
|
||||
|
||||
mzrouter
|
||||
style irouter
|
||||
layer metal 32 32 256 1
|
||||
layer poly 64 64 256 1
|
||||
contact pmc metal poly 1024
|
||||
end
|
||||
|
||||
#
|
||||
# DRC information
|
||||
# Width, spacing and edge rules are "compiled" into rules table entries.
|
||||
#
|
||||
# width: types in the mask, taken collectively, must have the given width
|
||||
#
|
||||
# spacing: types in mask1 must be separated by distance from types in mask2
|
||||
#
|
||||
# edge: explict entries for the rules table --
|
||||
# LHS RHS distance types allowed on RHS corner mask reason
|
||||
#
|
||||
# All combinations of single elements of the LHS and RHS masks
|
||||
# are used to form a rule.
|
||||
#
|
||||
|
||||
drc
|
||||
width allDiff 2 "Diffusion width must be at least 2"
|
||||
width dmc 4 "Metal_diff contact width must be at least 4"
|
||||
width allPoly 2 "Polysilicon width must be at least 2"
|
||||
width pmc 4 "Metal_poly contact width must be at least 4"
|
||||
width bc 2 "Buried contact width must be at least 2"
|
||||
width efet 2 "Enhancement FET width must be at least 2"
|
||||
width dfet 2 "Depletion FET width must be at least 2"
|
||||
width dcap 2 "Depletion capacitor width must be at least 2"
|
||||
width allMetal 3 "Metal width must be at least 3"
|
||||
|
||||
spacing allDiff allDiff 3 touching_ok \
|
||||
"Diff-diff separation must be at least 3"
|
||||
spacing allPoly allPoly 2 touching_ok \
|
||||
"Poly-poly separation must be at least 2"
|
||||
spacing tran pmc,dmc 1 touching_illegal \
|
||||
"Transistor-contact separation must be at least 1"
|
||||
spacing efet dfet,dcap 3 touching_illegal \
|
||||
"Enhancement-depletion transistor separation must be at least 3"
|
||||
spacing allMetal allMetal 3 touching_ok \
|
||||
"Metal-metal separation must be at least 3"
|
||||
#
|
||||
# Diff and poly cannot be adjacent, except at corners where
|
||||
# the intermediate material is "bc", "efet", "dfet", or "dcap".
|
||||
# Thus, there is no need for rules with RHS equal to "Bef".
|
||||
# But corner extension applies if the intermediate material is "s".
|
||||
# For this reason, the first edge rule CANNOT be rewritten as
|
||||
# "edge diff pP 1 0 pP 1".
|
||||
#
|
||||
edge diff spP 1 (space)/a spP 1 \
|
||||
"Diff-poly separation must be at least 1"
|
||||
edge poly sdD 1 (space)/a sdD 1 \
|
||||
"Diff-poly separation must be at least 1"
|
||||
#
|
||||
# Allow dmc and pmc to be adjacent since they are electrically shorted.
|
||||
#
|
||||
edge dmc (space,poly)/a 1 (space)/a (space,poly)/a 1 \
|
||||
"Diff-poly separation must be at least 1"
|
||||
edge pmc (space,diff)/a 1 (space)/a (space,diff)/a 1 \
|
||||
"Diff-poly separation must be at least 1"
|
||||
|
||||
#
|
||||
# Don't let pmc and dmc have convex shapes, since this may interfere
|
||||
# with the via-generation process. The corner check in the rules
|
||||
# below does this. Also don't let contacts overlap between cells
|
||||
# unless they do so exactly.
|
||||
#
|
||||
|
||||
edge4way dmc notDmc 1 notDmc notDmc,dmc 1 \
|
||||
"Diffusion-metal contacts must be rectangular"
|
||||
edge4way pmc notPmc 1 notPmc notPmc,pmc 1 \
|
||||
"Poly-metal contacts must be rectangular"
|
||||
exact_overlap pmc,dmc
|
||||
#
|
||||
# Transistors cannot touch space, except in corners.
|
||||
# The corner mask is set to 0 to prevent checking there.
|
||||
#
|
||||
edge tran (space)/a 1 0 0 0 \
|
||||
"Transistor overhang is missing"
|
||||
edge (space)/a tran 1 0 0 0 \
|
||||
"Transistor overhang is missing"
|
||||
#
|
||||
# Buried contacts must be 3 lambda from efets in all cases,
|
||||
# and 4 lambda in some. Depends on the orientation of the
|
||||
# buried contact implant. The 4x3 corner checks ON BOTH
|
||||
# SIDES solve the problem. Buried contacts may abut
|
||||
# depletion transistors, but only if the transistors are
|
||||
# fairly long (otherwise, a misalignment in the buried
|
||||
# window mask may make a huge difference in the transistor's
|
||||
# effective length).
|
||||
#
|
||||
spacing bc efet 3 touching_illegal \
|
||||
"Buried contact-transistor separation must be at least 3"
|
||||
spacing bc dfet 3 touching_ok \
|
||||
"Buried contact-transistor separation must be at least 3"
|
||||
edge4way bc diff,dmc 4 allButFet allpdTypes 3 \
|
||||
"Buried contact-transistor separation must be at least 4 on diff side"
|
||||
edge4way bc dfet 4 dfet 0 0 \
|
||||
"Transistors next to buried contacts must be at least 4 long"
|
||||
|
||||
#
|
||||
# WARNING: The above rules don't take care of poly approaching
|
||||
# the buried contact on the diffusion side. Unfortunately, the
|
||||
# only fix is a rule that is ridiculously conservative. So
|
||||
# for now, buyer beware!
|
||||
#
|
||||
|
||||
#
|
||||
# 3 by 2 shape of buried contact next to dfet.
|
||||
# No corner check.
|
||||
#
|
||||
edge4way dfet bc 3 bc 0 0 \
|
||||
"Buried contact next to depletion transistor must be at least 3x2"
|
||||
#
|
||||
# Poly and diffusion must overhang transistors by 2.
|
||||
#
|
||||
# Corner checks are necessary for L or S shaped transistors.
|
||||
#
|
||||
# Don't worry about dfet -- buried_contact boundaries here.
|
||||
#
|
||||
edge4way tran poly 2 poly,pmc poly 2 \
|
||||
"Polysilicon must overhang transistor by at least 2"
|
||||
edge4way tran diff 2 diff,dmc diff 2 \
|
||||
"Diffusion must overhang transistor by at least 2"
|
||||
|
||||
# Cannot change transistors as a result of cell overlaps */
|
||||
no_overlap efet,dfet efet,dfet
|
||||
end
|
||||
|
||||
#
|
||||
# Parameters for circuit extraction.
|
||||
# A type may appear both as a node and as a transistor. When it
|
||||
# appears as a node, we are describing the gate, and when it appears
|
||||
# as a transistor, we are describing the channel.
|
||||
#
|
||||
|
||||
extract
|
||||
style default
|
||||
# scale factor: output units (centimicrons) per lambda */
|
||||
lambda 200
|
||||
|
||||
# chunk size for hierarchical extraction, in lambda */
|
||||
step 100
|
||||
|
||||
planeorder active 0
|
||||
planeorder metal 1
|
||||
|
||||
# sheet resistivity milli-ohms per square */
|
||||
resist diff,dmc/poly 10000
|
||||
resist poly,pmc/poly,efet,dfet,bc 30000
|
||||
resist metal,glass 30
|
||||
|
||||
# area capacitance atto-farads/lambda**2 */
|
||||
areacap poly,efet,dfet 200
|
||||
areacap metal,glass 120
|
||||
areacap diff 400
|
||||
areacap bc 600
|
||||
areacap dmc/poly 520
|
||||
areacap pmc/poly 320
|
||||
|
||||
# sidewall capacitance atto-farads/lambda */
|
||||
perimc diff,dmc/poly,bc space,dfet,efet 200
|
||||
|
||||
# transistors terms #terms name substr gs-cap gc-cap */
|
||||
fet efet diff 2 efet GND! 0 0
|
||||
fet dfet diff,bc 2 dfet GND! 0 0
|
||||
fet dcap diff,bc 1 dcap GND! 0 0
|
||||
# End of style "default" */
|
||||
end
|
||||
|
||||
# Information for the wiring interface */
|
||||
wiring
|
||||
contact pmc 4 metal 0 poly 0
|
||||
contact dmc 4 metal 0 diff 0
|
||||
contact bc 2 poly 0 diff 0
|
||||
end
|
||||
|
||||
# Information to control the router */
|
||||
router
|
||||
layer1 metal 3 metal,pmc/metal,dmc/metal,glass 3
|
||||
layer2 poly 2 poly,efet,dfet,dcap,pmc,bc 2 diff,dmc 1
|
||||
contacts pmc 4
|
||||
gridspacing 7
|
||||
end
|
||||
|
||||
# Information for plowing */
|
||||
plowing
|
||||
fixed efet,dfet,dcap,bc,glass
|
||||
covered efet,dfet,dcap,bc
|
||||
drag efet,dfet,dcap,bc
|
||||
end
|
||||
|
||||
plot
|
||||
style versatec
|
||||
|
||||
# Same as Gremlin stipple 9: */
|
||||
dfet,dcap \
|
||||
07c0 0f80 1f00 3e00 \
|
||||
7c00 f800 f001 e003 \
|
||||
c007 800f 001f 003e \
|
||||
00c7 00f8 01f0 03e0
|
||||
|
||||
# Same as Gremlin stipple 10: */
|
||||
efet,dcap \
|
||||
1f00 0f80 07c0 03e0 \
|
||||
01f0 00f8 007c 003e \
|
||||
001f 800f c007 e003 \
|
||||
f001 f800 7c00 3e00
|
||||
|
||||
# Same as Gremlin stipple 11: */
|
||||
bc \
|
||||
c3c3 c3c3 0000 0000 \
|
||||
0000 0000 c3c3 c3c3 \
|
||||
c3c3 c3c3 0000 0000 \
|
||||
0000 0000 c3c3 c3c3
|
||||
|
||||
# Same as Gremlin stipple 12: */
|
||||
glass \
|
||||
0040 0080 0100 0200 \
|
||||
0400 0800 1000 2000 \
|
||||
4000 8000 0001 0002 \
|
||||
0004 0008 0010 0020
|
||||
|
||||
# Same as Gremlin stipple 17: */
|
||||
diff,dmc/active,efet,dfet,dcap,bc \
|
||||
0000 4242 6666 0000 \
|
||||
0000 2424 6666 0000 \
|
||||
0000 4242 6666 0000 \
|
||||
0000 2424 6666 0000
|
||||
|
||||
# Same as Gremlin stipple 19: */
|
||||
poly,pmc/active,efet,dfet,dcap,bc \
|
||||
0808 0400 0202 0101 \
|
||||
8080 4000 2020 1010 \
|
||||
0808 0004 0202 0101 \
|
||||
8080 0040 2020 1010
|
||||
|
||||
# Same as Gremlin stipple 22: */
|
||||
metal,dmc/metal,pmc/metal,glass \
|
||||
8080 0000 0000 0000 \
|
||||
0808 0000 0000 0000 \
|
||||
8080 0000 0000 0000 \
|
||||
0808 0000 0000 0000
|
||||
|
||||
# Same as Gremlin stipple 23: */
|
||||
glass \
|
||||
0000 0000 1c1c 3e3e \
|
||||
3636 3e3e 1c1c 0000 \
|
||||
0000 0000 1c1c 3e3e \
|
||||
3636 3e3e 1c1c 0000
|
||||
|
||||
pmc,dmc X
|
||||
bc B
|
||||
|
||||
style gremlin
|
||||
dfet,dcap 9
|
||||
efet,dcap 10
|
||||
bc 11
|
||||
glass 12
|
||||
diff,dmc/active,efet,dfet,dcap,bc 17
|
||||
poly,pmc/active,efet,dfet,dcap,bc 19
|
||||
metal,dmc,pmc,glass 22
|
||||
pmc,dmc X
|
||||
bc B
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -626,8 +626,6 @@ INSTALL_TARGET
|
|||
ALL_TARGET
|
||||
OA_LIBS
|
||||
OA
|
||||
MAGIC_REVISION
|
||||
MAGIC_VERSION
|
||||
MSED
|
||||
MCPP
|
||||
LD_RUN_PATH
|
||||
|
|
@ -2597,17 +2595,6 @@ test -n "$target_alias" &&
|
|||
|
||||
PACKAGE=magic
|
||||
|
||||
MAGIC_VERSION=`cat ../VERSION | cut -d. -f1-2`
|
||||
MAGIC_REVISION=`cat ../VERSION | cut -d. -f3`
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define MAGIC_VERSION "${MAGIC_VERSION}"
|
||||
_ACEOF
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define MAGIC_REVISION "${MAGIC_REVISION}"
|
||||
_ACEOF
|
||||
|
||||
|
||||
ALL_TARGET="standard"
|
||||
INSTALL_TARGET="install-magic"
|
||||
|
||||
|
|
@ -8227,9 +8214,6 @@ fi
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -11,11 +11,6 @@ AC_CANONICAL_SYSTEM
|
|||
dnl pass the version string on the the makefiles
|
||||
PACKAGE=magic
|
||||
|
||||
MAGIC_VERSION=`cat ../VERSION | cut -d. -f1-2`
|
||||
MAGIC_REVISION=`cat ../VERSION | cut -d. -f3`
|
||||
AC_DEFINE_UNQUOTED(MAGIC_VERSION, "${MAGIC_VERSION}")
|
||||
AC_DEFINE_UNQUOTED(MAGIC_REVISION, "${MAGIC_REVISION}")
|
||||
|
||||
dnl Override default target when compiling under TCL
|
||||
ALL_TARGET="standard"
|
||||
INSTALL_TARGET="install-magic"
|
||||
|
|
@ -407,6 +402,8 @@ AC_ARG_WITH(tcllibs, [ --with-tcllibs=DIR Find Tcl library in DIR],
|
|||
magic_with_tcl_libraries=$withval)
|
||||
AC_ARG_WITH(tklibs, [ --with-tklibs=DIR Find Tk library in DIR],
|
||||
magic_with_tk_libraries=$withval)
|
||||
AC_ARG_WITH(wish, [ --with-wish=EXE Use wish binary at EXE],
|
||||
magic_with_wish_binary=$withval)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Find the Tcl build configuration file "tclConfig.sh"
|
||||
|
|
@ -709,33 +706,37 @@ if test $usingTcl ; then
|
|||
# Find the version of "wish" that corresponds to TCL_EXEC_PREFIX
|
||||
# We really ought to run "ldd" to confirm that the linked libraries match.
|
||||
|
||||
AC_MSG_CHECKING([for wish executable])
|
||||
for dir in \
|
||||
${TK_EXEC_PREFIX}/bin \
|
||||
${TK_EXEC_PREFIX}
|
||||
do
|
||||
for wishexe in \
|
||||
wish-X11 \
|
||||
wish \
|
||||
wish${TK_VERSION} \
|
||||
wish.exe \
|
||||
wish${TK_VERSION}.exe
|
||||
if text "x${magic_with_wish_binary}" = "x" ; then
|
||||
AC_MSG_CHECKING([for wish executable])
|
||||
for dir in \
|
||||
${TK_EXEC_PREFIX}/bin \
|
||||
${TK_EXEC_PREFIX}
|
||||
do
|
||||
if test -r "$dir/$wishexe" ; then
|
||||
WISH_EXE=$dir/$wishexe
|
||||
for wishexe in \
|
||||
wish-X11 \
|
||||
wish \
|
||||
wish${TK_VERSION} \
|
||||
wish.exe \
|
||||
wish${TK_VERSION}.exe
|
||||
do
|
||||
if test -r "$dir/$wishexe" ; then
|
||||
WISH_EXE=$dir/$wishexe
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test "x${WISH_EXE}" != "x" ; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test "x${WISH_EXE}" != "x" ; then
|
||||
break
|
||||
if test "x${WISH_EXE}" = "x" ; then
|
||||
echo "Warning: Can't find executable for \"wish\". You may have to"
|
||||
echo "manually set the value for WISH_EXE in the magic startup script."
|
||||
AC_MSG_RESULT(no)
|
||||
else
|
||||
AC_MSG_RESULT([${WISH_EXE}])
|
||||
fi
|
||||
done
|
||||
if test "x${WISH_EXE}" = "x" ; then
|
||||
echo "Warning: Can't find executable for \"wish\". You may have to"
|
||||
echo "manually set the value for WISH_EXE in the magic startup script."
|
||||
AC_MSG_RESULT(no)
|
||||
else
|
||||
AC_MSG_RESULT([${WISH_EXE}])
|
||||
WISH_EXE=${magic_with_wish_binary}
|
||||
fi
|
||||
|
||||
# Find the version of "tclsh" that corresponds to TCL_EXEC_PREFIX
|
||||
|
|
@ -1800,9 +1801,6 @@ AC_SUBST(LD_RUN_PATH)
|
|||
AC_SUBST(MCPP)
|
||||
AC_SUBST(MSED)
|
||||
|
||||
AC_SUBST(MAGIC_VERSION)
|
||||
AC_SUBST(MAGIC_REVISION)
|
||||
|
||||
AC_SUBST(OA)
|
||||
AC_SUBST(OA_LIBS)
|
||||
|
||||
|
|
|
|||
|
|
@ -68,15 +68,15 @@ LIB_SPECS = @LIB_SPECS@
|
|||
LIB_SPECS_NOSTUB = @LIB_SPECS_NOSTUB@
|
||||
WISH_EXE = @WISH_EXE@
|
||||
TCL_LIB_DIR = @TCL_LIB_DIR@
|
||||
MAGIC_VERSION = @MAGIC_VERSION@
|
||||
MAGIC_REVISION = @MAGIC_REVISION@
|
||||
MAGIC_VERSION = `cat ../VERSION | cut -d. -f1-2`
|
||||
MAGIC_REVISION = `cat ../VERSION | cut -d. -f3`
|
||||
|
||||
CC = @CC@
|
||||
CPP = @CPP@
|
||||
CXX = @CXX@
|
||||
|
||||
CPPFLAGS = -I. -I${MAGICDIR} @CPPFLAGS@
|
||||
DFLAGS = @extra_defs@ @stub_defs@ @DEFS@ -DGCORE=\"@GCORE@\"
|
||||
DFLAGS = @extra_defs@ @stub_defs@ @DEFS@ -DMAGIC_VERSION=\"${MAGIC_VERSION}\" -DMAGIC_REVISION=\"${MAGIC_REVISION}\" -DGCORE=\"@GCORE@\"
|
||||
DFLAGS += -DSHDLIB_EXT=\"@SHDLIB_EXT@\" -DNDEBUG
|
||||
DFLAGS_NOSTUB = @extra_defs@ @DEFS@ -DGCORE=\"@GCORE@\"
|
||||
DFLAGS_NOSTUB += -DSHDLIB_EXT=\"@SHDLIB_EXT@\" -DNDEBUG
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
MODULE = tcltk
|
||||
MAGICDIR = ..
|
||||
SRCS = tclmagic.c
|
||||
OBJS = $(subst .c,.o,${SRCS})
|
||||
|
||||
include ${MAGICDIR}/defs.mak
|
||||
|
||||
|
|
@ -58,11 +59,10 @@ magicdnull: magicdnull.c ${MAGICDIR}/defs.mak
|
|||
-o magicdnull ${LD_RUN_PATH} ${LIB_SPECS_NOSTUB} ${LIBS} \
|
||||
${GR_LIBS}
|
||||
|
||||
magic.tcl: magic.tcl.in ${MAGICDIR}/defs.mak
|
||||
sed -e /TCL_DIR/s%TCL_DIR%${TCLDIR}%g \
|
||||
-e /MAGIC_VERSION/s%MAGIC_VERSION%${MAGIC_VERSION}%g \
|
||||
magic.tcl: magic.tcl.in ${MAGICDIR}/defs.mak ${MAGICDIR}/VERSION
|
||||
sed -e /MAGIC_VERSION/s%MAGIC_VERSION%${MAGIC_VERSION}%g \
|
||||
-e /MAGIC_REVISION/s%MAGIC_REVISION%${MAGIC_REVISION}%g \
|
||||
-e /SHDLIB_EXT/s%SHDLIB_EXT%${SHDLIB_EXT}%g magic.tcl.in > magic.tcl
|
||||
magic.tcl.in > magic.tcl
|
||||
|
||||
magic.sh: magic.sh.in ${MAGICDIR}/defs.mak
|
||||
sed -e /TCL_DIR/s%TCL_DIR%${TCLDIR}%g \
|
||||
|
|
@ -70,10 +70,12 @@ magic.sh: magic.sh.in ${MAGICDIR}/defs.mak
|
|||
-e /WISH_EXE/s%WISH_EXE%${WISH_EXE}%g magic.sh.in > magic.sh
|
||||
|
||||
ext2spice.sh: ext2spice.sh.in ${MAGICDIR}/defs.mak
|
||||
sed -e /TCL_DIR/s%TCL_DIR%${TCLDIR}%g ext2spice.sh.in > ext2spice.sh
|
||||
sed -e /TCL_DIR/s%TCL_DIR%${TCLDIR}%g \
|
||||
ext2spice.sh.in > ext2spice.sh
|
||||
|
||||
ext2sim.sh: ext2sim.sh.in ${MAGICDIR}/defs.mak
|
||||
sed -e /TCL_DIR/s%TCL_DIR%${TCLDIR}%g ext2sim.sh.in > ext2sim.sh
|
||||
sed -e /TCL_DIR/s%TCL_DIR%${TCLDIR}%g \
|
||||
ext2sim.sh.in > ext2sim.sh
|
||||
|
||||
$(DESTDIR)${INSTALL_TCLDIR}/%: %
|
||||
${RM} $(DESTDIR)${INSTALL_TCLDIR}/$*
|
||||
|
|
@ -94,4 +96,7 @@ $(DESTDIR)${INSTALL_BINDIR}/ext2sim.sh: ext2sim.sh
|
|||
${CP} ext2sim.sh $(DESTDIR)${INSTALL_BINDIR}/ext2sim
|
||||
(cd $(DESTDIR)${INSTALL_BINDIR}; chmod 0755 ext2sim)
|
||||
|
||||
# An additional dependency on the VERSION file
|
||||
${OBJS}: ${MAGICDIR}/VERSION
|
||||
|
||||
include ${MAGICDIR}/rules.mak
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
#
|
||||
# Standalone script for ext2sim, for Tcl-based magic 8.0
|
||||
#
|
||||
|
|
@ -14,8 +14,12 @@ for i in $@; do
|
|||
*) esargs="$esargs $i" ;;
|
||||
esac
|
||||
done
|
||||
TCL_MAG_DIR=${CAD_ROOT}/magic/tcl
|
||||
if [ "${TCL_MAG_DIR}" = "/magic/tcl" ]; then
|
||||
TCL_MAG_DIR=TCL_DIR
|
||||
fi
|
||||
#
|
||||
eval TCL_DIR/magicdnull -dnull -noconsole -nowrapper $mgargs <<EOF
|
||||
eval ${TCL_MAG_DIR}/magicdnull -dnull -noconsole -nowrapper $mgargs <<EOF
|
||||
drc off
|
||||
box 0 0 0 0
|
||||
ext2sim $esargs
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
#
|
||||
# Standalone script for ext2spice, for Tcl-based magic 8.0
|
||||
#
|
||||
|
|
@ -14,8 +14,12 @@ for i in $@; do
|
|||
*) esargs="$esargs $i" ;;
|
||||
esac
|
||||
done
|
||||
TCL_MAG_DIR=${CAD_ROOT}/magic/tcl
|
||||
if [ "${TCL_MAG_DIR}" = "/magic/tcl" ]; then
|
||||
TCL_MAG_DIR=TCL_DIR
|
||||
fi
|
||||
#
|
||||
eval TCL_DIR/magicdnull -dnull -noconsole -nowrapper $mgargs <<EOF
|
||||
eval ${TCL_MAG_DIR}/magicdnull -dnull -noconsole -nowrapper $mgargs <<EOF
|
||||
drc off
|
||||
box 0 0 0 0
|
||||
ext2spice $esargs
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@
|
|||
# Parse for the argument "-c[onsole]". If it exists, run magic
|
||||
# with the TkCon console. Strip this argument from the argument list.
|
||||
|
||||
TCL_MAG_DIR=${CAD_ROOT}/magic/tcl
|
||||
if [ "${TCL_MAG_DIR}" = "/magic/tcl" ]; then
|
||||
TCL_MAG_DIR=TCL_DIR
|
||||
fi
|
||||
TKCON=true
|
||||
DNULL=
|
||||
MAGIC_WISH=WISH_EXE
|
||||
|
|
@ -37,12 +41,12 @@ done
|
|||
if [ $TKCON ]; then
|
||||
|
||||
if [ $DNULL ]; then
|
||||
exec TCL_DIR/tkcon.tcl -eval "source TCL_DIR/console.tcl" \
|
||||
-slave "set argc $#; set argv [list $*]; source TCL_DIR/magic.tcl"
|
||||
exec $TCL_MAG_DIR/tkcon.tcl -eval "source $TCL_MAG_DIR/console.tcl" \
|
||||
-slave "set argc $#; set argv [list $*]; source $TCL_MAG_DIR/magic.tcl"
|
||||
else
|
||||
exec TCL_DIR/tkcon.tcl -eval "source TCL_DIR/console.tcl" \
|
||||
exec $TCL_MAG_DIR/tkcon.tcl -eval "source $TCL_MAG_DIR/console.tcl" \
|
||||
-slave "package require Tk; set argc $#; set argv [list $arglist]; \
|
||||
source TCL_DIR/magic.tcl"
|
||||
source $TCL_MAG_DIR/magic.tcl"
|
||||
fi
|
||||
|
||||
else
|
||||
|
|
@ -57,8 +61,8 @@ else
|
|||
# only, efficient for running in batch mode).
|
||||
#
|
||||
if [ $DNULL ]; then
|
||||
exec TCL_DIR/magicdnull -nowrapper "$@"
|
||||
exec $TCL_MAG_DIR/magicdnull -nowrapper "$@"
|
||||
else
|
||||
exec TCL_DIR/magicexec -- "$@"
|
||||
exec $TCL_MAG_DIR/magicexec -- "$@"
|
||||
fi
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,19 +1,20 @@
|
|||
# Wishrc startup for ToolScript (magic)
|
||||
#
|
||||
# For installation: Put this file and also magicwrap.so into
|
||||
# directory TCL_DIR, and set the "load" line below
|
||||
# to point to the location of magicwrap.so. Also see comments
|
||||
# in shell script "magic.sh".
|
||||
# the same directory. Also see comments in shell script "magic.sh".
|
||||
|
||||
global Opts
|
||||
|
||||
|
||||
# If we called magic via the non-console script, then we want to reset
|
||||
# the environment variable HOME to its original value.
|
||||
|
||||
|
||||
variable MAGIC_TCL_DIR [file dirname [file normalize [info script]]]
|
||||
variable CAD_ROOT_DEFAULT [file normalize [file join $MAGIC_TCL_DIR ../..]]
|
||||
|
||||
if {${tcl_version} >= 8.6} {
|
||||
load -lazy TCL_DIR/tclmagicSHDLIB_EXT
|
||||
load -lazy [file join $MAGIC_TCL_DIR tclmagic[info sharedlibextension]]
|
||||
} else {
|
||||
load TCL_DIR/tclmagicSHDLIB_EXT
|
||||
load [file join $MAGIC_TCL_DIR tclmagic[info sharedlibextension]]
|
||||
}
|
||||
|
||||
# It is important to make sure no magic commands overlap with Tcl built-in
|
||||
|
|
@ -30,8 +31,8 @@ proc pushnamespace { name } {
|
|||
foreach v $y {
|
||||
regsub -all {\*} $v {\\*} i
|
||||
set x [namespace tail $i]
|
||||
if {[lsearch $z $x] < 0} {
|
||||
namespace import $i
|
||||
if {[lsearch $z $x] < 0} {
|
||||
namespace import $i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -124,7 +125,7 @@ proc xcircuit { args } {
|
|||
# execute script in the scope of magic, because its variable space is
|
||||
# not modularized.
|
||||
set argv $args
|
||||
set argc [llength $args]
|
||||
set argc [llength $args]
|
||||
uplevel #0 source $xcircscript
|
||||
}
|
||||
}
|
||||
|
|
@ -143,7 +144,7 @@ proc netgen { args } {
|
|||
puts stderr "\"source <path>/netgen.tcl\"."
|
||||
} else {
|
||||
set argv $args
|
||||
set argc [llength $args]
|
||||
set argc [llength $args]
|
||||
uplevel #0 source $netgenscript
|
||||
}
|
||||
}
|
||||
|
|
@ -151,7 +152,7 @@ proc netgen { args } {
|
|||
# Add the "echo" command
|
||||
|
||||
proc echo {args} {
|
||||
puts stdout $args
|
||||
puts stdout $args
|
||||
}
|
||||
|
||||
# Parse argument list for "-c[onsole]" and "-now[rapper]".
|
||||
|
|
|
|||
|
|
@ -1191,7 +1191,7 @@ int
|
|||
Tclmagic_Init(interp)
|
||||
Tcl_Interp *interp;
|
||||
{
|
||||
char *cadroot;
|
||||
const char *cadroot;
|
||||
|
||||
/* Sanity check! */
|
||||
if (interp == NULL) return TCL_ERROR;
|
||||
|
|
@ -1221,12 +1221,18 @@ Tclmagic_Init(interp)
|
|||
|
||||
Tcl_Eval(interp, "lappend auto_path " TCL_DIR );
|
||||
|
||||
/* Set $CAD_ROOT as a Tcl variable */
|
||||
/* Get $CAD_ROOT from a Tcl variable, if it exists, and if not, then */
|
||||
/* set CAD_ROOT from the environment variable of the same name, if */
|
||||
/* it exists, and finally fall back on the CAD_DIR set at compile */
|
||||
/* time. */
|
||||
|
||||
cadroot = getenv("CAD_ROOT");
|
||||
if (cadroot == NULL) cadroot = CAD_DIR;
|
||||
|
||||
Tcl_SetVar(interp, "CAD_ROOT", cadroot, TCL_GLOBAL_ONLY);
|
||||
cadroot = Tcl_GetVar(interp, "CAD_ROOT", TCL_GLOBAL_ONLY);
|
||||
if (cadroot == NULL)
|
||||
{
|
||||
cadroot = (const char *)getenv("CAD_ROOT");
|
||||
if (cadroot == NULL) cadroot = CAD_DIR;
|
||||
Tcl_SetVar(interp, "CAD_ROOT", cadroot, TCL_GLOBAL_ONLY);
|
||||
}
|
||||
|
||||
Tcl_PkgProvide(interp, "Tclmagic", MAGIC_VERSION);
|
||||
return TCL_OK;
|
||||
|
|
|
|||
12
utils/path.c
12
utils/path.c
|
|
@ -119,7 +119,7 @@ PaExpand(psource, pdest, size)
|
|||
{
|
||||
char *ps, *pd;
|
||||
struct passwd *passwd, *getpwnam();
|
||||
char expandName[100], *string, *newEntry;
|
||||
char expandName[512], *string, *newEntry;
|
||||
HashEntry *h;
|
||||
int i, length;
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ PaExpand(psource, pdest, size)
|
|||
*pd = *++ps;
|
||||
if (isspace(*pd) || (*pd=='\0') || (*pd=='/') || (*pd==':'))
|
||||
break;
|
||||
if (i < 99) pd++;
|
||||
if (i < 511) pd++;
|
||||
}
|
||||
*pd = '\0';
|
||||
|
||||
|
|
@ -196,7 +196,7 @@ PaExpand(psource, pdest, size)
|
|||
*pd = *++ps;
|
||||
if (isspace(*pd) || (*pd=='\0') || (*pd=='/') || (*pd==':'))
|
||||
break;
|
||||
if (i < 99) pd++;
|
||||
if ((i < 511) && (*pd != '{') && (*pd != '}')) pd++;
|
||||
}
|
||||
saveChar = *pd;
|
||||
*pd = '\0';
|
||||
|
|
@ -226,7 +226,11 @@ PaExpand(psource, pdest, size)
|
|||
if (string == NULL)
|
||||
{
|
||||
/* Check for CAD_ROOT = CAD_DIR, the only internal variable */
|
||||
/* recognized (this is passed down from the Makefile) */
|
||||
/* recognized (this is passed down from the Makefile). */
|
||||
/* Note that in the MAGIC_WRAPPER version, CAD_ROOT was set */
|
||||
/* as a Tcl variable in tcltk/tclmagic.c, such that if */
|
||||
/* expandName == "CAD_ROOT", then string should not be NULL */
|
||||
/* here. */
|
||||
|
||||
if (!strcmp(expandName, "CAD_ROOT"))
|
||||
string = CAD_DIR;
|
||||
|
|
|
|||
|
|
@ -272,9 +272,12 @@ changePlanesFunc(cellDef, arg)
|
|||
/* Old planes to be subtracted */
|
||||
for (pNum = DBNumPlanes; pNum < oldnumplanes; pNum++)
|
||||
{
|
||||
DBFreePaintPlane(cellDef->cd_planes[pNum]);
|
||||
TiFreePlane(cellDef->cd_planes[pNum]);
|
||||
cellDef->cd_planes[pNum] = (Plane *) NULL;
|
||||
if (cellDef->cd_planes[pNum] != NULL)
|
||||
{
|
||||
DBFreePaintPlane(cellDef->cd_planes[pNum]);
|
||||
TiFreePlane(cellDef->cd_planes[pNum]);
|
||||
cellDef->cd_planes[pNum] = (Plane *) NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue