Merge branch 'master' of https://github.com/RTimothyEdwards/magic into spice_hier
This commit is contained in:
commit
dde3d75256
|
|
@ -48,12 +48,14 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
|
||||
int calmaNonManhattan;
|
||||
int CalmaFlattenLimit = 10;
|
||||
int NameConvertErrors = 0;
|
||||
|
||||
extern HashTable calmaDefInitHash;
|
||||
|
||||
/* forward declarations */
|
||||
int calmaElementSref();
|
||||
bool calmaParseElement();
|
||||
void calmaUniqueCell();
|
||||
|
||||
/* Structure used when flattening the GDS hierarchy on read-in */
|
||||
|
||||
|
|
@ -306,8 +308,8 @@ calmaParseStructure(filename)
|
|||
if (!calmaReadStringRecord(CALMA_STRNAME, &strname)) goto syntaxerror;
|
||||
TxPrintf("Reading \"%s\".\n", strname);
|
||||
|
||||
if (CalmaReadOnly)
|
||||
filepos = ftello(calmaInputFile);
|
||||
/* Used for read-only and annotated LEF views */
|
||||
filepos = ftello(calmaInputFile);
|
||||
|
||||
/* Set up the cell definition */
|
||||
he = HashFind(&calmaDefInitHash, strname);
|
||||
|
|
@ -348,51 +350,76 @@ calmaParseStructure(filename)
|
|||
freeMagic(newname);
|
||||
}
|
||||
}
|
||||
if (CalmaUnique) calmaUniqueCell(strname); /* Ensure uniqueness */
|
||||
cifReadCellDef = calmaFindCell(strname, &was_called, &predefined);
|
||||
HashSetValue(he, cifReadCellDef);
|
||||
|
||||
if (predefined == TRUE)
|
||||
{
|
||||
calmaNextCell();
|
||||
return TRUE;
|
||||
bool isAbstract;
|
||||
|
||||
/* If the cell was predefined, the "noduplicates" option was
|
||||
* invoked, and the existing cell is an abstract view, then
|
||||
* annotate the cell with the GDS file pointers to the cell
|
||||
* data, and the GDS filename.
|
||||
*/
|
||||
DBPropGet(cifReadCellDef, "LEFview", &isAbstract);
|
||||
if (!isAbstract)
|
||||
{
|
||||
calmaNextCell();
|
||||
return TRUE;
|
||||
}
|
||||
calmaSkipTo(CALMA_ENDSTR);
|
||||
}
|
||||
DBCellClearDef(cifReadCellDef);
|
||||
DBCellSetAvail(cifReadCellDef);
|
||||
HashSetValue(he, cifReadCellDef);
|
||||
cifCurReadPlanes = cifSubcellPlanes;
|
||||
cifReadCellDef->cd_flags &= ~CDDEREFERENCE;
|
||||
|
||||
/* For read-only cells, set flag in def */
|
||||
if (CalmaReadOnly)
|
||||
cifReadCellDef->cd_flags |= CDVENDORGDS;
|
||||
|
||||
/* Skip CALMA_STRCLASS or CALMA_STRTYPE */
|
||||
calmaSkipSet(structs);
|
||||
|
||||
/* Initialize the hash table for layer errors */
|
||||
HashInit(&calmaLayerHash, 32, sizeof (CalmaLayerType) / sizeof (unsigned));
|
||||
was_initialized = TRUE;
|
||||
|
||||
/* Body of structure: a sequence of elements */
|
||||
osrefs = nsrefs = 0;
|
||||
npaths = 0;
|
||||
calmaNonManhattan = 0;
|
||||
while (calmaParseElement(filename, &nsrefs, &npaths))
|
||||
else
|
||||
{
|
||||
if (SigInterruptPending)
|
||||
goto done;
|
||||
if (nsrefs > osrefs && (nsrefs % 100) == 0)
|
||||
TxPrintf(" %d uses\n", nsrefs);
|
||||
osrefs = nsrefs;
|
||||
DBCellClearDef(cifReadCellDef);
|
||||
DBCellSetAvail(cifReadCellDef);
|
||||
cifCurReadPlanes = cifSubcellPlanes;
|
||||
cifReadCellDef->cd_flags &= ~CDDEREFERENCE;
|
||||
|
||||
/* For read-only cells, set flag in def */
|
||||
if (CalmaReadOnly)
|
||||
cifReadCellDef->cd_flags |= CDVENDORGDS;
|
||||
|
||||
/* Skip CALMA_STRCLASS or CALMA_STRTYPE */
|
||||
calmaSkipSet(structs);
|
||||
|
||||
/* Initialize the hash table for layer errors */
|
||||
HashInit(&calmaLayerHash, 32, sizeof (CalmaLayerType) / sizeof (unsigned));
|
||||
was_initialized = TRUE;
|
||||
|
||||
/* Body of structure: a sequence of elements */
|
||||
osrefs = nsrefs = 0;
|
||||
npaths = 0;
|
||||
calmaNonManhattan = 0;
|
||||
|
||||
while (calmaParseElement(filename, &nsrefs, &npaths))
|
||||
{
|
||||
if (SigInterruptPending)
|
||||
goto done;
|
||||
if (nsrefs > osrefs && (nsrefs % 100) == 0)
|
||||
TxPrintf(" %d uses\n", nsrefs);
|
||||
osrefs = nsrefs;
|
||||
calmaNonManhattan = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (CalmaReadOnly)
|
||||
if (CalmaReadOnly || predefined)
|
||||
{
|
||||
char cstring[1024];
|
||||
|
||||
/* Writing the file position into a string is slow, but */
|
||||
/* it prevents requiring special handling when printing */
|
||||
/* out the properties. */
|
||||
|
||||
char *fpcopy = (char *)mallocMagic(20);
|
||||
char *fncopy = StrDup(NULL, filename);
|
||||
char *fncopy;
|
||||
|
||||
/* Substitute variable for PDK path or ~ for home directory */
|
||||
/* the same way that cell references are handled in .mag files. */
|
||||
DBPathSubstitute(filename, cstring, cifReadCellDef);
|
||||
fncopy = StrDup(NULL, cstring);
|
||||
sprintf(fpcopy, "%"DLONG_PREFIX"d", (dlong) filepos);
|
||||
DBPropPut(cifReadCellDef, "GDS_START", (ClientData)fpcopy);
|
||||
|
||||
|
|
@ -403,9 +430,11 @@ calmaParseStructure(filename)
|
|||
|
||||
DBPropPut(cifReadCellDef, "GDS_FILE", (ClientData)fncopy);
|
||||
|
||||
/* Do not lock the cell, or else we can't save the */
|
||||
/* magic cell with its GDS pointers to disk. . . */
|
||||
/* cifReadCellDef->cd_flags |= CDNOEDIT; */
|
||||
if (predefined)
|
||||
{
|
||||
if (strname != NULL) freeMagic(strname);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the cell name matches the pattern list of cells to flatten */
|
||||
|
|
@ -591,6 +620,25 @@ calmaParseElement(filename, pnsrefs, pnpaths)
|
|||
return (calmaSkipTo(CALMA_ENDEL));
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Callback procedure for enumerating any paint in a cell. Used to find if
|
||||
* a cell needs to be retained after being flattened into the parent cell.
|
||||
*
|
||||
* Returns 1 always. Only called if a non-space tile was encountered.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
calmaEnumFunc(tile, plane)
|
||||
Tile *tile;
|
||||
int *plane;
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -836,8 +884,24 @@ calmaElementSref(filename)
|
|||
READI2(propAttrType);
|
||||
if (propAttrType == CALMA_PROP_USENAME)
|
||||
{
|
||||
char *s;
|
||||
|
||||
if (!calmaReadStringRecord(CALMA_PROPVALUE, &useid))
|
||||
return -1;
|
||||
|
||||
/* Magic prohibits comma and slash from use names */
|
||||
for (s = useid; *s; s++)
|
||||
if (*s == '/' || *s == ',')
|
||||
{
|
||||
if (NameConvertErrors < 100)
|
||||
TxPrintf("\"%c\" character cannot be used in instance name; "
|
||||
"converting to underscore\n", *s);
|
||||
else if (NameConvertErrors == 100)
|
||||
TxPrintf("More than 100 character changes; not reporting"
|
||||
" further errors.\n");
|
||||
*s = '_';
|
||||
NameConvertErrors++;
|
||||
}
|
||||
}
|
||||
else if (propAttrType == CALMA_PROP_ARRAY_LIMITS)
|
||||
{
|
||||
|
|
@ -981,9 +1045,38 @@ calmaElementSref(filename)
|
|||
}
|
||||
}
|
||||
|
||||
/* If cell has children in addition to paint to be flattened, */
|
||||
/* then also generate an instance of the cell. */
|
||||
/* When not reading with VENDORGDS, if a cell has contents */
|
||||
/* other than the paint to be flattened, then also generate an */
|
||||
/* instance of the cell. Otherwise (with VENDORGDS), always */
|
||||
/* generate cell instances. Note that only paint and cells */
|
||||
/* are counted, not labels (see below). */
|
||||
|
||||
else if (!(def->cd_flags & CDVENDORGDS))
|
||||
{
|
||||
int plane;
|
||||
for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
|
||||
if (DBSrPaintArea((Tile *)NULL, def->cd_planes[plane], &TiPlaneRect,
|
||||
&DBAllButSpaceAndDRCBits, calmaEnumFunc, (ClientData)NULL))
|
||||
break;
|
||||
|
||||
if ((plane < DBNumPlanes) || DBCellEnum(def, gdsHasUses, (ClientData)NULL))
|
||||
{
|
||||
use = DBCellNewUse(def, (useid) ? useid : (char *) NULL);
|
||||
if (isArray)
|
||||
DBMakeArray(use, &GeoIdentityTransform, xlo, ylo, xhi, yhi, xsep, ysep);
|
||||
DBSetTrans(use, &trans);
|
||||
DBPlaceCell(use, cifReadCellDef);
|
||||
madeinst = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* (To do: Copy labels from flattened cells, with hierarchical */
|
||||
/* names. Whether to do this or not should be an option.) */
|
||||
/* TxPrintf("Removing instances of flattened cell %s in %s\n",
|
||||
def->cd_name, cifReadCellDef->cd_name); */
|
||||
madeinst = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
use = DBCellNewUse(def, (useid) ? useid : (char *) NULL);
|
||||
|
|
@ -1045,6 +1138,65 @@ gdsCopyPaintFunc(tile, gdsCopyRec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* calmaUniqueCell --
|
||||
*
|
||||
* Attempt to find a cell in the GDS subcell name hash table.
|
||||
* If one exists, rename its definition so that it will not
|
||||
* be overwritten when the cell is redefined.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
calmaUniqueCell(sname)
|
||||
char *sname;
|
||||
{
|
||||
HashEntry *h;
|
||||
CellDef *def, *testdef;
|
||||
char *newname;
|
||||
int snum = 0;
|
||||
|
||||
h = HashLookOnly(&CifCellTable, sname);
|
||||
|
||||
/* Existing entry with zero value indicates that the existing */
|
||||
/* cell came from the same GDS file, so don't change anything. */
|
||||
if ((h != NULL) && HashGetValue(h) == 0) return;
|
||||
|
||||
def = DBCellLookDef(sname);
|
||||
if (def == (CellDef *)NULL)
|
||||
return;
|
||||
|
||||
/* Cell may have been called but not yet defined---this is okay. */
|
||||
else if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
return;
|
||||
|
||||
testdef = def;
|
||||
newname = (char *)mallocMagic(10 + strlen(sname));
|
||||
|
||||
while (testdef != NULL)
|
||||
{
|
||||
/* Keep appending suffix indexes until we find one not used */
|
||||
sprintf(newname, "%s_%d", sname, ++snum);
|
||||
testdef = DBCellLookDef(newname);
|
||||
}
|
||||
DBCellRenameDef(def, newname);
|
||||
|
||||
h = HashFind(&CifCellTable, (char *)sname);
|
||||
HashSetValue(h, 0);
|
||||
|
||||
CalmaReadError("Warning: cell definition \"%s\" reused.\n", sname);
|
||||
freeMagic(newname);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
|
|||
|
|
@ -87,6 +87,12 @@ bool CalmaNoDuplicates = FALSE; /* If TRUE, then if a cell exists in
|
|||
* in the GDS file, then the cell in
|
||||
* the GDS file is skipped.
|
||||
*/
|
||||
bool CalmaUnique = FALSE; /* If TRUE, then if a cell exists in
|
||||
* memory with the same name as a cell
|
||||
* in the GDS file, then the cell in
|
||||
* memory is renamed to a unique
|
||||
* identifier with a _N suffix.
|
||||
*/
|
||||
extern void calmaUnexpected();
|
||||
extern int calmaWriteInitFunc();
|
||||
|
||||
|
|
|
|||
|
|
@ -613,7 +613,7 @@ calmaFullDump(def, fi, outf, filename)
|
|||
FILE *outf;
|
||||
char *filename;
|
||||
{
|
||||
int version, rval, i;
|
||||
int version, rval;
|
||||
char *libname = NULL, uniqlibname[4];
|
||||
char *sptr, *viewopts;
|
||||
bool isAbstract;
|
||||
|
|
@ -657,24 +657,29 @@ calmaFullDump(def, fi, outf, filename)
|
|||
viewopts = (char *)DBPropGet(def, "LEFview", &isAbstract);
|
||||
if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
|
||||
{
|
||||
|
||||
/* Generate a SHORT name for this cell (else it is easy to run into the
|
||||
* GDS 32-character cellname limit). Save it in the hash record. The
|
||||
* chance of generating the same prefix for a library that has items
|
||||
* with conflicting names is vanishingly small, but to be pedantic, store
|
||||
* the prefix in a hash table and check to make sure that uniqueness is
|
||||
* ensured.
|
||||
* ensured. NOTE: The first character of a SPICE name cannot be a
|
||||
* number. Therefore the first character is alphabetical, and the second
|
||||
* is alphanumeric. There are only 936 possible combinations, but this
|
||||
* is only meant to distinguish cells in large IP blocks of unknown
|
||||
* origin, of which only a limited number would be expected. Beware
|
||||
* the implications for LVS, as the prefixed names from layout would
|
||||
* need to be compared to un-prefixed names from another netlist.
|
||||
*/
|
||||
while (TRUE)
|
||||
{
|
||||
HashEntry *he2;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
rval = random() % 62;
|
||||
rval = (rval < 26) ? ('A' + rval) : ((rval < 52) ? ('a' + rval - 26) :
|
||||
('0' + rval - 52));
|
||||
uniqlibname[i] = (char)(rval & 127);
|
||||
}
|
||||
rval = random() % 26;
|
||||
rval = 'A' + rval;
|
||||
uniqlibname[0] = (char)(rval & 127);
|
||||
rval = random() % 36;
|
||||
rval = (rval < 26) ? ('A' + rval) : ('0' + rval - 26);
|
||||
uniqlibname[1] = (char)(rval & 127);
|
||||
uniqlibname[2] = '_';
|
||||
uniqlibname[3] = '\0';
|
||||
he2 = HashLookOnly(&calmaPrefixHash, uniqlibname);
|
||||
|
|
@ -809,6 +814,13 @@ calmaProcessDef(def, outf, do_library)
|
|||
|
||||
if (isReadOnly && hasContent && CalmaAddendum) return (0);
|
||||
|
||||
/* Give a strongly-worded statement about writing abstract views */
|
||||
|
||||
if (isAbstract && !isReadOnly)
|
||||
TxError("Warning: Writing abstract view of \"%s\" to GDS. This is"
|
||||
" probably not what you want to do.\n",
|
||||
def->cd_name);
|
||||
|
||||
/*
|
||||
* Output the definitions for any of our descendants that have
|
||||
* not already been output. Numbers are assigned to the subcells
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ extern bool CalmaDoLower;
|
|||
extern bool CalmaAddendum;
|
||||
extern bool CalmaNoDuplicates;
|
||||
extern bool CalmaNoDateStamp;
|
||||
extern bool CalmaUnique;
|
||||
extern bool CalmaMergeTiles;
|
||||
extern bool CalmaFlattenArrays;
|
||||
extern bool CalmaNoDRCCheck;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "calma/calma.h" /* for CalmaContactArrays */
|
||||
#include "commands/commands.h" /* for CmdFindNetProc() */
|
||||
#include "select/selInt.h" /* for select use and def */
|
||||
#include "select/select.h"
|
||||
#include "utils/stack.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "utils/maxrect.h"
|
||||
|
|
@ -4786,7 +4787,7 @@ CIFGenLayer(op, area, cellDef, origDef, temps, hier, clientdata)
|
|||
scx.scx_use = CIFDummyUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
DBTreeCopyConnect(&scx, &DBConnectTbl[ttype], 0,
|
||||
DBConnectTbl, &TiPlaneRect, FALSE, Select2Use);
|
||||
DBConnectTbl, &TiPlaneRect, SEL_NO_LABELS, Select2Use);
|
||||
cifSrTiles(op, area, Select2Def, temps, cifPaintFunc,
|
||||
(ClientData) CIFPaintTable);
|
||||
DBCellClearDef(Select2Def);
|
||||
|
|
|
|||
252
commands/CmdCD.c
252
commands/CmdCD.c
|
|
@ -110,6 +110,7 @@ bool cmdDumpParseArgs();
|
|||
#define CALMA_POLYS 19
|
||||
#define CALMA_PATHS 20
|
||||
#define CALMA_UNDEFINED 21
|
||||
#define CALMA_UNIQUE 22
|
||||
|
||||
#define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */
|
||||
|
||||
|
|
@ -145,8 +146,8 @@ CmdCalma(w, cmd)
|
|||
"library [yes|no] do not output the top level, only subcells",
|
||||
"lower [yes|no] allow both upper and lower case in labels",
|
||||
"merge [yes|no] merge tiles into polygons in the output",
|
||||
"noduplicates [yes|no] do not read cells that exist before reading GDS",
|
||||
"nodatestamp [yes|no] write a zero value creation date stamp",
|
||||
"noduplicates [yes|no] do not read cells that exist before reading GDS",
|
||||
"read file read Calma GDS-II format from \"file\"\n"
|
||||
" into edit cell",
|
||||
"readonly [yes|no] set cell as read-only and generate output from GDS file",
|
||||
|
|
@ -160,6 +161,7 @@ CmdCalma(w, cmd)
|
|||
" put wire paths into individual subcells",
|
||||
"undefined [allow|disallow]\n"
|
||||
" [dis]allow writing of GDS with calls to undefined cells",
|
||||
"unique [yes|no] rename any cells with names duplicated in the GDS",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -599,6 +601,26 @@ CmdCalma(w, cmd)
|
|||
CalmaNoDuplicates = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_UNIQUE:
|
||||
if (cmd->tx_argc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaUnique));
|
||||
#else
|
||||
TxPrintf("Cell defs that exist before reading GDS will be renamed.\n",
|
||||
(CalmaUnique) ? "not " : "");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
else if (cmd->tx_argc != 3)
|
||||
goto wrongNumArgs;
|
||||
|
||||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaUnique = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_NO_STAMP:
|
||||
if (cmd->tx_argc == 2)
|
||||
{
|
||||
|
|
@ -857,6 +879,9 @@ CmdCellname(w, cmd)
|
|||
IDX_ORIENTATION, IDX_RENAME, IDX_READWRITE,
|
||||
IDX_MODIFIED } optionType;
|
||||
|
||||
static char *cmdCellnameYesNo[] = {
|
||||
"no", "false", "off", "0", "yes", "true", "on", "1", 0 };
|
||||
|
||||
if (strstr(cmd->tx_argv[0], "in"))
|
||||
is_cellname = FALSE;
|
||||
else
|
||||
|
|
@ -1072,7 +1097,10 @@ CmdCellname(w, cmd)
|
|||
}
|
||||
else if (locargc == 4)
|
||||
{
|
||||
if (tolower(*cmd->tx_argv[3 + ((dolist) ? 1 : 0)]) == 't')
|
||||
int subopt = Lookup(cmd->tx_argv[3 + ((dolist) ? 1 : 0)],
|
||||
cmdCellnameYesNo);
|
||||
if (subopt < 0) goto badusage;
|
||||
else if (subopt >= 4)
|
||||
{
|
||||
/* Check if file is already read-write */
|
||||
if (!(cellDef->cd_flags & CDNOEDIT))
|
||||
|
|
@ -1084,13 +1112,11 @@ CmdCellname(w, cmd)
|
|||
if (cellDef->cd_fd == -1)
|
||||
dbReadOpen(cellDef, NULL, TRUE, NULL);
|
||||
|
||||
if (cellDef->cd_fd != -1)
|
||||
cellDef->cd_flags &= ~CDNOEDIT;
|
||||
else
|
||||
TxError("Advisory lock held on cell %s\n", cellDef->cd_name);
|
||||
#else
|
||||
cellDef->cd_flags &= ~CDNOEDIT;
|
||||
if (cellDef->cd_fd == -1)
|
||||
TxError("Overriding advisory lock held on cell %s\n",
|
||||
cellDef->cd_name);
|
||||
#endif
|
||||
cellDef->cd_flags &= ~CDNOEDIT;
|
||||
WindAreaChanged(w, &w->w_screenArea);
|
||||
CmdSetWindCaption(EditCellUse, EditRootDef);
|
||||
}
|
||||
|
|
@ -3921,6 +3947,216 @@ CmdDrc(w, cmd)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cmdDropPaintCell ---
|
||||
*
|
||||
* Callback function used by cmdDropFunc. Called for each tile found in
|
||||
* the edit cell hierarchy that matches paint that was in the selection.
|
||||
* Paints layers from lMask (clientData) into the subcell containing the
|
||||
* tile, within the area of the tile.
|
||||
*
|
||||
* Returns:
|
||||
* Always returns zero to keep the search going.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int cmdDropPaintCell(tile, cxp)
|
||||
Tile *tile;
|
||||
TreeContext *cxp;
|
||||
{
|
||||
CellDef *cellDef = cxp->tc_scx->scx_use->cu_def;
|
||||
TileTypeBitMask *lMask = (TileTypeBitMask *)cxp->tc_filter->tf_arg;
|
||||
int pNum;
|
||||
TileType type;
|
||||
Rect area;
|
||||
|
||||
if (SplitSide(tile))
|
||||
type = SplitRightType(tile);
|
||||
else
|
||||
type = SplitLeftType(tile);
|
||||
pNum = DBPlane(type);
|
||||
|
||||
TiToRect(tile, &area);
|
||||
|
||||
/* Clip to search area */
|
||||
GEOCLIP(&area, &cxp->tc_scx->scx_area);
|
||||
|
||||
DBPaintMask(cellDef, &area, lMask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cmdDropFunc ---
|
||||
*
|
||||
* Callback function used by CmdDrop. Called for each tile found in the
|
||||
* selection.
|
||||
*
|
||||
* Returns:
|
||||
* Always returns zero to keep the search going.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cmdDropFunc(Tile *tile, ClientData clientData)
|
||||
{
|
||||
TileTypeBitMask tMask, *lMask = (TileTypeBitMask *)clientData;
|
||||
SearchContext scx;
|
||||
TileType type;
|
||||
|
||||
TiToRect(tile, &scx.scx_area);
|
||||
scx.scx_use = EditCellUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
|
||||
if (SplitSide(tile))
|
||||
type = SplitRightType(tile);
|
||||
else
|
||||
type = SplitLeftType(tile);
|
||||
TTMaskSetOnlyType(&tMask, type);
|
||||
|
||||
DBTreeSrTiles(&scx, &tMask, 0, cmdDropPaintCell, (ClientData)lMask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cmdDropPaintFunc --
|
||||
*
|
||||
* Callback function to SelEnumPaint() from CmdDrop(). Sets a bit in
|
||||
* the type mask passed as clientData for the type of the tile found
|
||||
* in the selection.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cmdDropPaintFunc(rect, type, mask)
|
||||
Rect *rect; /* Not used. */
|
||||
TileType type; /* Type of this piece of paint. */
|
||||
TileTypeBitMask *mask; /* Place to OR in type's bit. */
|
||||
{
|
||||
if (type & TT_DIAGONAL)
|
||||
type = (type & TT_SIDE) ? (type & TT_RIGHTMASK) >> 14 :
|
||||
(type & TT_LEFTMASK);
|
||||
TTMaskSetType(mask, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CmdDrop --
|
||||
*
|
||||
* Implement the ":drop" command.
|
||||
*
|
||||
* Usage:
|
||||
* drop <layers>
|
||||
*
|
||||
* where <layers> is a list of paint layers. The command requires an
|
||||
* existing selection, with the expectation that the selection contains
|
||||
* paint material that exists in subcells of the current edit cell. The
|
||||
* "drop" command will copy the types in <layers> into every subcell in
|
||||
* the hierarchy of the current edit cell that contains selected material.
|
||||
*
|
||||
* The purpose of this command is to deal with issues arising from layers
|
||||
* in a vendor GDS file that must be in the same cell as a device layer
|
||||
* in order for the device to be extracted properly, but instead is placed
|
||||
* in a cell further up in the hierarchy. A typical example is the deep
|
||||
* nwell layer, which isolates the transistor bulk terminal from the
|
||||
* substrate. Without the deep nwell layer in the same cell as the
|
||||
* transistor, the transistor will be extracted with the bulk terminal
|
||||
* connected to the substrate.
|
||||
*
|
||||
* Note that the act of copying material down into a subcell means that
|
||||
* material is then present in all instances of the subcell. There is
|
||||
* no implementation as yet to handle the case where some instances of the
|
||||
* same subcell require <layers> and some don't, which would necessitate
|
||||
* splitting the subcell into (at least) two different subcells, one
|
||||
* containing <layers> and one not. This needs to be implemented. A
|
||||
* possible implementation would be: 1st pass: Find all subcells that
|
||||
* will be modified. Make a list of the instances that will be modified.
|
||||
* After the first pass, check if the list of instances contains all
|
||||
* instances of the cell def. If so, then just modify the cell def. If
|
||||
* not, then make a copy the cell def and split off the instances that
|
||||
* get the modification to point to that cell def, then modify that cell
|
||||
* def. 2nd pass: Run the "drop" command as before.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Subcells are modified by adding paint.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
CmdDrop(w, cmd)
|
||||
MagWindow *w;
|
||||
TxCommand *cmd;
|
||||
{
|
||||
TileType i;
|
||||
TileTypeBitMask lMask, tMask;
|
||||
CellUse *checkUse;
|
||||
int pNum;
|
||||
Rect editBox;
|
||||
|
||||
if (cmd->tx_argc != 2)
|
||||
{
|
||||
TxError("Usage: %s layers\n", cmd->tx_argv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ToolGetEditBox(&editBox)) return;
|
||||
if (!CmdParseLayers(cmd->tx_argv[1], &lMask))
|
||||
return;
|
||||
|
||||
checkUse = NULL;
|
||||
if (EditRootDef == SelectRootDef)
|
||||
checkUse = EditCellUse;
|
||||
if (checkUse == NULL)
|
||||
{
|
||||
if (w == (MagWindow *)NULL)
|
||||
windCheckOnlyWindow(&w, DBWclientID);
|
||||
if (w) checkUse = (CellUse *)w->w_surfaceID;
|
||||
}
|
||||
if ((checkUse == NULL) || (checkUse->cu_def != SelectRootDef))
|
||||
{
|
||||
TxError("The selection does not match the edit cell.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
TTMaskZero(&tMask);
|
||||
SelEnumPaint(&DBAllButSpaceAndDRCBits, FALSE, (bool *)NULL,
|
||||
cmdDropPaintFunc, (ClientData)&tMask);
|
||||
|
||||
if (TTMaskIsZero(&tMask)) return; /* Nothing selected */
|
||||
|
||||
for (i = TT_SELECTBASE; i < DBNumUserLayers; i++)
|
||||
{
|
||||
if (TTMaskHasType(&tMask, i))
|
||||
{
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
if (TTMaskHasType(&DBPlaneTypes[pNum], i))
|
||||
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum],
|
||||
&SelectUse->cu_bbox, &tMask,
|
||||
cmdDropFunc, (ClientData)&lMask);
|
||||
}
|
||||
}
|
||||
|
||||
DRCCheckThis(EditCellUse->cu_def, TT_CHECKPAINT, &editBox);
|
||||
DBWAreaChanged(EditCellUse->cu_def, &editBox, DBW_ALLWINDOWS, &tMask);
|
||||
DBReComputeBbox(EditCellUse->cu_def);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
|
|||
|
|
@ -880,6 +880,7 @@ cmdExpandFunc(use, windowMask)
|
|||
#define DOLENGTH 4
|
||||
#define DOLOCAL 5
|
||||
#define DORESISTANCE 6
|
||||
#define DOLABELCHECK 7
|
||||
|
||||
#define LENCLEAR 0
|
||||
#define LENDRIVER 1
|
||||
|
|
@ -922,6 +923,7 @@ CmdExtract(w, cmd)
|
|||
"length compute driver-receiver pathlengths",
|
||||
"local put all generated files in the current directory",
|
||||
"resistance estimate resistance",
|
||||
"labelcheck check for connections through sticky labels",
|
||||
NULL
|
||||
};
|
||||
static char *cmdExtLength[] =
|
||||
|
|
@ -1141,6 +1143,7 @@ CmdExtract(w, cmd)
|
|||
TxPrintf("%s length\n", OPTSET(EXT_DOLENGTH));
|
||||
TxPrintf("%s local\n", OPTSET(EXT_DOLOCAL));
|
||||
TxPrintf("%s resistance\n", OPTSET(EXT_DORESISTANCE));
|
||||
TxPrintf("%s label check\n", OPTSET(EXT_DOLABELCHECK));
|
||||
return;
|
||||
#undef OPTSET
|
||||
}
|
||||
|
|
@ -1169,6 +1172,7 @@ CmdExtract(w, cmd)
|
|||
case DOLENGTH: option = EXT_DOLENGTH; break;
|
||||
case DOLOCAL: option = EXT_DOLOCAL; break;
|
||||
case DORESISTANCE: option = EXT_DORESISTANCE; break;
|
||||
case DOLABELCHECK: option = EXT_DOLABELCHECK; break;
|
||||
}
|
||||
if (no) ExtOptions &= ~option;
|
||||
else ExtOptions |= option;
|
||||
|
|
|
|||
|
|
@ -1865,6 +1865,7 @@ flatCopyAllLabels(scx, lab, tpath, targetUse)
|
|||
{
|
||||
Rect labTargetRect;
|
||||
int targetPos;
|
||||
int flags = 0;
|
||||
CellDef *def;
|
||||
char labelname[1024];
|
||||
char *n, *f, c;
|
||||
|
|
@ -1894,6 +1895,8 @@ flatCopyAllLabels(scx, lab, tpath, targetUse)
|
|||
* not a port; possibly we should retain ports taken from the
|
||||
* top level cell, but certainly not any others.
|
||||
*/
|
||||
if (tpath && (*tpath->tp_first) == '\0')
|
||||
flags = lab->lab_flags;
|
||||
|
||||
/* To-do Feb. 2008: Translate target rotation and offset */
|
||||
|
||||
|
|
@ -1903,7 +1906,7 @@ flatCopyAllLabels(scx, lab, tpath, targetUse)
|
|||
strcpy(n, lab->lab_text);
|
||||
DBPutFontLabel(def, &labTargetRect, lab->lab_font, lab->lab_size,
|
||||
lab->lab_rotate, &lab->lab_offset, targetPos,
|
||||
f, lab->lab_type, 0);
|
||||
f, lab->lab_type, flags);
|
||||
*n = c;
|
||||
|
||||
return 0;
|
||||
|
|
@ -1932,7 +1935,7 @@ CmdFlatten(w, cmd)
|
|||
TxCommand *cmd;
|
||||
{
|
||||
int rval, xMask;
|
||||
bool dolabels, dobox, toplabels, invert;
|
||||
bool dolabels, dobox, toplabels, invert, doports;
|
||||
char *destname;
|
||||
CellDef *newdef;
|
||||
CellUse *newuse;
|
||||
|
|
@ -1944,6 +1947,7 @@ CmdFlatten(w, cmd)
|
|||
dolabels = TRUE;
|
||||
toplabels = FALSE;
|
||||
dobox = FALSE;
|
||||
doports = TRUE;
|
||||
|
||||
rval = 0;
|
||||
if (cmd->tx_argc > 2)
|
||||
|
|
@ -1978,6 +1982,9 @@ CmdFlatten(w, cmd)
|
|||
case 't':
|
||||
toplabels = (invert) ? FALSE : TRUE;
|
||||
break;
|
||||
case 'p':
|
||||
doports = (invert) ? FALSE : TRUE;
|
||||
break;
|
||||
case 's':
|
||||
xMask = (invert) ? CU_DESCEND_NO_SUBCKT : CU_DESCEND_ALL;
|
||||
break;
|
||||
|
|
@ -1985,7 +1992,7 @@ CmdFlatten(w, cmd)
|
|||
xMask = (invert) ? CU_DESCEND_NO_VENDOR : CU_DESCEND_ALL;
|
||||
break;
|
||||
default:
|
||||
TxError("options are: -nolabels, -nosubcircuits "
|
||||
TxError("options are: -nolabels, -nosubcircuits, -noports, "
|
||||
"-novendor, -dotoplabels, -dobox\n");
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
|
||||
void CmdPaintEraseButton();
|
||||
|
||||
/* See the SetLabel command */
|
||||
|
||||
extern Label *DefaultLabel;
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
|
|
@ -169,8 +172,8 @@ CmdLabel(w, cmd)
|
|||
MagWindow *w;
|
||||
TxCommand *cmd;
|
||||
{
|
||||
TileType type;
|
||||
int pos, font = -1, size = 0, rotate = 0, offx = 0, offy = 0;
|
||||
TileType type = (TileType)(-1);
|
||||
int pos = -1, font = -1, size = 0, rotate = 0, offx = 0, offy = 0;
|
||||
bool sticky = FALSE;
|
||||
int option;
|
||||
char *p;
|
||||
|
|
@ -185,6 +188,22 @@ CmdLabel(w, cmd)
|
|||
|
||||
p = cmd->tx_argv[1];
|
||||
|
||||
/*
|
||||
* If the "setlabel" command has been used to set defaults, pick up
|
||||
* the default values from DefaultLabel.
|
||||
*/
|
||||
if (DefaultLabel != NULL)
|
||||
{
|
||||
pos = DefaultLabel->lab_just;
|
||||
font = DefaultLabel->lab_font;
|
||||
size = DefaultLabel->lab_size;
|
||||
rotate = DefaultLabel->lab_rotate;
|
||||
offx = DefaultLabel->lab_offset.p_x;
|
||||
offy = DefaultLabel->lab_offset.p_y;
|
||||
sticky = (DefaultLabel->lab_flags & LABEL_STICKY) ? 1 : 0;
|
||||
type = DefaultLabel->lab_type;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find and check validity of position.
|
||||
*/
|
||||
|
|
@ -220,13 +239,14 @@ CmdLabel(w, cmd)
|
|||
else
|
||||
pos = GeoTransPos(&RootToEditTransform, pos);
|
||||
}
|
||||
else pos = -1;
|
||||
|
||||
if (font >= 0)
|
||||
{
|
||||
char *yp = NULL;
|
||||
|
||||
size = DBLambda[1];
|
||||
if (DefaultLabel == NULL)
|
||||
size = DBLambda[1];
|
||||
|
||||
if (cmd->tx_argc > 3)
|
||||
if (StrIsNumeric(cmd->tx_argv[3]))
|
||||
size = cmdScaleCoord(w, cmd->tx_argv[3], TRUE, TRUE, 8);
|
||||
|
|
@ -304,7 +324,7 @@ CmdLabel(w, cmd)
|
|||
TxError("Unknown layer: %s\n", cmd->tx_argv[cmd->tx_argc - 1]);
|
||||
return;
|
||||
}
|
||||
} else type = -1;
|
||||
}
|
||||
|
||||
CmdLabelProc(p, font, size, rotate, offx, offy, pos, sticky, type);
|
||||
}
|
||||
|
|
@ -1292,7 +1312,7 @@ complabel(const void *one, const void *two)
|
|||
* or
|
||||
* port makeall|renumber [connect_direction(s)]
|
||||
* or
|
||||
* port [name|num] class|use|shape|index [value]
|
||||
* port [name|num] class|use|shape|index|name [value] [-quiet]
|
||||
*
|
||||
* num is the index of the port, usually beginning with 1. This indicates
|
||||
* the order in which ports should be written to a subcircuit record
|
||||
|
|
@ -1310,6 +1330,9 @@ complabel(const void *one, const void *two)
|
|||
* "value" is a value string representing one of the valid port classes
|
||||
* or uses.
|
||||
*
|
||||
* The "-quiet" option causes magic to fail quietly and return (in Tcl)
|
||||
* an empty string if the value requested does not exist.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
|
|
@ -1346,7 +1369,7 @@ CmdPort(w, cmd)
|
|||
int i, refidx, idx, pos, type, option, argc;
|
||||
unsigned int dirmask;
|
||||
bool found;
|
||||
bool nonEdit = FALSE;
|
||||
bool nonEdit = FALSE, doQuiet = FALSE;
|
||||
Label *lab, *sl;
|
||||
Rect editBox, tmpArea;
|
||||
CellDef *editDef = EditCellUse->cu_def;
|
||||
|
|
@ -1441,6 +1464,16 @@ CmdPort(w, cmd)
|
|||
|
||||
argstart = 1;
|
||||
argc = cmd->tx_argc;
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
if (!strcmp(cmd->tx_argv[argc - 1], "-quiet"))
|
||||
{
|
||||
doQuiet = TRUE;
|
||||
argc--;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > 6 || argc == 1)
|
||||
goto portWrongNumArgs;
|
||||
else
|
||||
|
|
@ -1483,10 +1516,13 @@ CmdPort(w, cmd)
|
|||
}
|
||||
if (lab == NULL)
|
||||
{
|
||||
if (StrIsInt(cmd->tx_argv[1]))
|
||||
TxError("No label found with index %s.\n", cmd->tx_argv[1]);
|
||||
else
|
||||
TxError("No port found with name %s.\n", cmd->tx_argv[1]);
|
||||
if (!doQuiet)
|
||||
{
|
||||
if (StrIsInt(cmd->tx_argv[1]))
|
||||
TxError("No label found with index %s.\n", cmd->tx_argv[1]);
|
||||
else
|
||||
TxError("No port found with name %s.\n", cmd->tx_argv[1]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
argstart = 2;
|
||||
|
|
@ -1554,7 +1590,7 @@ CmdPort(w, cmd)
|
|||
/* label "lab" must already be a port */
|
||||
if (!(lab->lab_flags & PORT_DIR_MASK))
|
||||
{
|
||||
if (option != PORT_REMOVE)
|
||||
if ((option != PORT_REMOVE) && (!doQuiet))
|
||||
TxError("The selected label is not a port.\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -1946,8 +1982,11 @@ parseindex:
|
|||
if ((option != PORT_MAKEALL) && (lab->lab_flags & PORT_DIR_MASK))
|
||||
{
|
||||
/* For this syntax, the label must not already be a port */
|
||||
TxError("The selected label is already a port.\n");
|
||||
TxError("Do \"port help\" to get a list of options.\n");
|
||||
if (!doQuiet)
|
||||
{
|
||||
TxError("The selected label is already a port.\n");
|
||||
TxError("Do \"port help\" to get a list of options.\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
526
commands/CmdRS.c
526
commands/CmdRS.c
|
|
@ -54,6 +54,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
|
||||
extern void DisplayWindow();
|
||||
|
||||
/* Used by CmdSetLabel() */
|
||||
Label *DefaultLabel;
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -525,6 +528,26 @@ CmdSee(w, cmd)
|
|||
return;
|
||||
}
|
||||
|
||||
#define SEL_AREA 0
|
||||
#define SEL_VISIBLE 1
|
||||
#define SEL_CELL 2
|
||||
#define SEL_LABELS 3
|
||||
#define SEL_INTERSECT 4
|
||||
#define SEL_CLEAR 5
|
||||
#define SEL_FLAT 6
|
||||
#define SEL_HELP 7
|
||||
#define SEL_KEEP 8
|
||||
#define SEL_MOVE 9
|
||||
#define SEL_PICK 10
|
||||
#define SEL_SAVE 11
|
||||
#define SEL_FEEDBACK 12
|
||||
#define SEL_BBOX 13
|
||||
#define SEL_BOX 14
|
||||
#define SEL_CHUNK 15
|
||||
#define SEL_REGION 16
|
||||
#define SEL_NET 17
|
||||
#define SEL_SHORT 18
|
||||
#define SEL_DEFAULT 19
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
|
|
@ -547,86 +570,10 @@ CmdSee(w, cmd)
|
|||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
cmdSelectArea(layers, less)
|
||||
char *layers; /* Which layers are to be selected. */
|
||||
bool less;
|
||||
{
|
||||
SearchContext scx;
|
||||
TileTypeBitMask mask;
|
||||
int windowMask, xMask;
|
||||
DBWclientRec *crec;
|
||||
MagWindow *window;
|
||||
|
||||
bzero(&scx, sizeof(SearchContext));
|
||||
window = ToolGetBoxWindow(&scx.scx_area, &windowMask);
|
||||
if (window == NULL)
|
||||
{
|
||||
TxPrintf("The box isn't in a window.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Since the box may actually be in multiple windows, we have to
|
||||
* be a bit careful. If the box is only in one window, then there's
|
||||
* no problem. If it's in more than window, the cursor must
|
||||
* disambiguate the windows.
|
||||
*/
|
||||
|
||||
xMask = ((DBWclientRec *) window->w_clientData)->dbw_bitmask;
|
||||
if ((windowMask & ~xMask) != 0)
|
||||
{
|
||||
window = CmdGetRootPoint((Point *) NULL, (Rect *) NULL);
|
||||
xMask = ((DBWclientRec *) window->w_clientData)->dbw_bitmask;
|
||||
if ((windowMask & xMask) == 0)
|
||||
{
|
||||
TxPrintf("The box is in more than one window; use the cursor\n");
|
||||
TxPrintf("to select the one you want to select from.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (CmdParseLayers(layers, &mask))
|
||||
{
|
||||
if (TTMaskEqual(&mask, &DBSpaceBits))
|
||||
(void) CmdParseLayers("*,label", &mask);
|
||||
TTMaskClearType(&mask, TT_SPACE);
|
||||
}
|
||||
else return;
|
||||
|
||||
if (less)
|
||||
{
|
||||
(void) SelRemoveArea(&scx.scx_area, &mask);
|
||||
return;
|
||||
}
|
||||
|
||||
scx.scx_use = (CellUse *) window->w_surfaceID;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
crec = (DBWclientRec *) window->w_clientData;
|
||||
SelectArea(&scx, &mask, crec->dbw_bitmask);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cmdSelectVisible --
|
||||
*
|
||||
* This is a utility procedure used by CmdSelect to do area
|
||||
* selection of visible paint.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* The selection is augmented to contain all the information on
|
||||
* layers that is visible under the box, including paint, labels,
|
||||
* and expanded subcells.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
cmdSelectVisible(layers, less)
|
||||
cmdSelectArea(layers, less, option)
|
||||
char *layers; /* Which layers are to be selected. */
|
||||
bool less;
|
||||
int option; /* Option from defined list above */
|
||||
{
|
||||
SearchContext scx;
|
||||
TileTypeBitMask mask;
|
||||
|
|
@ -677,6 +624,7 @@ cmdSelectVisible(layers, less)
|
|||
scx.scx_use = (CellUse *) window->w_surfaceID;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
crec = (DBWclientRec *) window->w_clientData;
|
||||
if (option == SEL_VISIBLE)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < DBNumUserLayers; i++)
|
||||
|
|
@ -688,6 +636,85 @@ cmdSelectVisible(layers, less)
|
|||
SelectArea(&scx, &mask, crec->dbw_bitmask);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cmdIntersectArea --
|
||||
*
|
||||
* This is a utility procedure used by CmdSelect to do area
|
||||
* selection itersect.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* The selection is pared down to contain only the part of the
|
||||
* original selection that intersects with the type "layer".
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
cmdIntersectArea(layer)
|
||||
char *layer; /* The layer to intersect with */
|
||||
{
|
||||
TileType ttype;
|
||||
SearchContext scx;
|
||||
int windowMask, xMask;
|
||||
DBWclientRec *crec;
|
||||
MagWindow *window;
|
||||
char *lptr;
|
||||
bool negate = FALSE;
|
||||
|
||||
bzero(&scx, sizeof(SearchContext));
|
||||
window = ToolGetBoxWindow(&scx.scx_area, &windowMask);
|
||||
if (window == NULL)
|
||||
{
|
||||
TxPrintf("The box isn't in a window.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Since the box may actually be in multiple windows, we have to
|
||||
* be a bit careful. If the box is only in one window, then there's
|
||||
* no problem. If it's in more than window, the cursor must
|
||||
* disambiguate the windows.
|
||||
*/
|
||||
|
||||
xMask = ((DBWclientRec *) window->w_clientData)->dbw_bitmask;
|
||||
if ((windowMask & ~xMask) != 0)
|
||||
{
|
||||
window = CmdGetRootPoint((Point *) NULL, (Rect *) NULL);
|
||||
xMask = ((DBWclientRec *) window->w_clientData)->dbw_bitmask;
|
||||
if ((windowMask & xMask) == 0)
|
||||
{
|
||||
TxPrintf("The box is in more than one window; use the cursor\n");
|
||||
TxPrintf("to select the one you want to select from.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
scx.scx_use = (CellUse *) window->w_surfaceID;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
crec = (DBWclientRec *) window->w_clientData;
|
||||
|
||||
/* Special behavior: "!" or "~" in front of layer name intersects */
|
||||
/* with NOT(layer). */
|
||||
|
||||
lptr = layer;
|
||||
if ((*lptr == '~') || (*lptr == '!'))
|
||||
{
|
||||
negate = TRUE;
|
||||
lptr++;
|
||||
}
|
||||
|
||||
ttype = DBTechNameType(lptr);
|
||||
if (ttype < 0) {
|
||||
TxError("Cannot parse layer type \"%s\".\n", layer);
|
||||
return;
|
||||
}
|
||||
SelectIntersect(&scx, ttype, crec->dbw_bitmask, negate);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -725,30 +752,13 @@ CmdSelect(w, cmd)
|
|||
* second table, due to a help message for ":select" with no arguments.
|
||||
*/
|
||||
|
||||
#define SEL_AREA 0
|
||||
#define SEL_VISIBLE 1
|
||||
#define SEL_CELL 2
|
||||
#define SEL_CLEAR 3
|
||||
#define SEL_FLAT 4
|
||||
#define SEL_HELP 5
|
||||
#define SEL_KEEP 6
|
||||
#define SEL_MOVE 7
|
||||
#define SEL_PICK 8
|
||||
#define SEL_SAVE 9
|
||||
#define SEL_FEEDBACK 10
|
||||
#define SEL_BBOX 11
|
||||
#define SEL_BOX 12
|
||||
#define SEL_CHUNK 13
|
||||
#define SEL_REGION 14
|
||||
#define SEL_NET 15
|
||||
#define SEL_SHORT 16
|
||||
#define SEL_DEFAULT 17
|
||||
|
||||
static char *cmdSelectOption[] =
|
||||
{
|
||||
"area",
|
||||
"visible",
|
||||
"cell",
|
||||
"labels",
|
||||
"intersection",
|
||||
"clear",
|
||||
"flat",
|
||||
"help",
|
||||
|
|
@ -774,6 +784,8 @@ CmdSelect(w, cmd)
|
|||
"[more | less] area [layers] [de]select all info under box in layers",
|
||||
"[more | less] visible [layers] [de]select all visible info under box in layers",
|
||||
"[more | less | top] cell [name] [de]select cell under cursor, or \"name\"",
|
||||
"[do | no] labels [do not] select subcell labels",
|
||||
"[more | less] intersection [layers] [de]select intersection of layers",
|
||||
"clear clear selection",
|
||||
"flat flatten the contents of the selection",
|
||||
"help print this message",
|
||||
|
|
@ -819,7 +831,7 @@ CmdSelect(w, cmd)
|
|||
* also used to step through multiple uses.
|
||||
*/
|
||||
static bool lessCycle = FALSE, lessCellCycle = FALSE;
|
||||
char path[200], *printPath, **msg, **optionArgs, *feedtext;
|
||||
char path[200], *printPath, **msg, **optionArgs, *feedtext, *pstr;
|
||||
TerminalPath tpath;
|
||||
CellUse *use;
|
||||
CellDef *rootBoxDef;
|
||||
|
|
@ -832,6 +844,7 @@ CmdSelect(w, cmd)
|
|||
bool layerspec;
|
||||
bool degenerate;
|
||||
bool more = FALSE, less = FALSE, samePlace = TRUE;
|
||||
unsigned char labelpolicy = SEL_DO_LABELS;
|
||||
#ifdef MAGIC_WRAPPER
|
||||
char *tclstr;
|
||||
Tcl_Obj *lobj;
|
||||
|
|
@ -851,7 +864,7 @@ CmdSelect(w, cmd)
|
|||
|
||||
/* See if "more" was given. If so, just strip off the "more" from
|
||||
* the argument list and set the "more" flag. Similarly for options
|
||||
* "less", "nocycle", "top", and "cell".
|
||||
* "less", "do", "no", "nocycle", "top", and "cell".
|
||||
*/
|
||||
|
||||
if (cmd->tx_argc >= 2)
|
||||
|
|
@ -876,6 +889,7 @@ CmdSelect(w, cmd)
|
|||
else if (!strncmp(cmd->tx_argv[1], "nocycle", arg1len))
|
||||
{
|
||||
samePlace = FALSE;
|
||||
labelpolicy = SEL_NO_LABELS;
|
||||
more = FALSE;
|
||||
less = FALSE;
|
||||
type = TT_SELECTBASE - 1; /* avoid cycling between types */
|
||||
|
|
@ -890,6 +904,24 @@ CmdSelect(w, cmd)
|
|||
optionArgs = &cmd->tx_argv[2];
|
||||
cmd->tx_argc--;
|
||||
}
|
||||
else if (!strncmp(cmd->tx_argv[1], "do", arg1len))
|
||||
{
|
||||
labelpolicy = SEL_DO_LABELS;
|
||||
optionArgs = &cmd->tx_argv[2];
|
||||
cmd->tx_argc--;
|
||||
}
|
||||
else if (!strncmp(cmd->tx_argv[1], "no", arg1len))
|
||||
{
|
||||
labelpolicy = SEL_NO_LABELS;
|
||||
optionArgs = &cmd->tx_argv[2];
|
||||
cmd->tx_argc--;
|
||||
}
|
||||
else if (!strncmp(cmd->tx_argv[1], "simple", arg1len))
|
||||
{
|
||||
labelpolicy = SEL_SIMPLE_LABELS;
|
||||
optionArgs = &cmd->tx_argv[2];
|
||||
cmd->tx_argc--;
|
||||
}
|
||||
|
||||
else if (!strncmp(cmd->tx_argv[1], "top", arg1len))
|
||||
{
|
||||
|
|
@ -954,7 +986,7 @@ CmdSelect(w, cmd)
|
|||
}
|
||||
if (!(more || less)) SelectClear();
|
||||
if (cmd->tx_argc == 3)
|
||||
cmdSelectArea(optionArgs[1], less);
|
||||
cmdSelectArea(optionArgs[1], less, option);
|
||||
else cmdSelectArea("*,label,subcell", less);
|
||||
return;
|
||||
|
||||
|
|
@ -968,8 +1000,18 @@ CmdSelect(w, cmd)
|
|||
if (cmd->tx_argc > 3) goto usageError;
|
||||
if (!(more || less)) SelectClear();
|
||||
if (cmd->tx_argc == 3)
|
||||
cmdSelectVisible(optionArgs[1], less);
|
||||
else cmdSelectVisible("*,label,subcell", less);
|
||||
cmdSelectArea(optionArgs[1], less, option);
|
||||
else cmdSelectArea("*,label,subcell", less, option);
|
||||
return;
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
* Select area that is the intersection of all the specified layers
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
case SEL_INTERSECT:
|
||||
if (cmd->tx_argc > 3) goto usageError;
|
||||
cmdIntersectArea(optionArgs[1]);
|
||||
return;
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
|
|
@ -982,6 +1024,14 @@ CmdSelect(w, cmd)
|
|||
SelectClear();
|
||||
return;
|
||||
|
||||
case SEL_LABELS:
|
||||
SelectDoLabels = labelpolicy;
|
||||
if (SelectDoLabels)
|
||||
TxPrintf("Selection includes subcell labels\n");
|
||||
else
|
||||
TxPrintf("Selection ignores subcell labels\n");
|
||||
return;
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
* Print out help information.
|
||||
*--------------------------------------------------------------------
|
||||
|
|
@ -1526,6 +1576,13 @@ Okay:
|
|||
DBWSetBox(scx.scx_use->cu_def, &r);
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
/* Remove any backslash escapes so that Tcl_escape() doesn't
|
||||
* double-escape them.
|
||||
*/
|
||||
for (pstr = printPath; *pstr != '\0';)
|
||||
if ((*pstr == '\\') && ((*(pstr + 1) == '[') || (*(pstr + 1) == ']')))
|
||||
memmove(pstr, pstr + 1, 1 + strlen(pstr + 1));
|
||||
else pstr++;
|
||||
tclstr = Tcl_escape(printPath);
|
||||
Tcl_SetResult(magicinterp, tclstr, TCL_DYNAMIC);
|
||||
#else
|
||||
|
|
@ -1854,8 +1911,7 @@ cmdLabelFontFunc(label, cellUse, transform, font)
|
|||
* Query or change properties of a (selected) label in the edit cell
|
||||
*
|
||||
* Usage:
|
||||
* setlabel option [name]
|
||||
*
|
||||
* setlabel [-default] option [name]
|
||||
*
|
||||
* Option may be one of:
|
||||
* text
|
||||
|
|
@ -1875,6 +1931,11 @@ cmdLabelFontFunc(label, cellUse, transform, font)
|
|||
* "setlabel font <name>" can be used without any select to load fonts
|
||||
* from a startup script.
|
||||
*
|
||||
* Use with "-default" causes the DefaultLabel structure to be created
|
||||
* (if not existing already) and set with the given value. Subsequent
|
||||
* use of the "label" command will start with the given defaults, then
|
||||
* apply whatever non-default values are specified in the command.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -1895,10 +1956,12 @@ CmdSetLabel(w, cmd)
|
|||
TxCommand *cmd;
|
||||
{
|
||||
int pos = -1, font = -1, size = 0, rotate = 0, flags = 0;
|
||||
int locargc, argstart = 1;
|
||||
char **msg;
|
||||
Point offset;
|
||||
TileType ttype;
|
||||
int option;
|
||||
bool doDefault = FALSE;
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_Obj *lobj;
|
||||
#endif
|
||||
|
|
@ -1921,10 +1984,34 @@ CmdSetLabel(w, cmd)
|
|||
NULL
|
||||
};
|
||||
|
||||
if (cmd->tx_argc < 2 || cmd->tx_argc > 4)
|
||||
locargc = cmd->tx_argc;
|
||||
if (locargc > 2)
|
||||
{
|
||||
if (!strncmp(cmd->tx_argv[1], "-def", 4))
|
||||
{
|
||||
if (DefaultLabel == NULL)
|
||||
{
|
||||
DefaultLabel = (Label *)mallocMagic(sizeof(Label));
|
||||
/* Set default defaults (lab_text is ignored) */
|
||||
DefaultLabel->lab_just = -1;
|
||||
DefaultLabel->lab_size = 0;
|
||||
DefaultLabel->lab_font = -1;
|
||||
DefaultLabel->lab_rotate = 0;
|
||||
DefaultLabel->lab_flags = 0;
|
||||
DefaultLabel->lab_offset.p_x = 0;
|
||||
DefaultLabel->lab_offset.p_y = 0;
|
||||
DefaultLabel->lab_type = (TileType)(-1);
|
||||
}
|
||||
doDefault = TRUE;
|
||||
locargc--;
|
||||
argstart++;
|
||||
}
|
||||
}
|
||||
|
||||
if (locargc < 2 || locargc > 4)
|
||||
option = SETLABEL_HELP;
|
||||
else
|
||||
option = Lookup(cmd->tx_argv[1], cmdLabelSetOption);
|
||||
option = Lookup(cmd->tx_argv[argstart], cmdLabelSetOption);
|
||||
|
||||
switch (option)
|
||||
{
|
||||
|
|
@ -1943,20 +2030,27 @@ CmdSetLabel(w, cmd)
|
|||
break;
|
||||
|
||||
case SETLABEL_TEXT:
|
||||
if (EditCellUse)
|
||||
if (doDefault)
|
||||
{
|
||||
TxError("Cannot set a default label text.\n");
|
||||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelTextFunc, (cmd->tx_argc == 3) ?
|
||||
(ClientData)cmd->tx_argv[2] : (ClientData)NULL);
|
||||
cmdLabelTextFunc, (locargc == 3) ?
|
||||
(ClientData)cmd->tx_argv[argstart + 1] : (ClientData)NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case SETLABEL_FONT:
|
||||
if (cmd->tx_argc >= 2 && cmd->tx_argc <= 4)
|
||||
if (locargc >= 2 && locargc <= 4)
|
||||
{
|
||||
if ((cmd->tx_argc == 3) && StrIsInt(cmd->tx_argv[2]))
|
||||
/* This option is used to see the font name corresponding
|
||||
* to a font number.
|
||||
*/
|
||||
if ((locargc == 3) && StrIsInt(cmd->tx_argv[argstart + 1]))
|
||||
{
|
||||
int font = atoi(cmd->tx_argv[2]);
|
||||
int font = atoi(cmd->tx_argv[argstart + 1]);
|
||||
if (font < -1 || font >= DBNumFonts)
|
||||
{
|
||||
if (DBNumFonts == 0)
|
||||
|
|
@ -1970,67 +2064,118 @@ CmdSetLabel(w, cmd)
|
|||
else
|
||||
TxPrintf("%s\n", DBFontList[font]->mf_name);
|
||||
}
|
||||
else if ((cmd->tx_argc == 3 || cmd->tx_argc == 4) &&
|
||||
!StrIsInt(cmd->tx_argv[2]))
|
||||
else if ((locargc == 3 || locargc == 4) &&
|
||||
!StrIsInt(cmd->tx_argv[argstart + 1]))
|
||||
{
|
||||
font = DBNameToFont(cmd->tx_argv[2]);
|
||||
font = DBNameToFont(cmd->tx_argv[argstart + 1]);
|
||||
if (font < -1)
|
||||
{
|
||||
float scale = 1.0;
|
||||
if ((cmd->tx_argc == 4) && StrIsNumeric(cmd->tx_argv[3]))
|
||||
scale = (float)atof(cmd->tx_argv[3]);
|
||||
if (DBLoadFont(cmd->tx_argv[2], scale) != 0)
|
||||
TxError("Error loading font \"%s\"\n", cmd->tx_argv[2]);
|
||||
font = DBNameToFont(cmd->tx_argv[2]);
|
||||
if ((locargc == 4) && StrIsNumeric(cmd->tx_argv[argstart + 2]))
|
||||
scale = (float)atof(cmd->tx_argv[argstart + 2]);
|
||||
if (DBLoadFont(cmd->tx_argv[argstart + 1], scale) != 0)
|
||||
TxError("Error loading font \"%s\"\n", cmd->tx_argv[argstart + 1]);
|
||||
font = DBNameToFont(cmd->tx_argv[argstart + 1]);
|
||||
if (font < -1) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (EditCellUse)
|
||||
if (doDefault)
|
||||
{
|
||||
if (locargc == 2)
|
||||
{
|
||||
font = DefaultLabel->lab_font;
|
||||
if (font == -1)
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetResult(magicinterp, "default", TCL_VOLATILE);
|
||||
#else
|
||||
TxPrintf("default\n");
|
||||
#endif
|
||||
else
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp,
|
||||
Tcl_NewStringObj(DBFontList[font]->mf_name, -1));
|
||||
#else
|
||||
TxPrintf("%s\n", DBFontList[font]->mf_name);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
DefaultLabel->lab_font = font;
|
||||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelFontFunc, (cmd->tx_argc == 3) ?
|
||||
cmdLabelFontFunc, (locargc == 3) ?
|
||||
(ClientData)&font : (ClientData)NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SETLABEL_JUSTIFY:
|
||||
if (cmd->tx_argc == 3)
|
||||
if (locargc == 3)
|
||||
{
|
||||
pos = GeoNameToPos(cmd->tx_argv[2], FALSE, TRUE);
|
||||
pos = GeoNameToPos(cmd->tx_argv[argstart + 1], FALSE, TRUE);
|
||||
if (pos < 0) break;
|
||||
}
|
||||
if (EditCellUse)
|
||||
if (doDefault)
|
||||
{
|
||||
if (locargc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp,
|
||||
Tcl_NewStringObj(GeoPosToName(DefaultLabel->lab_just),
|
||||
-1));
|
||||
#else
|
||||
TxPrintf("%s\n", GeoPosToName(DefaultLabel->lab_just));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
DefaultLabel->lab_just = pos;
|
||||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelJustFunc, (cmd->tx_argc == 3) ?
|
||||
cmdLabelJustFunc, (locargc == 3) ?
|
||||
(ClientData)&pos : (ClientData)NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case SETLABEL_SIZE:
|
||||
if (cmd->tx_argc == 3)
|
||||
if (locargc == 3)
|
||||
{
|
||||
if (StrIsNumeric(cmd->tx_argv[2]))
|
||||
size = cmdScaleCoord(w, cmd->tx_argv[2], TRUE, TRUE, 8);
|
||||
if (StrIsNumeric(cmd->tx_argv[argstart + 1]))
|
||||
size = cmdScaleCoord(w, cmd->tx_argv[argstart + 1], TRUE, TRUE, 8);
|
||||
if (size <= 0) break;
|
||||
}
|
||||
if (EditCellUse)
|
||||
if (doDefault)
|
||||
{
|
||||
if (locargc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp,
|
||||
Tcl_NewIntObj(DefaultLabel->lab_size));
|
||||
#else
|
||||
TxPrintf("%d\n", DefaultLabel->lab_size);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
DefaultLabel->lab_size = size;
|
||||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelSizeFunc, (cmd->tx_argc == 3) ?
|
||||
cmdLabelSizeFunc, (locargc == 3) ?
|
||||
(ClientData)&size : (ClientData)NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case SETLABEL_OFFSET:
|
||||
if (cmd->tx_argc == 3)
|
||||
if (locargc == 3)
|
||||
{
|
||||
char *yp;
|
||||
if ((yp = strchr(cmd->tx_argv[2], ' ')) != NULL)
|
||||
if ((yp = strchr(cmd->tx_argv[argstart + 1], ' ')) != NULL)
|
||||
{
|
||||
offset.p_x = cmdScaleCoord(w, cmd->tx_argv[2], TRUE, TRUE, 8);
|
||||
offset.p_x = cmdScaleCoord(w, cmd->tx_argv[argstart + 1], TRUE, TRUE, 8);
|
||||
offset.p_y = cmdScaleCoord(w, yp, TRUE, FALSE, 8);
|
||||
}
|
||||
else
|
||||
|
|
@ -2039,67 +2184,138 @@ CmdSetLabel(w, cmd)
|
|||
return;
|
||||
}
|
||||
}
|
||||
else if (cmd->tx_argc == 4)
|
||||
else if (locargc == 4)
|
||||
{
|
||||
offset.p_x = cmdScaleCoord(w, cmd->tx_argv[2], TRUE, TRUE, 8);
|
||||
offset.p_y = cmdScaleCoord(w, cmd->tx_argv[3], TRUE, FALSE, 8);
|
||||
offset.p_x = cmdScaleCoord(w, cmd->tx_argv[argstart + 1], TRUE, TRUE, 8);
|
||||
offset.p_y = cmdScaleCoord(w, cmd->tx_argv[argstart + 2], TRUE, FALSE, 8);
|
||||
}
|
||||
if (EditCellUse)
|
||||
if (doDefault)
|
||||
{
|
||||
if (locargc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_Obj *lobj;
|
||||
Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewIntObj(DefaultLabel->lab_offset.p_x));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewIntObj(DefaultLabel->lab_offset.p_y));
|
||||
Tcl_SetObjResult(magicinterp, lobj);
|
||||
#else
|
||||
TxPrintf("%d %d\n", DefaultLabel->lab_offset.p_x,
|
||||
DefaultLabel->lab_offset.p_y);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
DefaultLabel->lab_offset = offset;
|
||||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelOffsetFunc, (cmd->tx_argc != 2) ?
|
||||
cmdLabelOffsetFunc, (locargc != 2) ?
|
||||
(ClientData)&offset : (ClientData)NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case SETLABEL_ROTATE:
|
||||
if (cmd->tx_argc == 3)
|
||||
if (locargc == 3)
|
||||
{
|
||||
if (StrIsInt(cmd->tx_argv[2]))
|
||||
rotate = atoi(cmd->tx_argv[2]);
|
||||
if (StrIsInt(cmd->tx_argv[argstart + 1]))
|
||||
rotate = atoi(cmd->tx_argv[argstart + 1]);
|
||||
}
|
||||
if (EditCellUse)
|
||||
if (doDefault)
|
||||
{
|
||||
if (locargc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp,
|
||||
Tcl_NewIntObj(DefaultLabel->lab_rotate));
|
||||
#else
|
||||
TxPrintf("%d\n", DefaultLabel->lab_rotate);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
DefaultLabel->lab_rotate = rotate;
|
||||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelRotateFunc, (cmd->tx_argc == 3) ?
|
||||
cmdLabelRotateFunc, (locargc == 3) ?
|
||||
(ClientData)&rotate : (ClientData)NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case SETLABEL_STICKY:
|
||||
if (cmd->tx_argc == 3)
|
||||
if (locargc == 3)
|
||||
{
|
||||
option = Lookup(cmd->tx_argv[2], cmdLabelYesNo);
|
||||
option = Lookup(cmd->tx_argv[argstart + 1], cmdLabelYesNo);
|
||||
if (option < 0)
|
||||
{
|
||||
TxError("Unknown sticky option \"%s\"\n", cmd->tx_argv[2]);
|
||||
TxError("Unknown sticky option \"%s\"\n", cmd->tx_argv[argstart + 1]);
|
||||
break;
|
||||
}
|
||||
flags = (option <= 3) ? 0 : LABEL_STICKY;
|
||||
}
|
||||
if (EditCellUse)
|
||||
if (doDefault)
|
||||
{
|
||||
if (locargc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp,
|
||||
Tcl_NewBooleanObj((DefaultLabel->lab_flags &
|
||||
LABEL_STICKY) ? TRUE : FALSE));
|
||||
#else
|
||||
TxPrintf("%d\n", (DefaultLabel->lab_flags & LABEL_STICKY) ? 1 : 0);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
DefaultLabel->lab_flags = flags;
|
||||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelStickyFunc, (cmd->tx_argc == 3) ?
|
||||
cmdLabelStickyFunc, (locargc == 3) ?
|
||||
(ClientData)&flags : (ClientData)NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case SETLABEL_LAYER:
|
||||
if (cmd->tx_argc == 3)
|
||||
if (locargc == 3)
|
||||
{
|
||||
if (!strcasecmp(cmd->tx_argv[2], "default"))
|
||||
if (!strcasecmp(cmd->tx_argv[argstart + 1], "default"))
|
||||
ttype = -1;
|
||||
else
|
||||
{
|
||||
ttype = DBTechNoisyNameType(cmd->tx_argv[2]);
|
||||
ttype = DBTechNoisyNameType(cmd->tx_argv[argstart + 1]);
|
||||
if (ttype < 0) break;
|
||||
}
|
||||
}
|
||||
if (EditCellUse)
|
||||
if (doDefault)
|
||||
{
|
||||
if (locargc == 2)
|
||||
{
|
||||
if (DefaultLabel->lab_type == (TileType)(-1))
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetResult(magicinterp, "default", TCL_VOLATILE);
|
||||
#else
|
||||
TxPrintf("default\n");
|
||||
#endif
|
||||
else
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetResult(magicinterp,
|
||||
DBTypeLongNameTbl[DefaultLabel->lab_type],
|
||||
TCL_VOLATILE);
|
||||
#else
|
||||
TxPrintf("%s\n", DBTypeLongNameTbl[DefaultLabel->lab_type]);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
DefaultLabel->lab_type = ttype;
|
||||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelLayerFunc, (cmd->tx_argc == 3) ?
|
||||
cmdLabelLayerFunc, (locargc == 3) ?
|
||||
(ClientData)&ttype : (ClientData)NULL);
|
||||
}
|
||||
break;
|
||||
|
|
@ -2113,7 +2329,7 @@ CmdSetLabel(w, cmd)
|
|||
break;
|
||||
|
||||
default:
|
||||
TxError("Unknown setlabel option \"%s\"\n", cmd->tx_argv[1]);
|
||||
TxError("Unknown setlabel option \"%s\"\n", cmd->tx_argv[argstart]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
139
commands/CmdTZ.c
139
commands/CmdTZ.c
|
|
@ -825,7 +825,6 @@ int cmdWhatPrintCell(tile, cxp)
|
|||
}
|
||||
if (curlid == NULL)
|
||||
{
|
||||
TxPrintf(" %s ", CurrCellName);
|
||||
curlid = (struct linked_id *)mallocMagic(sizeof(struct linked_id));
|
||||
curlid->lid_name = CurrCellName;
|
||||
curlid->lid_next = *lid;
|
||||
|
|
@ -844,6 +843,41 @@ typedef struct labelstore
|
|||
static int moreLabelEntries, labelEntryCount;
|
||||
static LabelStore *labelBlockTop, *labelEntry;
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cmdFindWhatTileFunc ---
|
||||
*
|
||||
* Callback function for CmdWhat(). Given a tile found in the current
|
||||
* selection, searches the database to find what cell or cells that type
|
||||
* belongs to.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cmdFindWhatTileFunc(Tile *tile, ClientData clientData)
|
||||
{
|
||||
struct linked_id **lid = (struct linked_id **)clientData;
|
||||
SearchContext scx;
|
||||
TileTypeBitMask tmask;
|
||||
TileType type;
|
||||
|
||||
TiToRect(tile, &scx.scx_area);
|
||||
scx.scx_use = EditCellUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
|
||||
if (SplitSide(tile))
|
||||
type = SplitRightType(tile);
|
||||
else
|
||||
type = SplitLeftType(tile);
|
||||
TTMaskSetOnlyType(&tmask, type);
|
||||
|
||||
DBTreeSrTiles(&scx, &tmask, 0, cmdWhatPrintCell, (ClientData)lid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -852,7 +886,7 @@ static LabelStore *labelBlockTop, *labelEntry;
|
|||
* Print out information about what's selected.
|
||||
*
|
||||
* Usage:
|
||||
* what [-list]
|
||||
* what [-list[all]]
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
|
|
@ -861,7 +895,8 @@ static LabelStore *labelBlockTop, *labelEntry;
|
|||
* Information gets printed to identify the kinds of paint, plus
|
||||
* labels and subcells, that are selected.
|
||||
* In the TCL version, the "-list" option puts the result in a
|
||||
* nested TCL list.
|
||||
* nested TCL list. The "-listall" variant gives more information
|
||||
* about what cell(s) each type exists in, in the type list.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -873,14 +908,12 @@ CmdWhat(w, cmd)
|
|||
{
|
||||
int i, locargc;
|
||||
bool foundAny;
|
||||
bool doList = FALSE;
|
||||
bool doList = FALSE, doListAll = FALSE;
|
||||
TileTypeBitMask layers, maskBits, *rMask;
|
||||
SearchContext scx;
|
||||
CellUse *CheckUse;
|
||||
struct linked_id *lid;
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_Obj *lobj, *paintobj, *labelobj, *cellobj;
|
||||
Tcl_Obj *lobj, *paintobj, *paintcellobj, *celllistobj, *labelobj, *cellobj;
|
||||
extern int cmdWhatCellListFunc();
|
||||
#endif
|
||||
|
||||
|
|
@ -890,14 +923,20 @@ CmdWhat(w, cmd)
|
|||
locargc = cmd->tx_argc;
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
if ((locargc == 2) && !strncmp(cmd->tx_argv[locargc - 1], "-list", 5))
|
||||
if (locargc == 2)
|
||||
{
|
||||
doList = TRUE;
|
||||
locargc--;
|
||||
lobj = Tcl_NewListObj(0, NULL);
|
||||
paintobj = Tcl_NewListObj(0, NULL);
|
||||
labelobj = Tcl_NewListObj(0, NULL);
|
||||
cellobj = Tcl_NewListObj(0, NULL);
|
||||
if (!strncmp(cmd->tx_argv[locargc - 1], "-list", 5))
|
||||
{
|
||||
if (!strncmp(cmd->tx_argv[locargc - 1], "-listall", 8))
|
||||
doListAll = TRUE;
|
||||
else
|
||||
doList = TRUE;
|
||||
locargc--;
|
||||
lobj = Tcl_NewListObj(0, NULL);
|
||||
paintobj = Tcl_NewListObj(0, NULL);
|
||||
labelobj = Tcl_NewListObj(0, NULL);
|
||||
cellobj = Tcl_NewListObj(0, NULL);
|
||||
}
|
||||
}
|
||||
if (locargc > 1)
|
||||
{
|
||||
|
|
@ -959,29 +998,69 @@ CmdWhat(w, cmd)
|
|||
}
|
||||
if ((CheckUse != NULL) && (CheckUse->cu_def == SelectRootDef))
|
||||
{
|
||||
scx.scx_use = CheckUse;
|
||||
scx.scx_area = SelectUse->cu_bbox; // BSI
|
||||
scx.scx_trans = GeoIdentityTransform; // BSI
|
||||
CellUse *saveUse = EditCellUse;
|
||||
struct linked_id *lid, *lidp;
|
||||
int pNum;
|
||||
|
||||
TxPrintf("Selected mask layers:\n");
|
||||
EditCellUse = CheckUse;
|
||||
|
||||
if (!doListAll) TxPrintf("Selected mask layers:\n");
|
||||
for (i = TT_SELECTBASE; i < DBNumUserLayers; i++)
|
||||
{
|
||||
if (TTMaskHasType(&layers, i))
|
||||
{
|
||||
lid = NULL;
|
||||
TxPrintf(" %-8s (", DBTypeLongName(i));
|
||||
TTMaskSetOnlyType(&maskBits, i);
|
||||
if (DBIsContact(i)) DBMaskAddStacking(&maskBits);
|
||||
DBTreeSrTiles(&scx, &maskBits, 0, cmdWhatPrintCell,
|
||||
(ClientData)&lid);
|
||||
TxPrintf(")\n");
|
||||
while (lid != NULL)
|
||||
|
||||
if (doListAll) paintcellobj = Tcl_NewListObj(0, NULL);
|
||||
|
||||
/* Search selection for tiles of this type, then */
|
||||
/* call cmdFindWhatTileFunc() to search the cell */
|
||||
/* def in the area of that tile to determine what */
|
||||
/* cell or subcell that tile belongs to. */
|
||||
|
||||
lid = NULL;
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
if (TTMaskHasType(&DBPlaneTypes[pNum], i))
|
||||
{
|
||||
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum],
|
||||
&SelectUse->cu_bbox, &maskBits,
|
||||
cmdFindWhatTileFunc, (ClientData)&lid);
|
||||
}
|
||||
|
||||
if (!doListAll)
|
||||
{
|
||||
freeMagic(lid);
|
||||
lid = lid->lid_next;
|
||||
TxPrintf(" %-8s (", DBTypeLongName(i));
|
||||
for (lidp = lid; lidp; lidp = lidp->lid_next)
|
||||
TxPrintf(" %s ", lidp->lid_name);
|
||||
TxPrintf(")\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Tcl_ListObjAppendElement(magicinterp, paintcellobj,
|
||||
Tcl_NewStringObj(DBTypeLongName(i), -1));
|
||||
|
||||
celllistobj = Tcl_NewListObj(0, NULL);
|
||||
for (lidp = lid; lidp; lidp = lidp->lid_next)
|
||||
Tcl_ListObjAppendElement(magicinterp, celllistobj,
|
||||
Tcl_NewStringObj(lidp->lid_name, -1));
|
||||
|
||||
Tcl_ListObjAppendElement(magicinterp, paintcellobj,
|
||||
celllistobj);
|
||||
}
|
||||
|
||||
while (lid != NULL)
|
||||
{
|
||||
freeMagic(lid);
|
||||
lid = lid->lid_next;
|
||||
}
|
||||
if (doListAll)
|
||||
Tcl_ListObjAppendElement(magicinterp, paintobj,
|
||||
paintcellobj);
|
||||
}
|
||||
}
|
||||
EditCellUse = saveUse;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1008,7 +1087,7 @@ CmdWhat(w, cmd)
|
|||
qsort(labelBlockTop, labelEntryCount, sizeof(LabelStore), orderLabelFunc);
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
if (doList)
|
||||
if (doList || doListAll)
|
||||
{
|
||||
Tcl_Obj *newtriple;
|
||||
for (labelEntry = labelBlockTop; labelEntryCount-- > 0; labelEntry++)
|
||||
|
|
@ -1052,7 +1131,7 @@ CmdWhat(w, cmd)
|
|||
|
||||
foundAny = FALSE;
|
||||
#ifdef MAGIC_WRAPPER
|
||||
if (doList)
|
||||
if (doList || doListAll)
|
||||
SelEnumCells(FALSE, (bool *) NULL, (SearchContext *) NULL,
|
||||
cmdWhatCellListFunc, (ClientData) cellobj);
|
||||
else
|
||||
|
|
@ -1061,7 +1140,7 @@ CmdWhat(w, cmd)
|
|||
cmdWhatCellFunc, (ClientData) &foundAny);
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
if (doList)
|
||||
if (doList || doListAll)
|
||||
{
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj, paintobj);
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj, labelobj);
|
||||
|
|
@ -1926,7 +2005,7 @@ CmdXor(w, cmd)
|
|||
|
||||
PaintResultType DBXORResultTbl[NP][NT][NT];
|
||||
PaintResultType (*curPaintSave)[NT][NT];
|
||||
void (*curPlaneSave)();
|
||||
int (*curPlaneSave)();
|
||||
|
||||
int p, t, h;
|
||||
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ DBCellFindDup(use, parent)
|
|||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* DBPlaceCell --
|
||||
* DBPlaceCellNoModify --
|
||||
*
|
||||
* Add a CellUse to the subcell tile plane of a CellDef.
|
||||
* Assumes prior check that the new CellUse is not an exact duplicate
|
||||
|
|
@ -162,11 +163,47 @@ DBPlaceCell (use, def)
|
|||
SigEnableInterrupts();
|
||||
}
|
||||
|
||||
/* Like DBPlaceCell(), but don't change the flags of the parent cell. */
|
||||
/* This is needed by the bounding box recalculation routine, which may */
|
||||
/* cause the cell to be deleted and replaced for the purpose of */
|
||||
/* capturing the bounding box information in the BPlane structure, but */
|
||||
/* this does not mean that anything in the parent cell has changed. */
|
||||
|
||||
void
|
||||
DBPlaceCellNoModify (use, def)
|
||||
CellUse * use; /* new celluse to add to subcell tile plane */
|
||||
CellDef * def; /* parent cell's definition */
|
||||
{
|
||||
Rect rect; /* argument to DBSrCellPlaneArea(), placeCellFunc() */
|
||||
BPlane *bplane; /* argument to DBSrCellPlaneArea(), placeCellFunc() */
|
||||
struct searchArg arg; /* argument to placeCellFunc() */
|
||||
|
||||
ASSERT(use != (CellUse *) NULL, "DBPlaceCell");
|
||||
ASSERT(def, "DBPlaceCell");
|
||||
|
||||
/* To do: Check non-duplicate placement, check non-duplicate ID */
|
||||
|
||||
use->cu_parent = def;
|
||||
|
||||
/* Be careful not to permit interrupts during this, or the
|
||||
* database could be left in a trashed state.
|
||||
*/
|
||||
|
||||
SigDisableInterrupts();
|
||||
BPAdd(def->cd_cellPlane, use);
|
||||
if (UndoIsEnabled())
|
||||
DBUndoCellUse(use, UNDO_CELL_PLACE);
|
||||
SigEnableInterrupts();
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* DBDeleteCell --
|
||||
*
|
||||
* Remove a CellUse from the subcell tile plane of a CellDef.
|
||||
* If "nomodify" is TRUE, then don't set the parent cell's CDMODIFIED flag.
|
||||
* This is needed when recomputing the bounding box, which should not by
|
||||
* itself change the modified state.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
|
|
@ -197,3 +234,39 @@ DBDeleteCell (use)
|
|||
SigEnableInterrupts();
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* DBDeleteCellNoModify --
|
||||
*
|
||||
* Remove a CellUse from the subcell tile plane of a CellDef, as above,
|
||||
* but don't set the parent cell's CDMODIFIED flag. This is needed when
|
||||
* recomputing the bounding box, which should not by itself change the
|
||||
* modified state.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Modifies the subcell tile plane of the CellDef, sets the
|
||||
* parent pointer of the deleted CellUse to NULL.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
DBDeleteCellNoModify (use)
|
||||
CellUse * use;
|
||||
{
|
||||
ASSERT(use != (CellUse *) NULL, "DBDeleteCell");
|
||||
|
||||
/* It's important that this code run with interrupts disabled,
|
||||
* or else we could leave the subcell tile plane in a weird
|
||||
* state.
|
||||
*/
|
||||
|
||||
SigDisableInterrupts();
|
||||
dbInstanceUnplace(use);
|
||||
if (UndoIsEnabled())
|
||||
DBUndoCellUse(use, UNDO_CELL_DELETE);
|
||||
use->cu_parent = (CellDef *) NULL;
|
||||
SigEnableInterrupts();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -723,7 +723,7 @@ dbReComputeBboxFunc(cellDef, boundProc, recurseProc)
|
|||
*/
|
||||
|
||||
parent = use->cu_parent;
|
||||
DBDeleteCell(use);
|
||||
DBDeleteCellNoModify(use);
|
||||
use->cu_parent = parent;
|
||||
}
|
||||
|
||||
|
|
@ -751,7 +751,7 @@ dbReComputeBboxFunc(cellDef, boundProc, recurseProc)
|
|||
if ((parent = use->cu_parent) != (CellDef *) NULL)
|
||||
{
|
||||
parent->cd_flags |= CDBOXESCHANGED;
|
||||
DBPlaceCell(use, parent);
|
||||
DBPlaceCellNoModify(use, parent);
|
||||
if (last != parent)
|
||||
{
|
||||
if (last != NULL) (*recurseProc)(last);
|
||||
|
|
|
|||
|
|
@ -342,6 +342,214 @@ DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func)
|
|||
DBTreeSrTiles(scx, &locMask, xMask, dbCopyAllPaint, (ClientData) &arg);
|
||||
}
|
||||
|
||||
/* Client data structure used by DBCellGenerateSubstrate() */
|
||||
|
||||
struct dbCopySubData {
|
||||
Plane *csd_plane;
|
||||
TileType csd_subtype;
|
||||
int csd_pNum;
|
||||
bool csd_modified;
|
||||
};
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* DBCellGenerateSubstrate --
|
||||
*
|
||||
* This function is used by the extraction code in ExtSubtree.c.
|
||||
* Paint substrate into the target use. Similar to DBCellCopyAllPaint(),
|
||||
* but it finds space tiles on the substrate plane and converts them to
|
||||
* a substrate type in the target, clipped to the cell boundary. This
|
||||
* allows the extraction to find and record all substrate regions, both
|
||||
* common (global substrate) and local (isolated substrate), without
|
||||
* requiring a physical substrate type to be drawn into all cells.
|
||||
*
|
||||
* Unlike normal paint copying, this can only be done by painting the
|
||||
* substrate type over the entire cell area and then erasing all areas
|
||||
* belonging to not-substrate types in the source.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Side Effects:
|
||||
* Paints into the targetUse's CellDef. This only happens if two
|
||||
* conditions are met:
|
||||
* (1) The techfile has defined "substrate"
|
||||
* (2) The techfile defines a type corresponding to the substrate
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Plane *
|
||||
DBCellGenerateSubstrate(scx, subType, notSubMask, subShieldMask, targetDef)
|
||||
SearchContext *scx;
|
||||
TileType subType; /* Substrate paint type */
|
||||
TileTypeBitMask *notSubMask; /* Mask of types that are not substrate */
|
||||
TileTypeBitMask *subShieldMask; /* Mask of types that shield substrate */
|
||||
CellDef *targetDef;
|
||||
{
|
||||
struct dbCopySubData csd;
|
||||
Plane *tempPlane;
|
||||
int plane;
|
||||
Rect rect;
|
||||
int dbPaintSubFunc();
|
||||
int dbEraseNonSub();
|
||||
int dbCopySubFunc();
|
||||
|
||||
GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &rect);
|
||||
|
||||
/* Clip to bounding box of the top level cell */
|
||||
GEOCLIP(&rect, &scx->scx_use->cu_def->cd_bbox);
|
||||
|
||||
plane = DBPlane(subType);
|
||||
|
||||
tempPlane = DBNewPlane((ClientData) TT_SPACE);
|
||||
DBClearPaintPlane(tempPlane);
|
||||
|
||||
csd.csd_subtype = subType;
|
||||
csd.csd_plane = tempPlane;
|
||||
csd.csd_pNum = plane;
|
||||
csd.csd_modified = FALSE;
|
||||
|
||||
/* First paint the substrate type in the temporary plane over the */
|
||||
/* area of all substrate shield types. */
|
||||
/* Note: xMask is always zero, as this is only called from extract routines */
|
||||
DBTreeSrTiles(scx, subShieldMask, 0, dbPaintSubFunc, (ClientData)&csd);
|
||||
if (csd.csd_modified == FALSE) return NULL;
|
||||
|
||||
/* Now erase all areas that are non-substrate types in the source */
|
||||
DBTreeSrTiles(scx, notSubMask, 0, dbEraseNonSub, (ClientData)&csd);
|
||||
|
||||
/* Finally, copy the destination plane contents onto tempPlane */
|
||||
DBSrPaintArea((Tile *)NULL, targetDef->cd_planes[plane], &TiPlaneRect,
|
||||
&DBAllButSpaceBits, dbCopySubFunc, (ClientData)&csd);
|
||||
|
||||
return tempPlane;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback function for DBCellGenerateSubstrate()
|
||||
* Finds tiles in the source def that belong to the list of types that
|
||||
* shield the substrate (e.g., deep nwell), and paint the substrate type
|
||||
* into the target plane over the same area.
|
||||
*/
|
||||
|
||||
int
|
||||
dbPaintSubFunc(tile, cxp)
|
||||
Tile *tile; /* Pointer to source tile with shield type */
|
||||
TreeContext *cxp; /* Context from DBTreeSrTiles */
|
||||
{
|
||||
SearchContext *scx;
|
||||
Rect sourceRect, targetRect;
|
||||
int pNum;
|
||||
TileType type, loctype, subType;
|
||||
Plane *plane;
|
||||
struct dbCopySubData *csd; /* Client data */
|
||||
|
||||
scx = cxp->tc_scx;
|
||||
csd = (struct dbCopySubData *)cxp->tc_filter->tf_arg;
|
||||
plane = csd->csd_plane;
|
||||
pNum = csd->csd_pNum;
|
||||
subType = csd->csd_subtype;
|
||||
type = TiGetTypeExact(tile);
|
||||
if (IsSplit(tile))
|
||||
{
|
||||
loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
|
||||
if (loctype == TT_SPACE) return 0;
|
||||
}
|
||||
|
||||
/* Construct the rect for the tile */
|
||||
TITORECT(tile, &sourceRect);
|
||||
|
||||
/* Transform to target coordinates */
|
||||
GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect);
|
||||
|
||||
csd->csd_modified = TRUE;
|
||||
|
||||
return DBNMPaintPlane(plane, type, &targetRect, DBStdPaintTbl(subType, pNum),
|
||||
(PaintUndoInfo *)NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback function for DBCellGenerateSubstrate()
|
||||
* Finds tiles on the substrate plane in the source def that are not the
|
||||
* substrate type, and erases those areas from the target. This reduces
|
||||
* the geometry in the target plane to areas that form isolated substrate
|
||||
* regions. Regions belonging to the common global substrate are ignored.
|
||||
*/
|
||||
|
||||
int
|
||||
dbEraseNonSub(tile, cxp)
|
||||
Tile *tile; /* Pointer to tile to erase from target */
|
||||
TreeContext *cxp; /* Context from DBTreeSrTiles */
|
||||
{
|
||||
SearchContext *scx;
|
||||
Rect sourceRect, targetRect;
|
||||
Plane *plane; /* Plane of target data */
|
||||
TileType type, loctype, subType;
|
||||
struct dbCopySubData *csd;
|
||||
int pNum;
|
||||
|
||||
csd = (struct dbCopySubData *)cxp->tc_filter->tf_arg;
|
||||
plane = csd->csd_plane;
|
||||
subType = csd->csd_subtype;
|
||||
pNum = csd->csd_pNum;
|
||||
|
||||
scx = cxp->tc_scx;
|
||||
|
||||
type = TiGetTypeExact(tile);
|
||||
if (IsSplit(tile))
|
||||
{
|
||||
loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
|
||||
if (loctype == TT_SPACE) return 0;
|
||||
}
|
||||
|
||||
/* Construct the rect for the tile */
|
||||
TITORECT(tile, &sourceRect);
|
||||
|
||||
/* Transform to target coordinates */
|
||||
GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect);
|
||||
|
||||
/* Erase the substrate type from the area of this tile in the target plane. */
|
||||
return DBNMPaintPlane(plane, type, &targetRect, DBStdEraseTbl(subType, pNum),
|
||||
(PaintUndoInfo *)NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback function for DBCellGenerateSubstrate()
|
||||
* Simple paint function to copy all paint from the substrate plane of the
|
||||
* source def into the target plane containing the isolated substrate
|
||||
* regions.
|
||||
*/
|
||||
|
||||
int
|
||||
dbCopySubFunc(tile, csd)
|
||||
Tile *tile; /* Pointer to tile to erase from target */
|
||||
struct dbCopySubData *csd; /* Client data */
|
||||
{
|
||||
Rect rect;
|
||||
int pNum;
|
||||
TileType type, loctype;
|
||||
Plane *plane;
|
||||
|
||||
plane = csd->csd_plane;
|
||||
pNum = csd->csd_pNum;
|
||||
type = TiGetTypeExact(tile);
|
||||
if (IsSplit(tile))
|
||||
{
|
||||
loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
|
||||
if (loctype == TT_SPACE) return 0;
|
||||
}
|
||||
else
|
||||
loctype = type;
|
||||
|
||||
/* Construct the rect for the tile */
|
||||
TITORECT(tile, &rect);
|
||||
|
||||
return DBNMPaintPlane(plane, type, &rect, DBStdPaintTbl(loctype, pNum),
|
||||
(PaintUndoInfo *)NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -480,6 +688,7 @@ DBCellCopyPaint(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);
|
||||
|
||||
/* Build dummy TreeContext */
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#endif /* not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for qsort() */
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
|
|
@ -271,6 +273,7 @@ DBCellDelete(cellname, force)
|
|||
}
|
||||
celldef->cd_parents = (CellUse *)NULL;
|
||||
|
||||
DBWResetBox(celldef);
|
||||
result = DBCellDeleteDef(celldef);
|
||||
|
||||
if (result == FALSE)
|
||||
|
|
@ -280,8 +283,6 @@ DBCellDelete(cellname, force)
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -598,6 +599,67 @@ DBTopPrint(mw, dolist)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* Simple natural sort routine
|
||||
* https://stackoverflow.com/questions/34518/natural-sorting-algorithm
|
||||
* By Norman Ramsey, edited for style.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int strcmpbynum(const char *s1, const char *s2)
|
||||
{
|
||||
/* Like strcmp() but compare sequences of digits numerically */
|
||||
for (;;)
|
||||
{
|
||||
if (*s2 == '\0')
|
||||
return *s1 != '\0';
|
||||
else if (*s1 == '\0')
|
||||
return 1;
|
||||
else if (!(isdigit(*s1) && isdigit(*s2)))
|
||||
{
|
||||
if (*s1 != *s2)
|
||||
return (int)*s1 - (int)*s2;
|
||||
else
|
||||
{
|
||||
++s1;
|
||||
++s2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char *lim1, *lim2;
|
||||
unsigned long n1 = strtoul(s1, &lim1, 10);
|
||||
unsigned long n2 = strtoul(s2, &lim2, 10);
|
||||
if (n1 > n2)
|
||||
return 1;
|
||||
else if (n1 < n2)
|
||||
return -1;
|
||||
s1 = lim1;
|
||||
s2 = lim2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* Sort routine for qsort() to be used by DBCellPrint(). Sorts in alphabetical
|
||||
* order using the natural sort routine above. List is reverse sorted since
|
||||
* the code below prints from the end to the beginning of the list.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
qcompare(const void *one, const void *two)
|
||||
{
|
||||
int cval;
|
||||
|
||||
char *s1 = *((char **)one);
|
||||
char *s2 = *((char **)two);
|
||||
cval = strcmpbynum(s1, s2);
|
||||
return -cval;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -625,11 +687,12 @@ DBCellPrint(CellName, who, dolist)
|
|||
int who;
|
||||
bool dolist;
|
||||
{
|
||||
int found;
|
||||
int found, numcells;
|
||||
HashSearch hs;
|
||||
HashEntry *entry;
|
||||
CellDef *celldef;
|
||||
CellUse *celluse;
|
||||
char **celllist;
|
||||
|
||||
if (!dolist)
|
||||
{
|
||||
|
|
@ -657,6 +720,11 @@ DBCellPrint(CellName, who, dolist)
|
|||
* CDMODIFIED flag set.
|
||||
*/
|
||||
|
||||
numcells = dbCellDefTable.ht_nEntries;
|
||||
if (numcells == 0) numcells = 1;
|
||||
celllist = (char **)mallocMagic(numcells * sizeof(char *));
|
||||
numcells = 0;
|
||||
|
||||
HashStartSearch(&hs);
|
||||
while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
|
||||
{
|
||||
|
|
@ -666,28 +734,39 @@ DBCellPrint(CellName, who, dolist)
|
|||
if (((celldef->cd_flags & CDINTERNAL) != CDINTERNAL) &&
|
||||
((who != MODIFIED) ||
|
||||
(celldef->cd_flags & CDMODIFIED)))
|
||||
{
|
||||
if (celldef->cd_name != NULL)
|
||||
{
|
||||
if (dolist)
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_AppendElement(magicinterp, celldef->cd_name);
|
||||
#else
|
||||
TxPrintf("%s ", celldef->cd_name);
|
||||
#endif
|
||||
else
|
||||
TxPrintf(" %s\n", celldef->cd_name);
|
||||
}
|
||||
}
|
||||
celllist[numcells++] = celldef->cd_name;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
qsort(celllist, numcells, sizeof(char *), qcompare);
|
||||
|
||||
while (--numcells >= 0)
|
||||
{
|
||||
if (dolist)
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_AppendElement(magicinterp, celllist[numcells]);
|
||||
#else
|
||||
TxPrintf("%s ", celllist[numcells]);
|
||||
#endif
|
||||
else
|
||||
TxPrintf(" %s\n", celllist[numcells]);
|
||||
}
|
||||
|
||||
freeMagic(celllist);
|
||||
break;
|
||||
|
||||
case TOPCELLS:
|
||||
/*
|
||||
* Print the name of all the 'top' cells.
|
||||
* Print the name of all the 'top' cells. Sort alphabetically.
|
||||
*/
|
||||
|
||||
numcells = dbCellDefTable.ht_nEntries;
|
||||
if (numcells == 0) numcells = 1;
|
||||
celllist = (char **)mallocMagic(numcells * sizeof(char *));
|
||||
numcells = 0;
|
||||
|
||||
HashStartSearch(&hs);
|
||||
while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
|
||||
{
|
||||
|
|
@ -712,19 +791,25 @@ DBCellPrint(CellName, who, dolist)
|
|||
}
|
||||
}
|
||||
if ( (found == 0) && (celldef->cd_name != NULL) )
|
||||
{
|
||||
if (dolist)
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_AppendElement(magicinterp, celldef->cd_name);
|
||||
#else
|
||||
TxPrintf("%s ", celldef->cd_name);
|
||||
#endif
|
||||
else
|
||||
TxPrintf(" %s\n", celldef->cd_name);
|
||||
}
|
||||
celllist[numcells++] = celldef->cd_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qsort(celllist, numcells, sizeof(char *), qcompare);
|
||||
|
||||
while (--numcells >= 0)
|
||||
{
|
||||
if (dolist)
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_AppendElement(magicinterp, celllist[numcells]);
|
||||
#else
|
||||
TxPrintf("%s ", celllist[numcells]);
|
||||
#endif
|
||||
else
|
||||
TxPrintf(" %s\n", celllist[numcells]);
|
||||
}
|
||||
freeMagic(celllist);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -29,8 +29,10 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/geometry.h"
|
||||
#include "tiles/tile.h"
|
||||
#include "utils/hash.h"
|
||||
#include "utils/stack.h"
|
||||
#include "database/database.h"
|
||||
#include "database/databaseInt.h"
|
||||
#include "select/select.h"
|
||||
#include "utils/signals.h"
|
||||
#include "utils/malloc.h"
|
||||
|
||||
|
|
@ -43,55 +45,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
* is used to clear the markings again.
|
||||
*/
|
||||
|
||||
/* The following structure is used to hold several pieces
|
||||
* of information that must be passed through multiple
|
||||
* levels of search function (used by dbSrConnectFunc).
|
||||
*/
|
||||
|
||||
struct conSrArg
|
||||
{
|
||||
CellDef *csa_def; /* Definition being searched. */
|
||||
int csa_plane; /* Index of current plane being searched. */
|
||||
TileTypeBitMask *csa_connect; /* Table indicating what connects
|
||||
* to what.
|
||||
*/
|
||||
int (*csa_clientFunc)(); /* Client function to call. */
|
||||
ClientData csa_clientData; /* Argument for clientFunc. */
|
||||
bool csa_clear; /* FALSE means pass 1, TRUE
|
||||
* means pass 2.
|
||||
*/
|
||||
Rect csa_bounds; /* Area that limits search. */
|
||||
};
|
||||
|
||||
/* The following structure is used to hold several pieces
|
||||
* of information that must be passed through multiple
|
||||
* levels of search function (used by dbcConnectFunc).
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Rect area; /* Area to process */
|
||||
TileTypeBitMask *connectMask; /* Connection mask for search */
|
||||
TileType dinfo; /* Info about triangular search areas */
|
||||
} conSrArea;
|
||||
|
||||
struct conSrArg2
|
||||
{
|
||||
CellUse *csa2_use; /* Destination use */
|
||||
TileTypeBitMask *csa2_connect; /* Table indicating what connects
|
||||
* to what.
|
||||
*/
|
||||
SearchContext *csa2_topscx; /* Original top-level search context */
|
||||
int csa2_xMask; /* Cell window mask for search */
|
||||
Rect *csa2_bounds; /* Area that limits the search */
|
||||
|
||||
conSrArea *csa2_list; /* List of areas to process */
|
||||
int csa2_top; /* Index of next area to process */
|
||||
int csa2_size; /* Max. number bins in area list */
|
||||
};
|
||||
|
||||
#define CSA2_LIST_START_SIZE 256
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------
|
||||
* DBTransformDiagonal --
|
||||
|
|
@ -255,6 +208,7 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
|
|||
startTile = NULL;
|
||||
for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
|
||||
{
|
||||
csa.csa_pNum = startPlane;
|
||||
if (DBSrPaintArea((Tile *) NULL,
|
||||
def->cd_planes[startPlane], startArea, mask,
|
||||
dbSrConnectStartFunc, (ClientData) &startTile) != 0) break;
|
||||
|
|
@ -270,7 +224,6 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
|
|||
csa.csa_clientData = clientData;
|
||||
csa.csa_clear = FALSE;
|
||||
csa.csa_connect = connect;
|
||||
csa.csa_plane = startPlane;
|
||||
if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
|
||||
|
||||
/* Pass 2. Don't call any client function, just clear the marks.
|
||||
|
|
@ -280,7 +233,6 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
|
|||
SigDisableInterrupts();
|
||||
csa.csa_clientFunc = NULL;
|
||||
csa.csa_clear = TRUE;
|
||||
csa.csa_plane = startPlane;
|
||||
(void) dbSrConnectFunc(startTile, &csa);
|
||||
SigEnableInterrupts();
|
||||
|
||||
|
|
@ -346,6 +298,7 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
|
|||
startTile = NULL;
|
||||
for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
|
||||
{
|
||||
csa.csa_pNum = startPlane;
|
||||
if (DBSrPaintArea((Tile *) NULL,
|
||||
def->cd_planes[startPlane], startArea, mask,
|
||||
dbSrConnectStartFunc, (ClientData) &startTile) != 0) break;
|
||||
|
|
@ -361,7 +314,6 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
|
|||
csa.csa_clientData = clientData;
|
||||
csa.csa_clear = FALSE;
|
||||
csa.csa_connect = connect;
|
||||
csa.csa_plane = startPlane;
|
||||
if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
|
||||
|
||||
return result;
|
||||
|
|
@ -434,7 +386,7 @@ dbSrConnectFunc(tile, csa)
|
|||
|
||||
if (csa->csa_clientFunc != NULL)
|
||||
{
|
||||
if ((*csa->csa_clientFunc)(tile, csa->csa_plane, csa->csa_clientData) != 0)
|
||||
if ((*csa->csa_clientFunc)(tile, csa->csa_pNum, csa->csa_clientData) != 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -577,7 +529,7 @@ donesides:
|
|||
*/
|
||||
|
||||
planes = DBConnPlanes[loctype];
|
||||
planes &= ~(PlaneNumToMaskBit(csa->csa_plane));
|
||||
planes &= ~(PlaneNumToMaskBit(csa->csa_pNum));
|
||||
if (planes != 0)
|
||||
{
|
||||
struct conSrArg newcsa;
|
||||
|
|
@ -589,7 +541,7 @@ donesides:
|
|||
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
|
||||
{
|
||||
if (!PlaneMaskHasPlane(planes, i)) continue;
|
||||
newcsa.csa_plane = i;
|
||||
newcsa.csa_pNum = i;
|
||||
if (IsSplit(tile))
|
||||
{
|
||||
if (DBSrPaintNMArea((Tile *) NULL, csa->csa_def->cd_planes[i],
|
||||
|
|
@ -653,7 +605,7 @@ dbcUnconnectFunc(tile, clientData)
|
|||
* connectivity between them.
|
||||
*
|
||||
* Results:
|
||||
* Always 0.
|
||||
* Return 0 normally, 1 if list size exceeds integer bounds.
|
||||
*
|
||||
* Side effects:
|
||||
* Adds a label to the destination definition "def".
|
||||
|
|
@ -691,10 +643,15 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
|
|||
{
|
||||
int newllen = tpath->tp_next - tpath->tp_first;
|
||||
newlabtext[0] = '\0';
|
||||
if (newllen > 0)
|
||||
strncpy(newlabtext, tpath->tp_first, newllen);
|
||||
sprintf(newlabtext + newllen, "%s", lab->lab_text);
|
||||
newlabptr = newlabtext;
|
||||
if (tpath->tp_first == NULL)
|
||||
newlabptr = lab->lab_text;
|
||||
else
|
||||
{
|
||||
if (newllen > 0)
|
||||
strncpy(newlabtext, tpath->tp_first, newllen);
|
||||
sprintf(newlabtext + newllen, "%s", lab->lab_text);
|
||||
newlabptr = newlabtext;
|
||||
}
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
|
@ -734,7 +691,7 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
|
|||
if ((slab->lab_flags & PORT_NUM_MASK) == lidx)
|
||||
{
|
||||
Rect newarea;
|
||||
int pNum;
|
||||
int i, pNum;
|
||||
|
||||
// Do NOT go searching on labels connected to space!
|
||||
if (slab->lab_type == TT_SPACE) continue;
|
||||
|
|
@ -757,24 +714,29 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
|
|||
newarea.r_ybot--;
|
||||
newarea.r_ytop++;
|
||||
|
||||
/* Check if any of the last 5 entries has the same type and */
|
||||
/* area. If so, don't duplicate the existing entry. */
|
||||
|
||||
for (i = csa2->csa2_lasttop; (i >= 0) &&
|
||||
(i > csa2->csa2_lasttop - 5); i--)
|
||||
if (connectMask == csa2->csa2_list[i].connectMask)
|
||||
if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea))
|
||||
return 0;
|
||||
|
||||
/* Register the area and connection mask as needing to be processed */
|
||||
|
||||
if (++csa2->csa2_top == csa2->csa2_size)
|
||||
if (++csa2->csa2_top == CSA2_LIST_SIZE)
|
||||
{
|
||||
/* Reached list size limit---need to enlarge the list */
|
||||
/* Double the size of the list every time we hit the limit */
|
||||
/* Reached list size limit---need to push the list and */
|
||||
/* start a new one. */
|
||||
|
||||
conSrArea *newlist;
|
||||
int i, lastsize = csa2->csa2_size;
|
||||
|
||||
csa2->csa2_size *= 2;
|
||||
|
||||
newlist = (conSrArea *)mallocMagic(csa2->csa2_size
|
||||
* sizeof(conSrArea));
|
||||
memcpy((void *)newlist, (void *)csa2->csa2_list,
|
||||
(size_t)lastsize * sizeof(conSrArea));
|
||||
freeMagic((char *)csa2->csa2_list);
|
||||
newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE *
|
||||
sizeof(conSrArea));
|
||||
StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
|
||||
csa2->csa2_list = newlist;
|
||||
csa2->csa2_top = 0;
|
||||
}
|
||||
|
||||
csa2->csa2_list[csa2->csa2_top].area = newarea;
|
||||
|
|
@ -805,7 +767,8 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
|
|||
* catecorner tiles from being considered as connected.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0 to keep the search from aborting.
|
||||
* Returns 0 normally to keep the search from aborting; returns 1
|
||||
* if allocation of list failed due to exceeding integer bounds.
|
||||
*
|
||||
* Side effects:
|
||||
* Adds paint to the destination definition.
|
||||
|
|
@ -829,7 +792,7 @@ dbcConnectFunc(tile, cx)
|
|||
SearchContext scx2;
|
||||
TileType loctype = TiGetTypeExact(tile);
|
||||
TileType dinfo = 0;
|
||||
int pNum = cx->tc_plane;
|
||||
int i, pNum = cx->tc_plane;
|
||||
CellDef *def;
|
||||
|
||||
TiToRect(tile, &tileArea);
|
||||
|
|
@ -942,23 +905,29 @@ dbcConnectFunc(tile, cx)
|
|||
newarea.r_xtop += 1;
|
||||
}
|
||||
|
||||
/* Check if any of the last 5 entries has the same type and */
|
||||
/* area. If so, don't duplicate the existing entry. */
|
||||
/* (NOTE: Connect masks are all from the same table, so */
|
||||
/* they can be compared by address, no need for TTMaskEqual)*/
|
||||
|
||||
for (i = csa2->csa2_lasttop; (i >= 0) && (i > csa2->csa2_lasttop - 5); i--)
|
||||
if (connectMask == csa2->csa2_list[i].connectMask)
|
||||
if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea))
|
||||
return 0;
|
||||
|
||||
/* Register the area and connection mask as needing to be processed */
|
||||
|
||||
if (++csa2->csa2_top == csa2->csa2_size)
|
||||
if (++csa2->csa2_top == CSA2_LIST_SIZE)
|
||||
{
|
||||
/* Reached list size limit---need to enlarge the list */
|
||||
/* Double the size of the list every time we hit the limit */
|
||||
/* Reached list size limit---need to push the list and */
|
||||
/* start a new one. */
|
||||
|
||||
conSrArea *newlist;
|
||||
int i, lastsize = csa2->csa2_size;
|
||||
|
||||
csa2->csa2_size *= 2;
|
||||
|
||||
newlist = (conSrArea *)mallocMagic((size_t)(csa2->csa2_size) * sizeof(conSrArea));
|
||||
memcpy((void *)newlist, (void *)csa2->csa2_list,
|
||||
(size_t)lastsize * sizeof(conSrArea));
|
||||
freeMagic((char *)csa2->csa2_list);
|
||||
newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
|
||||
StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
|
||||
csa2->csa2_list = newlist;
|
||||
csa2->csa2_top = 0;
|
||||
}
|
||||
|
||||
csa2->csa2_list[csa2->csa2_top].area = newarea;
|
||||
|
|
@ -968,7 +937,6 @@ dbcConnectFunc(tile, cx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -1019,9 +987,10 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse)
|
|||
* clipped to this area. Pass
|
||||
* TiPlaneRect to get everything.
|
||||
*/
|
||||
bool doLabels; /* If TRUE, copy connected labels
|
||||
* and paint. If FALSE, copy only
|
||||
* connected paint.
|
||||
unsigned char doLabels; /* If SEL_DO_LABELS, copy connected labels
|
||||
* and paint. If SEL_NO_LABELS, copy only
|
||||
* connected paint. If SEL_SIMPLE_LABELS,
|
||||
* copy only root of labels in subcircuits.
|
||||
*/
|
||||
CellUse *destUse; /* Result use in which to place
|
||||
* anything connected to material of
|
||||
|
|
@ -1034,7 +1003,6 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse)
|
|||
unsigned char searchtype;
|
||||
|
||||
csa2.csa2_use = destUse;
|
||||
csa2.csa2_xMask = xMask;
|
||||
csa2.csa2_bounds = area;
|
||||
csa2.csa2_connect = connect;
|
||||
csa2.csa2_topscx = scx;
|
||||
|
|
@ -1043,10 +1011,11 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse)
|
|||
/* malloc calls by maintaining a small list and expanding it only */
|
||||
/* when necessary. */
|
||||
|
||||
csa2.csa2_size = CSA2_LIST_START_SIZE;
|
||||
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_START_SIZE
|
||||
* sizeof(conSrArea));
|
||||
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
|
||||
csa2.csa2_top = -1;
|
||||
csa2.csa2_lasttop = -1;
|
||||
|
||||
csa2.csa2_stack = StackNew(100);
|
||||
|
||||
DBTreeSrTiles(scx, mask, xMask, dbcConnectFunc, (ClientData) &csa2);
|
||||
while (csa2.csa2_top >= 0)
|
||||
|
|
@ -1061,13 +1030,28 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse)
|
|||
newmask = csa2.csa2_list[csa2.csa2_top].connectMask;
|
||||
scx->scx_area = csa2.csa2_list[csa2.csa2_top].area;
|
||||
newtype = csa2.csa2_list[csa2.csa2_top].dinfo;
|
||||
csa2.csa2_top--;
|
||||
if (csa2.csa2_top == 0)
|
||||
{
|
||||
if (StackLook(csa2.csa2_stack) != (ClientData)NULL)
|
||||
{
|
||||
freeMagic(csa2.csa2_list);
|
||||
csa2.csa2_list = (conSrArea *)StackPop(csa2.csa2_stack);
|
||||
csa2.csa2_top = CSA2_LIST_SIZE - 1;
|
||||
}
|
||||
else
|
||||
csa2.csa2_top--;
|
||||
}
|
||||
else
|
||||
csa2.csa2_top--;
|
||||
|
||||
csa2.csa2_lasttop = csa2.csa2_top;
|
||||
|
||||
if (newtype & TT_DIAGONAL)
|
||||
DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFunc,
|
||||
(ClientData) &csa2);
|
||||
else
|
||||
DBTreeSrTiles(scx, newmask, xMask, dbcConnectFunc, (ClientData) &csa2);
|
||||
DBTreeSrTiles(scx, newmask, xMask, dbcConnectFunc,
|
||||
(ClientData) &csa2);
|
||||
|
||||
/* Check the source def for any labels belonging to this */
|
||||
/* tile area and plane, and add them to the destination. */
|
||||
|
|
@ -1098,11 +1082,17 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse)
|
|||
searchtype |= TF_LABEL_ATTACH_NOT_SE;
|
||||
}
|
||||
}
|
||||
if (doLabels)
|
||||
DBTreeSrLabels(scx, newmask, xMask, &tpath, searchtype,
|
||||
dbcConnectLabelFunc, (ClientData) &csa2);
|
||||
if (doLabels == SEL_SIMPLE_LABELS) tpath.tp_first = NULL;
|
||||
if (doLabels != SEL_NO_LABELS)
|
||||
if (DBTreeSrLabels(scx, newmask, xMask, &tpath, searchtype,
|
||||
dbcConnectLabelFunc, (ClientData) &csa2) != 0)
|
||||
{
|
||||
TxError("Connection search hit memory limit and stopped.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeMagic((char *)csa2.csa2_list);
|
||||
StackFree(csa2.csa2_stack);
|
||||
|
||||
/* Recompute the bounding box of the destination and record its area
|
||||
* for redisplay.
|
||||
|
|
|
|||
451
database/DBio.c
451
database/DBio.c
|
|
@ -135,6 +135,132 @@ file_is_not_writeable(name)
|
|||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* DBSearchForTech --
|
||||
*
|
||||
* Helper function for automatically discovering a technology used in a
|
||||
* .mag file when reading. This function will recursively search all
|
||||
* directories rooted at "pathroot" looking for a file "techname" which
|
||||
* must include the ".tech" extension. If found, the path name is returned.
|
||||
*
|
||||
* Results:
|
||||
* Pointer to a string containing the path name. This is allocated so as
|
||||
* not to be lost, and must be freed by the caller.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
DBSearchForTech(techname, pathroot, level)
|
||||
char *techname;
|
||||
char *pathroot;
|
||||
int level;
|
||||
{
|
||||
char *newpath, *found;
|
||||
struct dirent *tdent;
|
||||
DIR *tdir;
|
||||
|
||||
/* Avoid potential infinite looping. Any tech file should not be very */
|
||||
/* far down the path. 10 levels is already excessive. */
|
||||
if (level > 10) return NULL;
|
||||
|
||||
tdir = opendir(pathroot);
|
||||
if (tdir) {
|
||||
|
||||
/* Read the directory contents of tdir */
|
||||
while ((tdent = readdir(tdir)) != NULL)
|
||||
{
|
||||
if (tdent->d_type != DT_DIR)
|
||||
{
|
||||
if (!strcmp(tdent->d_name, techname))
|
||||
return pathroot;
|
||||
}
|
||||
else if (strcmp(tdent->d_name, ".") && strcmp(tdent->d_name, ".."))
|
||||
{
|
||||
newpath = mallocMagic(strlen(pathroot) + strlen(tdent->d_name) + 3);
|
||||
sprintf(newpath, "%s/%s", pathroot, tdent->d_name);
|
||||
found = DBSearchForTech(techname, newpath, level + 1);
|
||||
if (found != newpath) freeMagic(newpath);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
closedir(tdir);
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* DBAddStandardCellPaths --
|
||||
*
|
||||
* Search for .mag files in any directory below "pathptr", for any
|
||||
* directory found containing .mag files, add that path to the search
|
||||
* path for cells.
|
||||
*
|
||||
* Results:
|
||||
* Number of paths added to CellLibPath.
|
||||
*
|
||||
* Side effects:
|
||||
* May add paths to the CellLibPath.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
DBAddStandardCellPaths(pathptr, level)
|
||||
char *pathptr;
|
||||
int level;
|
||||
{
|
||||
int paths = 0;
|
||||
struct dirent *tdent;
|
||||
char *newpath;
|
||||
DIR *tdir;
|
||||
bool magfound = FALSE;
|
||||
|
||||
/* Avoid potential infinite looping. Any tech file should not be very */
|
||||
/* far down the path. 10 levels is already excessive. */
|
||||
if (level > 10) return 0;
|
||||
|
||||
tdir = opendir(pathptr);
|
||||
if (tdir) {
|
||||
|
||||
while ((tdent = readdir(tdir)) != NULL)
|
||||
{
|
||||
if ((tdent->d_type == DT_DIR) &&
|
||||
(strcmp(tdent->d_name, ".") && strcmp(tdent->d_name, "..")))
|
||||
{
|
||||
/* Scan the directory contents of tdir for more subdirectories */
|
||||
newpath = mallocMagic(strlen(pathptr) + strlen(tdent->d_name) + 3);
|
||||
sprintf(newpath, "%s/%s", pathptr, tdent->d_name);
|
||||
paths += DBAddStandardCellPaths(newpath, level + 1);
|
||||
freeMagic(newpath);
|
||||
}
|
||||
else if (tdent->d_type != DT_DIR)
|
||||
{
|
||||
/* Scan the directory contents of tdir for .mag files */
|
||||
if (!strcmp(tdent->d_name + strlen(tdent->d_name) - 4, ".mag"))
|
||||
{
|
||||
if (magfound == FALSE)
|
||||
{
|
||||
PaAppend(&CellLibPath, pathptr);
|
||||
paths++;
|
||||
magfound = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(tdir);
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -285,7 +411,7 @@ dbCellReadDef(f, cellDef, name, ignoreTech, dereference)
|
|||
int cellStamp = 0, rectCount = 0, rectReport = 10000;
|
||||
char line[2048], tech[50], layername[50];
|
||||
PaintResultType *ptable;
|
||||
bool result = TRUE, scaleLimit = FALSE;
|
||||
bool result = TRUE, scaleLimit = FALSE, has_mismatch;
|
||||
Rect *rp;
|
||||
int c;
|
||||
TileType type, rtype, loctype;
|
||||
|
|
@ -335,13 +461,122 @@ dbCellReadDef(f, cellDef, name, ignoreTech, dereference)
|
|||
TxPrintf("Will attempt to read cell anyway.\n");
|
||||
else
|
||||
{
|
||||
TxError("Use command \"tech load\" if you want to switch"
|
||||
" technologies, or use\n");
|
||||
TxError("\"cellname delete %s\" and \"load %s -force\" to"
|
||||
" force the cell to load as technology %s\n",
|
||||
cellDef->cd_name, cellDef->cd_name, DBTechName);
|
||||
SigEnableInterrupts();
|
||||
return (FALSE);
|
||||
/* If no cells are currently in memory, then make an
|
||||
* attempt to find the technology associated with the
|
||||
* layout and load it.
|
||||
*/
|
||||
|
||||
if (!CmdCheckForPaintFunc())
|
||||
{
|
||||
/* Places to check for a technology: In the PDK_ROOT
|
||||
* (PDKROOT) directory, PDK_PATH (PDKPATH) from environment
|
||||
* variables, and CAD_ROOT from Tcl variables; the open_pdks
|
||||
* default install path /usr/share/pdk/, and magic's install
|
||||
* path. For CAD_ROOT the variable is expected to point to
|
||||
* a path containing the techfile. For PDK_PATH and PDK_ROOT,
|
||||
* search the directory tree for any subdirectory called
|
||||
* magic/ and look for a compatible techfile there.
|
||||
*/
|
||||
char *found = NULL;
|
||||
char *string, *techfullname;
|
||||
|
||||
techfullname = mallocMagic(strlen(tech) + 6);
|
||||
sprintf(techfullname, "%s.tech", tech);
|
||||
|
||||
string = getenv("PDK_PATH");
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
if (!found)
|
||||
{
|
||||
string = getenv("PDKPATH");
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
string = getenv("PDK_ROOT");
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
string = getenv("PDKROOT");
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
found = DBSearchForTech(techfullname, "/usr/share/pdk", 0);
|
||||
}
|
||||
#ifdef MAGIC_WRAPPER
|
||||
/* Additional checks for PDK_PATH, etc., as Tcl variables. */
|
||||
/* This is unlikely, as they would have to be set in a */
|
||||
/* startup file, and a startup file is likely to just load */
|
||||
/* the technology itself. */
|
||||
if (!found)
|
||||
{
|
||||
string = (char *)Tcl_GetVar(magicinterp, "PDK_ROOT",
|
||||
TCL_GLOBAL_ONLY);
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
string = (char *)Tcl_GetVar(magicinterp, "PDKROOT",
|
||||
TCL_GLOBAL_ONLY);
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
string = (char *)Tcl_GetVar(magicinterp, "PDK_PATH",
|
||||
TCL_GLOBAL_ONLY);
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
string = (char *)Tcl_GetVar(magicinterp, "PDKPATH",
|
||||
TCL_GLOBAL_ONLY);
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
freeMagic(techfullname);
|
||||
if (found)
|
||||
{
|
||||
char *sptr;
|
||||
PaAppend(&SysLibPath, found);
|
||||
|
||||
TxError("Loading technology %s\n", tech);
|
||||
if (!TechLoad(tech, 0))
|
||||
TxError("Error in loading technology file\n");
|
||||
else if ((sptr = strstr(found, "libs.tech")) != NULL)
|
||||
{
|
||||
int paths = 0;
|
||||
/* Additional automatic handling of open_pdks- */
|
||||
/* style PDKs. Append the libs.ref libraries */
|
||||
/* to the cell search path. */
|
||||
|
||||
strcpy(sptr + 5, "ref");
|
||||
paths = DBAddStandardCellPaths(found, 0);
|
||||
if (paths > 0)
|
||||
TxPrintf("Cell path is now \"%s\"\n", CellLibPath);
|
||||
}
|
||||
freeMagic(found);
|
||||
}
|
||||
}
|
||||
if (strcmp(DBTechName, tech))
|
||||
{
|
||||
TxError("Use command \"tech load\" if you want to switch"
|
||||
" technologies, or use\n");
|
||||
TxError("\"cellname delete %s\" and \"load %s -force\" to"
|
||||
" force the cell to load as technology %s\n",
|
||||
cellDef->cd_name, cellDef->cd_name, DBTechName);
|
||||
SigEnableInterrupts();
|
||||
return (FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dbFgets(line, sizeof line, f) == NULL)
|
||||
|
|
@ -609,6 +844,7 @@ done:
|
|||
* timestamp, then force the cell to be written out with a
|
||||
* correct timestamp.
|
||||
*/
|
||||
has_mismatch = FALSE;
|
||||
if ((cellDef->cd_timestamp != cellStamp) || (cellStamp == 0))
|
||||
{
|
||||
CellUse *cu;
|
||||
|
|
@ -617,12 +853,13 @@ done:
|
|||
if (cu->cu_parent != NULL)
|
||||
{
|
||||
DBStampMismatch(cellDef, &cellDef->cd_bbox);
|
||||
has_mismatch = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Update timestamp flags */
|
||||
DBFlagMismatches(cellDef);
|
||||
if (has_mismatch) DBFlagMismatches(cellDef);
|
||||
|
||||
cellDef->cd_timestamp = cellStamp;
|
||||
if (cellStamp == 0)
|
||||
|
|
@ -634,7 +871,8 @@ done:
|
|||
}
|
||||
|
||||
UndoEnable();
|
||||
DRCCheckThis(cellDef, TT_CHECKPAINT, (Rect *) NULL);
|
||||
/* Disabled 3/16/2021. Let <<checkpaint>> in file force a DRC check */
|
||||
/* DRCCheckThis(cellDef, TT_CHECKPAINT, (Rect *) NULL); */
|
||||
SigEnableInterrupts();
|
||||
return (result);
|
||||
|
||||
|
|
@ -3167,6 +3405,105 @@ dbClearCellFunc(cellUse, cdarg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* DBPathSubstitute --
|
||||
*
|
||||
* Replace the leading part of a file path string according to the following
|
||||
* criteria:
|
||||
*
|
||||
* 1) If the filename starts with a string equal to the contents of
|
||||
* Tcl variables PDK_PATH, PDKPATH, PDK_ROOT, or PDKROOT, then
|
||||
* replace the string with the variable name. The "PATH" names are
|
||||
* more specific than "ROOT" and so are checked first.
|
||||
* 2) If the filename starts with a string equal to the contents of
|
||||
* environment variable HOME, then replace the string with "~".
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side Effects:
|
||||
* Writes into the string "cstring".
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
DBPathSubstitute(pathstart, cstring, cellDef)
|
||||
char *pathstart;
|
||||
char *cstring;
|
||||
CellDef *cellDef;
|
||||
{
|
||||
bool subbed = FALSE;
|
||||
#ifdef MAGIC_WRAPPER
|
||||
char *tvar;
|
||||
|
||||
/* 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 (subbed == FALSE)
|
||||
{
|
||||
tvar = (char *)Tcl_GetVar(magicinterp, "PDK_PATH", TCL_GLOBAL_ONLY);
|
||||
if (tvar)
|
||||
if (!strncmp(pathstart, tvar, strlen(tvar)))
|
||||
{
|
||||
sprintf(cstring, "$PDK_PATH%s", 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, "$PDKPATH%s", 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, "$PDK_ROOT%s", 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, "$PDKROOT%s", 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 (cellDef->cd_file == NULL)
|
||||
sprintf(cstring, "%s", pathstart);
|
||||
else if (!strncmp(cellDef->cd_file, homedir, strlen(homedir))
|
||||
&& (*(cellDef->cd_file + strlen(homedir)) == '/'))
|
||||
sprintf(cstring, "~%s", cellDef->cd_file + strlen(homedir));
|
||||
else
|
||||
sprintf(cstring, "%s", pathstart);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -3192,8 +3529,7 @@ dbWriteCellFunc(cellUse, cdarg)
|
|||
struct writeArg *arg = (struct writeArg *) cdarg;
|
||||
Transform *t;
|
||||
Rect *b;
|
||||
bool subbed = FALSE;
|
||||
char cstring[256], *pathend, *pathstart, *parent;
|
||||
char cstring[1024], *pathend, *pathstart, *parent;
|
||||
|
||||
t = &(cellUse->cu_transform);
|
||||
b = &(cellUse->cu_def->cd_bbox);
|
||||
|
|
@ -3244,92 +3580,13 @@ dbWriteCellFunc(cellUse, cdarg)
|
|||
}
|
||||
else
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
char *tvar;
|
||||
|
||||
/* 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 (subbed == FALSE)
|
||||
{
|
||||
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,
|
||||
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
|
||||
cellUse->cu_id, pathstart);
|
||||
}
|
||||
}
|
||||
sprintf(cstring, "use %s %c%s ", cellUse->cu_def->cd_name,
|
||||
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
|
||||
cellUse->cu_id);
|
||||
DBPathSubstitute(pathstart, cstring + strlen(cstring), cellUse->cu_def);
|
||||
strcat(cstring, "\n");
|
||||
}
|
||||
|
||||
FPRINTR(arg->wa_file, cstring);
|
||||
|
||||
cellUse->cu_def->cd_flags |= CDVISITED;
|
||||
|
|
|
|||
|
|
@ -2573,7 +2573,7 @@ DBPaintPlaneVert(plane, area, resultTbl, undo)
|
|||
Tile *newtile, *tp; /* Used for paint */
|
||||
|
||||
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
|
||||
|
|
@ -2798,6 +2798,7 @@ paintdone:
|
|||
|
||||
done:
|
||||
plane->pl_hint = tile;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -83,6 +83,15 @@ DBPropPut(cellDef, name, value)
|
|||
cellDef->cd_flags |= CDFIXEDBBOX;
|
||||
}
|
||||
|
||||
/* Special handling of GDS_FILE, which uses CDVENDORGDS as a quick lookup */
|
||||
if (!strcmp(name, "GDS_FILE"))
|
||||
{
|
||||
if (value == (ClientData)NULL)
|
||||
cellDef->cd_flags &= ~CDVENDORGDS;
|
||||
else
|
||||
cellDef->cd_flags |= CDVENDORGDS;
|
||||
}
|
||||
|
||||
entry = HashFind(htab, name);
|
||||
oldvalue = (char *)HashGetValue(entry);
|
||||
if (oldvalue != NULL) freeMagic(oldvalue);
|
||||
|
|
|
|||
|
|
@ -425,7 +425,8 @@ DBTechFinalConnect()
|
|||
for (n = 0; n < dbNumContacts; n++)
|
||||
{
|
||||
lp = dbContactInfo[n];
|
||||
TTMaskSetOnlyType(&DBNotConnectTbl[lp->l_type], lp->l_type);
|
||||
TTMaskZero(&DBNotConnectTbl[lp->l_type]);
|
||||
TTMaskSetMask(&DBNotConnectTbl[lp->l_type], &DBConnectTbl[lp->l_type]);
|
||||
rMask = DBResidueMask(lp->l_type);
|
||||
|
||||
/* Different contact types may share residues. */
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@
|
|||
#include "utils/hash.h"
|
||||
#endif /* _HASH_H */
|
||||
|
||||
#ifndef _STACK_H
|
||||
#include "utils/stack.h"
|
||||
#endif /* _STACK_H */
|
||||
|
||||
#ifndef _BPLANE_H
|
||||
#include "bplane/bplane.h"
|
||||
#endif /* _BPLANE_H */
|
||||
|
|
@ -658,6 +662,54 @@ typedef struct treeFilter
|
|||
/* To do: Make the tpath entries dynamically allocated */
|
||||
#define FLATTERMSIZE 4096 /* Used for generating flattened labels */
|
||||
|
||||
/* ------------ Information used in connectivity searches --------------*/
|
||||
|
||||
/* The following structure is used to hold several pieces of information
|
||||
* that must be passed through multiple levels of search function. This
|
||||
* structure is used by DBSrConnect, DBTreeCopyConnect, SimTreeCopyConnect,
|
||||
* and DBTreeCopyConnectDCS.
|
||||
*/
|
||||
|
||||
struct conSrArg
|
||||
{
|
||||
CellDef *csa_def; /* Definition being searched. */
|
||||
int csa_pNum; /* Index of plane being searched */
|
||||
TileTypeBitMask *csa_connect; /* Table indicating what connects
|
||||
* to what.
|
||||
*/
|
||||
int (*csa_clientFunc)(); /* Client function to call. */
|
||||
ClientData csa_clientData; /* Argument for clientFunc. */
|
||||
bool csa_clear; /* FALSE means pass 1, TRUE
|
||||
* means pass 2.
|
||||
*/
|
||||
Rect csa_bounds; /* Area that limits search. */
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Rect area; /* Area to process */
|
||||
TileTypeBitMask *connectMask; /* Connection mask for search */
|
||||
TileType dinfo; /* Info about triangular search areas */
|
||||
} conSrArea;
|
||||
|
||||
struct conSrArg2
|
||||
{
|
||||
CellUse *csa2_use; /* Destination use */
|
||||
TileTypeBitMask *csa2_connect; /* Table indicating what connects
|
||||
* to what.
|
||||
*/
|
||||
SearchContext *csa2_topscx; /* Original top-level search context */
|
||||
int csa2_xMask; /* Cell window mask for search */
|
||||
Rect *csa2_bounds; /* Area that limits the search */
|
||||
|
||||
Stack *csa2_stack; /* Stack of full csa2_list entries */
|
||||
conSrArea *csa2_list; /* List of areas to process */
|
||||
int csa2_top; /* Index of next area to process */
|
||||
int csa2_lasttop; /* Previous top index */
|
||||
};
|
||||
|
||||
#define CSA2_LIST_SIZE 65536 /* Number of entries per list */
|
||||
|
||||
/* -------------- Undo information passed to DBPaintPlane ------------- */
|
||||
|
||||
typedef struct
|
||||
|
|
@ -725,6 +777,7 @@ extern void DBFileRecovery();
|
|||
extern bool DBWriteBackup();
|
||||
extern bool DBReadBackup();
|
||||
extern void DBRemoveBackup();
|
||||
extern void DBPathSubstitute();
|
||||
|
||||
/* Labels */
|
||||
extern Label *DBPutLabel();
|
||||
|
|
@ -790,7 +843,9 @@ extern CellUse *DBFindUse();
|
|||
|
||||
/* Insertion/deletion of cell uses into the cell tile plane of a parent */
|
||||
extern void DBPlaceCell();
|
||||
extern void DBPlaceCellNoModify();
|
||||
extern void DBDeleteCell();
|
||||
extern void DBDeleteCellNoModify();
|
||||
extern void DBClearCellPlane();
|
||||
|
||||
/* Insertion/deletion of cell uses into the name space of a parent */
|
||||
|
|
@ -821,6 +876,7 @@ extern void DBCellCopyLabels();
|
|||
extern void DBCellCopyAllLabels();
|
||||
extern void DBCellCopyCells();
|
||||
extern void DBCellCopyAllCells();
|
||||
extern Plane *DBCellGenerateSubstrate();
|
||||
|
||||
/* Contact image handling */
|
||||
extern TileType DBPlaneToResidue();
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ extern void CmdAddPath(), CmdAntennaCheck(), CmdArray();
|
|||
extern void CmdBox(), CmdCellname(), CmdClockwise();
|
||||
extern void CmdContact(), CmdCopy(), CmdCorner();
|
||||
extern void CmdCrash(), CmdCrosshair();
|
||||
extern void CmdDelete(), CmdDown(), CmdDrc(), CmdDump();
|
||||
extern void CmdDelete(), CmdDown(), CmdDrc(), CmdDrop(), CmdDump();
|
||||
extern void CmdEdit(), CmdElement(), CmdErase(), CmdExpand(), CmdExtract();
|
||||
extern void CmdFeedback(), CmdFill(), CmdFindBox(), CmdFindLabel(), CmdFlush();
|
||||
extern void CmdGetcell(), CmdGrid(), CmdIdentify();
|
||||
|
|
@ -278,6 +278,10 @@ DBWInitCommands()
|
|||
"drc option design rule checker; type \"drc help\"\n"
|
||||
" for information on options",
|
||||
CmdDrc, FALSE);
|
||||
WindAddCommand(DBWclientID,
|
||||
"drop layers copy layers from edit cell into\n"
|
||||
" subcells containing selected paint",
|
||||
CmdDrop, FALSE);
|
||||
WindAddCommand(DBWclientID,
|
||||
"dump cell [child refPointC] [parent refPointP]\n\
|
||||
copy contents of cell into edit cell, so that\n\
|
||||
|
|
|
|||
|
|
@ -790,6 +790,31 @@ DBWSetBox(rootDef, rect)
|
|||
dbwRecordBoxArea(FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* DBWResetBox() ---
|
||||
*
|
||||
* Make sure that boxRootDef is set to NULL if it is equal to the
|
||||
* specified CellDef. This is used by the cell delete function to
|
||||
* make sure that if an edit cell is deleted, the boxRootDef is not
|
||||
* pointing to an invalid area of memory.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Global variable boxRootDef may be set to NULL.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
DBWResetBox(CellDef *def)
|
||||
{
|
||||
if (def == boxRootDef)
|
||||
boxRootDef = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* ToolMoveBox --
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ extern void ToolMoveBox(), ToolMoveCorner();
|
|||
extern int ToolGetCorner();
|
||||
extern void DBWloadWindow(), DBWxloadWindow();
|
||||
extern void DBWSetBox();
|
||||
extern void DBWResetBox();
|
||||
extern void DBWUndoOldEdit();
|
||||
extern void DBWUndoNewEdit();
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ drcArrayFunc(scx, arg)
|
|||
int xsep, ysep;
|
||||
int xsize, ysize;
|
||||
int rval, oldTiles;
|
||||
Rect errorArea, yankArea, tmp, tmp2;
|
||||
Rect errorArea, yankArea, tmp, tmp2, saveClip;
|
||||
DRCCookie *save_cptr;
|
||||
CellUse *use = scx->scx_use;
|
||||
Rect *area;
|
||||
|
|
@ -114,7 +114,7 @@ drcArrayFunc(scx, arg)
|
|||
ClientData drcArrayClientData; /* Extra parameter to pass to func. */
|
||||
PaintResultType (*savedPaintTable)[NT][NT];
|
||||
PaintResultType (*savedEraseTable)[NT][NT];
|
||||
void (*savedPaintPlane)();
|
||||
int (*savedPaintPlane)();
|
||||
|
||||
if ((use->cu_xlo == use->cu_xhi) && (use->cu_ylo == use->cu_yhi))
|
||||
return 2;
|
||||
|
|
@ -183,6 +183,8 @@ drcArrayFunc(scx, arg)
|
|||
(ClientData) &yankArea);
|
||||
drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea,
|
||||
drcArrayErrorFunc, drcArrayClientData);
|
||||
*arg->dCD_clip = *area;
|
||||
GeoClip(arg->dCD_clip, &yankArea);
|
||||
(void) DBArraySr(use, &errorArea, drcArrayOverlapFunc,
|
||||
(ClientData) arg);
|
||||
}
|
||||
|
|
@ -200,6 +202,8 @@ drcArrayFunc(scx, arg)
|
|||
(ClientData) &yankArea);
|
||||
drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea,
|
||||
drcArrayErrorFunc, drcArrayClientData);
|
||||
*arg->dCD_clip = *area;
|
||||
GeoClip(arg->dCD_clip, &yankArea);
|
||||
(void) DBArraySr(use, &errorArea, drcArrayOverlapFunc,
|
||||
(ClientData) arg);
|
||||
}
|
||||
|
|
@ -222,6 +226,8 @@ drcArrayFunc(scx, arg)
|
|||
(ClientData) &yankArea);
|
||||
drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea,
|
||||
drcArrayErrorFunc, drcArrayClientData);
|
||||
*arg->dCD_clip = *area;
|
||||
GeoClip(arg->dCD_clip, &yankArea);
|
||||
(void) DBArraySr(use, &errorArea, drcArrayOverlapFunc,
|
||||
(ClientData) arg);
|
||||
}
|
||||
|
|
@ -239,11 +245,16 @@ drcArrayFunc(scx, arg)
|
|||
(ClientData) &yankArea);
|
||||
drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea,
|
||||
drcArrayErrorFunc, drcArrayClientData);
|
||||
*arg->dCD_clip = *area;
|
||||
GeoClip(arg->dCD_clip, &yankArea);
|
||||
(void) DBArraySr(use, &errorArea, drcArrayOverlapFunc,
|
||||
(ClientData) arg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore original clip rect */
|
||||
*arg->dCD_clip = *area;
|
||||
|
||||
(void) DBNewPaintTable(savedPaintTable);
|
||||
(void) DBNewPaintPlane(savedPaintPlane);
|
||||
|
||||
|
|
|
|||
185
drc/DRCbasic.c
185
drc/DRCbasic.c
|
|
@ -26,6 +26,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h> // for memcpy()
|
||||
#include <math.h> // for sqrt() for diagonal check
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "tiles/tile.h"
|
||||
|
|
@ -268,6 +269,47 @@ areaCheck(tile, arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* areaNMCheck ---
|
||||
*
|
||||
* Check for errors in triangular area of a tile
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
areaNMCheck(tile, arg)
|
||||
Tile *tile;
|
||||
struct drcClientData *arg;
|
||||
{
|
||||
Rect rect; /* Area where error is to be recorded. */
|
||||
|
||||
/* Ignore the tile that initiates the check, because the error area */
|
||||
/* of a non-Manhattan check may fall inside of it. */
|
||||
if (tile == arg->dCD_initial) return 0;
|
||||
|
||||
TiToRect(tile, &rect);
|
||||
|
||||
/* Only consider the portion of the suspicious tile that overlaps
|
||||
* the clip area for errors, unless this is a trigger rule.
|
||||
*/
|
||||
|
||||
if (!(arg->dCD_cptr->drcc_flags & DRC_TRIGGER))
|
||||
GeoClip(&rect, arg->dCD_clip);
|
||||
|
||||
GeoClip(&rect, arg->dCD_constraint);
|
||||
if ((rect.r_xbot >= rect.r_xtop) || (rect.r_ybot >= rect.r_ytop))
|
||||
return 0;
|
||||
|
||||
(*(arg->dCD_function))(arg->dCD_celldef, &rect, arg->dCD_cptr,
|
||||
arg->dCD_clientData);
|
||||
(*(arg->dCD_errors))++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -412,8 +454,11 @@ drcTile (tile, arg)
|
|||
|
||||
if (IsSplit(tile))
|
||||
{
|
||||
int deltax, deltay;
|
||||
TileType tt, to;
|
||||
|
||||
/* Check rules for DRC_ANGLES rule and process */
|
||||
TileType tt = TiGetLeftType(tile);
|
||||
tt = TiGetLeftType(tile);
|
||||
if (tt != TT_SPACE)
|
||||
{
|
||||
for (cptr = DRCCurStyle->DRCRulesTbl[TT_SPACE][tt];
|
||||
|
|
@ -436,8 +481,98 @@ drcTile (tile, arg)
|
|||
}
|
||||
}
|
||||
|
||||
/* This drc is only for the left edge of the tile */
|
||||
if (SplitSide(tile)) goto checkbottom;
|
||||
/* Full check of edge rules along the diagonal. */
|
||||
if (SplitSide(tile))
|
||||
{
|
||||
tt = TiGetRightType(tile); /* inside type */
|
||||
to = TiGetLeftType(tile); /* outside type */
|
||||
}
|
||||
else
|
||||
{
|
||||
tt = TiGetLeftType(tile); /* inside type */
|
||||
to = TiGetRightType(tile); /* outside type */
|
||||
}
|
||||
|
||||
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
||||
cptr = cptr->drcc_next)
|
||||
{
|
||||
int deltax, deltay, w, h;
|
||||
double r;
|
||||
TileType dinfo, dsplit;
|
||||
|
||||
/* Work to be done: Handle triggering rules for non-Manhattan */
|
||||
/* edges; especially important for the wide-spacing rule. */
|
||||
|
||||
if (cptr->drcc_flags & DRC_TRIGGER)
|
||||
{
|
||||
cptr = cptr->drcc_next; // Skip both triggering and triggered rules
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Note: Triggered wide-spacing rule will require handling */
|
||||
/* the DRC_MAXWIDTH rule on non-Manhattan edges. */
|
||||
|
||||
if (cptr->drcc_flags & (DRC_ANGLES | DRC_AREA | DRC_MAXWIDTH
|
||||
| DRC_RECTSIZE | DRC_OFFGRID))
|
||||
continue;
|
||||
|
||||
TiToRect(tile, &errRect);
|
||||
|
||||
/* Find the rule distances according to the scale factor */
|
||||
dist = cptr->drcc_dist;
|
||||
|
||||
/* drcc_edgeplane is used to avoid checks on edges */
|
||||
/* in more than one plane */
|
||||
|
||||
if (arg->dCD_plane != cptr->drcc_edgeplane) continue;
|
||||
|
||||
DRCstatRules++;
|
||||
|
||||
DRCstatSlow++;
|
||||
arg->dCD_cptr = cptr;
|
||||
arg->dCD_entries = 0;
|
||||
TTMaskCom2(&tmpMask, &cptr->drcc_mask);
|
||||
TTMaskClearType(&tmpMask, TT_ERROR_S);
|
||||
arg->dCD_initial = tile;
|
||||
|
||||
/* Compute position that is the rule distance away from */
|
||||
/* the tile's diagonal edge, by Euclidean measure */
|
||||
/* (rounded down if fractional). Use the forward */
|
||||
/* position, and negate if reversed. */
|
||||
|
||||
w = RIGHT(tile) - LEFT(tile);
|
||||
h = TOP(tile) - BOTTOM(tile);
|
||||
r = 1.0 / (1.0 + ((double)(w * w) / (double)(h * h)));
|
||||
deltax = (int)((double)cptr->drcc_dist * sqrt(r));
|
||||
deltay = (deltax * w) / h;
|
||||
|
||||
if (SplitSide(tile) == 1) deltax = -deltax;
|
||||
if (SplitDirection(tile) == SplitSide(tile)) deltay = -deltay;
|
||||
|
||||
dinfo = TiGetTypeExact(tile) & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE);
|
||||
if (!(cptr->drcc_flags & DRC_REVERSE))
|
||||
{
|
||||
/* Forward case is behind the triangle */
|
||||
deltax = -deltax;
|
||||
deltay = -deltay;
|
||||
/* Split side changes in the reverse case */
|
||||
if (SplitSide(tile))
|
||||
dinfo &= (~TT_SIDE);
|
||||
else
|
||||
dinfo |= TT_SIDE;
|
||||
}
|
||||
|
||||
/* errRect is the tile area offset by (deltax, deltay) */
|
||||
errRect.r_xbot += deltax;
|
||||
errRect.r_ybot += deltay;
|
||||
errRect.r_xtop += deltax;
|
||||
errRect.r_ytop += deltay;
|
||||
|
||||
DBSrPaintNMArea((Tile *) NULL,
|
||||
arg->dCD_celldef->cd_planes[cptr->drcc_plane], dinfo,
|
||||
&errRect, &tmpMask, areaNMCheck, (ClientData) arg);
|
||||
}
|
||||
DRCstatEdges++;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -604,9 +739,17 @@ drcTile (tile, arg)
|
|||
}
|
||||
else if (cptr->drcc_flags & DRC_MAXWIDTH)
|
||||
{
|
||||
/* bends_illegal option only */
|
||||
if (firsttile)
|
||||
drcCheckMaxwidth(tile, arg, cptr);
|
||||
if (cptr->drcc_flags & DRC_MAXWIDTH_BOTH)
|
||||
{
|
||||
if (firsttile)
|
||||
drcCheckMaxwidth(tile, arg, cptr, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* bends_illegal option only */
|
||||
if (firsttile)
|
||||
drcCheckMaxwidth(tile, arg, cptr, FALSE);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -671,8 +814,8 @@ drcTile (tile, arg)
|
|||
else tpl = tpleft;
|
||||
|
||||
/* Make sure the edge stops at edgeBot */
|
||||
if ((TiGetTopType(tpl) != TiGetBottomType(tpleft)) ||
|
||||
(TiGetTopType(tpr) != TiGetBottomType(tile)))
|
||||
if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
|
||||
(TiGetLeftType(tpr) != TiGetLeftType(tile)))
|
||||
{
|
||||
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpr)))
|
||||
{
|
||||
|
|
@ -698,8 +841,8 @@ drcTile (tile, arg)
|
|||
else tpl = tpleft;
|
||||
|
||||
/* Make sure the edge stops at edgeTop */
|
||||
if ((TiGetBottomType(tpl) != TiGetTopType(tpleft)) ||
|
||||
(TiGetBottomType(tpr) != TiGetTopType(tile)))
|
||||
if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
|
||||
(TiGetLeftType(tpr) != TiGetLeftType(tile)))
|
||||
{
|
||||
if (TTMaskHasType(&cptr->drcc_corner,
|
||||
TiGetBottomType(tpr)))
|
||||
|
|
@ -745,8 +888,8 @@ drcTile (tile, arg)
|
|||
else tpr = tile;
|
||||
|
||||
/* Make sure the edge stops at edgeTop */
|
||||
if ((TiGetBottomType(tpl) != TiGetTopType(tpleft)) ||
|
||||
(TiGetBottomType(tpr) != TiGetTopType(tile)))
|
||||
if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
|
||||
(TiGetLeftType(tpr) != TiGetLeftType(tile)))
|
||||
{
|
||||
if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpl)))
|
||||
{
|
||||
|
|
@ -772,8 +915,8 @@ drcTile (tile, arg)
|
|||
else tpr = tile;
|
||||
|
||||
/* Make sure the edge stops at edgeBot */
|
||||
if ((TiGetTopType(tpl) != TiGetBottomType(tpleft)) ||
|
||||
(TiGetTopType(tpr) != TiGetBottomType(tile)))
|
||||
if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
|
||||
(TiGetLeftType(tpr) != TiGetLeftType(tile)))
|
||||
{
|
||||
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpl)))
|
||||
{
|
||||
|
|
@ -834,12 +977,6 @@ drcTile (tile, arg)
|
|||
}
|
||||
}
|
||||
|
||||
/* This drc is only for the bottom edge of the tile */
|
||||
|
||||
checkbottom:
|
||||
if (IsSplit(tile))
|
||||
if (SplitSide(tile) == SplitDirection(tile)) return 0;
|
||||
|
||||
/*
|
||||
* Check design rules along a horizontal boundary between two tiles.
|
||||
*
|
||||
|
|
@ -1044,7 +1181,7 @@ checkbottom:
|
|||
for (tpx = TR(tile); BOTTOM(tpx) > edgeY; tpx = LB(tpx));
|
||||
else tpx = tile;
|
||||
|
||||
if (TTMaskHasType(&cptr->drcc_corner, TiGetLeftType(tpx)))
|
||||
if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpx)))
|
||||
{
|
||||
errRect.r_xtop += cdist;
|
||||
if (DRCEuclidean)
|
||||
|
|
@ -1061,7 +1198,7 @@ checkbottom:
|
|||
if (LEFT(tile) >= errRect.r_xbot) tpx = BL(tile);
|
||||
else tpx = tile;
|
||||
|
||||
if (TTMaskHasType(&cptr->drcc_corner, TiGetRightType(tpx)))
|
||||
if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpx)))
|
||||
{
|
||||
errRect.r_xbot -= cdist;
|
||||
if (DRCEuclidean)
|
||||
|
|
@ -1098,7 +1235,7 @@ checkbottom:
|
|||
for (tpx = BL(tpbot); TOP(tpx) < edgeY; tpx = RT(tpx));
|
||||
else tpx = tpbot;
|
||||
|
||||
if (TTMaskHasType(&cptr->drcc_corner, TiGetRightType(tpx)))
|
||||
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpx)))
|
||||
{
|
||||
errRect.r_xbot -= cdist;
|
||||
if (DRCEuclidean)
|
||||
|
|
@ -1114,7 +1251,7 @@ checkbottom:
|
|||
if (RIGHT(tpbot) <= errRect.r_xtop) tpx = TR(tpbot);
|
||||
else tpx = tpbot;
|
||||
|
||||
if (TTMaskHasType(&cptr->drcc_corner, TiGetLeftType(tpx)))
|
||||
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpx)))
|
||||
{
|
||||
errRect.r_xtop += cdist;
|
||||
if (DRCEuclidean)
|
||||
|
|
|
|||
|
|
@ -257,11 +257,14 @@ forgetit:
|
|||
*/
|
||||
|
||||
int
|
||||
drcCheckMaxwidth(starttile,arg,cptr)
|
||||
drcCheckMaxwidth(starttile,arg,cptr,both)
|
||||
Tile *starttile;
|
||||
struct drcClientData *arg;
|
||||
DRCCookie *cptr;
|
||||
bool both;
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int edgelimit;
|
||||
int retval = 0;
|
||||
Rect boundrect;
|
||||
|
|
@ -314,8 +317,11 @@ drcCheckMaxwidth(starttile,arg,cptr)
|
|||
if (TTMaskHasType(oktypes, TiGetLeftType(tp))) PUSHTILE(tp);
|
||||
}
|
||||
|
||||
if (boundrect.r_xtop - boundrect.r_xbot > edgelimit &&
|
||||
boundrect.r_ytop - boundrect.r_ybot > edgelimit)
|
||||
width = boundrect.r_xtop - boundrect.r_xbot;
|
||||
height = boundrect.r_ytop - boundrect.r_ybot;
|
||||
|
||||
if ( (width > edgelimit && height > edgelimit) ||
|
||||
( both == TRUE && (width > edgelimit || height > edgelimit)) )
|
||||
{
|
||||
Rect rect;
|
||||
TiToRect(starttile,&rect);
|
||||
|
|
|
|||
|
|
@ -539,13 +539,23 @@ drcExactOverlapTile(tile, cxp)
|
|||
|
||||
type = TiGetType(tile);
|
||||
TTMaskSetOnlyType(&typeMask, type);
|
||||
for (t = DBNumUserLayers; t < DBNumTypes; t++)
|
||||
if (type < DBNumUserLayers)
|
||||
{
|
||||
rmask = DBResidueMask(t);
|
||||
if (TTMaskHasType(rmask, type))
|
||||
TTMaskSetType(&typeMask, t);
|
||||
for (t = DBNumUserLayers; t < DBNumTypes; t++)
|
||||
{
|
||||
rmask = DBResidueMask(t);
|
||||
if (TTMaskHasType(rmask, type))
|
||||
TTMaskSetType(&typeMask, t);
|
||||
}
|
||||
TTMaskCom2(&invMask, &typeMask);
|
||||
}
|
||||
else
|
||||
{
|
||||
rmask = DBResidueMask(type);
|
||||
TTMaskSetMask(&typeMask, rmask); // Add residue types for inverse only
|
||||
TTMaskCom2(&invMask, &typeMask);
|
||||
TTMaskSetOnlyType(&typeMask, type); // Restore original type mask
|
||||
}
|
||||
TTMaskCom2(&invMask, &typeMask);
|
||||
|
||||
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
|
||||
{
|
||||
|
|
@ -647,6 +657,7 @@ void
|
|||
DRCOffGridError(rect)
|
||||
Rect *rect; /* Area of error */
|
||||
{
|
||||
if (drcSubFunc == NULL) return;
|
||||
(*drcSubFunc)(DRCErrorDef, rect, &drcOffGridCookie, drcSubClientData);
|
||||
}
|
||||
|
||||
|
|
@ -696,7 +707,7 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
int oldTiles, count, x, y, errorSaveType;
|
||||
Rect intArea, square, cliparea, subArea;
|
||||
PaintResultType (*savedPaintTable)[NT][NT];
|
||||
void (*savedPaintPlane)();
|
||||
int (*savedPaintPlane)();
|
||||
struct drcClientData arg;
|
||||
SearchContext scx;
|
||||
|
||||
|
|
@ -896,7 +907,7 @@ DRCFlatCheck(use, area)
|
|||
SearchContext scx;
|
||||
void drcIncCount();
|
||||
PaintResultType (*savedPaintTable)[NT][NT];
|
||||
void (*savedPaintPlane)();
|
||||
int (*savedPaintPlane)();
|
||||
int drcFlatCount = 0;
|
||||
|
||||
UndoDisable();
|
||||
|
|
|
|||
|
|
@ -1550,6 +1550,7 @@ drcOffGrid(argc, argv)
|
|||
* bend_ok - Used mainly for wide metal rules where metal greater than
|
||||
* some given width must be slotted. Also, used for things
|
||||
* like trench, where the width is some fixed value:
|
||||
* both - implies bend_illegal and both directions are checked
|
||||
*
|
||||
* XXXXX XXXXXX
|
||||
* X X XXXXXX
|
||||
|
|
@ -1608,6 +1609,7 @@ drcMaxwidth(argc, argv)
|
|||
{
|
||||
if (strcmp(bends,"bend_illegal") == 0) bend = 0;
|
||||
else if (strcmp(bends,"bend_ok") == 0) bend = DRC_BENDS;
|
||||
else if (strcmp(bends,"both") == 0) bend = DRC_MAXWIDTH_BOTH;
|
||||
else
|
||||
{
|
||||
TechError("unknown bend option %s\n",bends);
|
||||
|
|
|
|||
|
|
@ -73,8 +73,9 @@ typedef struct drccookie
|
|||
#define DRC_AREA 0x020
|
||||
#define DRC_OFFGRID 0x040
|
||||
#define DRC_MAXWIDTH 0x080
|
||||
#define DRC_RECTSIZE 0x100
|
||||
#define DRC_ANGLES 0x200
|
||||
#define DRC_MAXWIDTH_BOTH 0x100
|
||||
#define DRC_RECTSIZE 0x200
|
||||
#define DRC_ANGLES 0x400
|
||||
#define DRC_NONSTANDARD (DRC_AREA|DRC_MAXWIDTH|DRC_RECTSIZE\
|
||||
|DRC_ANGLES|DRC_OFFGRID)
|
||||
|
||||
|
|
|
|||
|
|
@ -999,11 +999,12 @@ simdevVisit(dev, hc, scale, trans)
|
|||
float scale; /* Scale transform for output */
|
||||
Transform *trans; /* Coordinate transform */
|
||||
{
|
||||
DevTerm *gate, *source, *drain;
|
||||
DevTerm *gate, *source, *drain, *term;
|
||||
EFNode *subnode, *snode, *dnode;
|
||||
int l, w;
|
||||
Rect r;
|
||||
char name[12];
|
||||
bool is_subckt = FALSE;
|
||||
HierName *hierName = hc->hc_hierName;
|
||||
|
||||
sprintf(name, "output");
|
||||
|
|
@ -1057,7 +1058,6 @@ simdevVisit(dev, hc, scale, trans)
|
|||
case DEV_FET:
|
||||
case DEV_MOSFET:
|
||||
case DEV_ASYMMETRIC:
|
||||
case DEV_MSUBCKT:
|
||||
/* The sim file format only understands "n" and "p" for FETs. */
|
||||
/* The extraction method says nothing about which is which. */
|
||||
/* The EFDevTypes[] should ideally start with "n" or "p". If */
|
||||
|
|
@ -1089,6 +1089,19 @@ simdevVisit(dev, hc, scale, trans)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case DEV_MSUBCKT:
|
||||
case DEV_CSUBCKT:
|
||||
case DEV_RSUBCKT:
|
||||
case DEV_SUBCKT:
|
||||
/* Use the 'x' type in .sim format. This is implemented in the */
|
||||
/* IRSIM "user subcircuit" package, so it has a valid syntax. */
|
||||
/* It is used by the extresist code in magic as a way to work */
|
||||
/* around the lack of substrate and lack of device names in the */
|
||||
/* .sim format. */
|
||||
is_subckt = TRUE;
|
||||
fprintf(esSimF, "x");
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(esSimF, "%c", EFDevTypes[dev->dev_type][0]);
|
||||
break;
|
||||
|
|
@ -1121,8 +1134,31 @@ simdevVisit(dev, hc, scale, trans)
|
|||
else if (dev->dev_nterm > 2)
|
||||
simdevOutNode(hierName, drain->dterm_node->efnode_name->efnn_hier, name, esSimF);
|
||||
|
||||
if (dev->dev_nterm > 3) /* For subcircuit support ('x' device) */
|
||||
{
|
||||
int i;
|
||||
|
||||
sprintf(name, "subckt");
|
||||
for (i = 3; i < dev->dev_nterm; i++)
|
||||
{
|
||||
term = &dev->dev_terms[i];
|
||||
simdevOutNode(hierName, term->dterm_node->efnode_name->efnn_hier,
|
||||
name, esSimF);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_subckt && subnode)
|
||||
{
|
||||
/* As a general policy on subcircuits supporting extresist, */
|
||||
/* output the subcircuit node as the last port of the */
|
||||
/* subcircuit definition. */
|
||||
putc(' ', esSimF);
|
||||
simdevSubstrate(hierName, subnode->efnode_name->efnn_hier,
|
||||
dev->dev_type, 0.0, FALSE, esSimF);
|
||||
}
|
||||
|
||||
/* Support gemini's substrate comparison */
|
||||
if (esFormat == LBL && subnode)
|
||||
else if (esFormat == LBL && subnode)
|
||||
{
|
||||
putc(' ', esSimF);
|
||||
simdevSubstrate(hierName, subnode->efnode_name->efnn_hier,
|
||||
|
|
@ -1165,6 +1201,15 @@ simdevVisit(dev, hc, scale, trans)
|
|||
else if (dev->dev_class == DEV_CAPREV) { /* generate a capacitor */
|
||||
fprintf(esSimF, " %f", (double)(dev->dev_cap));
|
||||
}
|
||||
else if (is_subckt)
|
||||
{
|
||||
/* Output length, width, and position as attributes */
|
||||
fprintf(esSimF, " l=%g w=%g x=%g y=%g",
|
||||
l * scale, w * scale, r.r_xbot * scale, r.r_ybot * scale);
|
||||
|
||||
/* Output tile type as an attribute for quick lookup by ResReadSim */
|
||||
fprintf(esSimF, " t=%d", fetInfo[dev->dev_type].devType);
|
||||
}
|
||||
else if ((dev->dev_class != DEV_DIODE) && (dev->dev_class != DEV_PDIODE)
|
||||
&& (dev->dev_class != DEV_NDIODE)) {
|
||||
|
||||
|
|
@ -1235,6 +1280,13 @@ simdevVisit(dev, hc, scale, trans)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_subckt)
|
||||
{
|
||||
/* Last token on a subcircuit 'x' line is the subcircuit name */
|
||||
fprintf(esSimF, " %s", EFDevTypes[dev->dev_type]);
|
||||
}
|
||||
|
||||
fprintf(esSimF, "\n");
|
||||
|
||||
return 0;
|
||||
|
|
@ -1572,9 +1624,8 @@ int simnodeVisit(node, res, cap)
|
|||
|
||||
if (esLabF)
|
||||
{
|
||||
fprintf(esLabF, "94 ");
|
||||
EFHNOut(hierName, esLabF);
|
||||
fprintf(esLabF, " %d %d %s;\n",
|
||||
fprintf(esLabF, " %d %d %s\n",
|
||||
node->efnode_loc.r_xbot, node->efnode_loc.r_ybot,
|
||||
EFLayerNames[node->efnode_type]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ ESGenerateHierarchy(inName, flags)
|
|||
hc.hc_hierName = NULL;
|
||||
hc.hc_trans = GeoIdentityTransform;
|
||||
hc.hc_x = hc.hc_y = 0;
|
||||
|
||||
EFHierSrDefs(&hc, esMakePorts, NULL);
|
||||
EFHierSrDefs(&hc, NULL, NULL); /* Clear processed */
|
||||
|
||||
|
|
@ -500,7 +501,7 @@ spcdevHierVisit(hc, dev, scale)
|
|||
EFNode *subnode, *snode, *dnode, *subnodeFlat = NULL;
|
||||
int l, w, i, parmval;
|
||||
Rect r;
|
||||
bool subAP = FALSE, hierS, hierD, extHierSDAttr(), swapped = FALSE;
|
||||
bool subAP = FALSE, hierS, hierD, extHierSDAttr();
|
||||
float sdM;
|
||||
char devchar;
|
||||
bool has_model = TRUE;
|
||||
|
|
@ -522,6 +523,8 @@ spcdevHierVisit(hc, dev, scale)
|
|||
source = drain = &dev->dev_terms[1];
|
||||
if (dev->dev_nterm >= 3)
|
||||
{
|
||||
drain = &dev->dev_terms[2];
|
||||
|
||||
/* If any terminal is marked with attribute "D" or "S" */
|
||||
/* (label "D$" or "S$" at poly-diffusion interface), */
|
||||
/* then force order of source and drain accordingly. */
|
||||
|
|
@ -531,11 +534,8 @@ spcdevHierVisit(hc, dev, scale)
|
|||
(dev->dev_terms[2].dterm_attrs &&
|
||||
!strcmp(dev->dev_terms[2].dterm_attrs, "S")))
|
||||
{
|
||||
swapDrainSource(dev, &source, &drain);
|
||||
swapped = TRUE;
|
||||
swapDrainSource(dev);
|
||||
}
|
||||
else
|
||||
drain = &dev->dev_terms[2];
|
||||
}
|
||||
else if (dev->dev_nterm == 1) // Is a device with one terminal an error?
|
||||
source = drain = &dev->dev_terms[0];
|
||||
|
|
@ -1023,10 +1023,6 @@ spcdevHierVisit(hc, dev, scale)
|
|||
break;
|
||||
}
|
||||
fprintf(esSpiceF, "\n");
|
||||
|
||||
/* If S/D parameters were swapped, then put them back */
|
||||
if (swapped) swapDrainSource(dev, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1642,8 +1638,11 @@ esMakePorts(hc, cdata)
|
|||
*tptr = '/';
|
||||
portname = tptr + 1;
|
||||
|
||||
// Find the net of portname in the subcell and
|
||||
// make it a port if it is not already.
|
||||
/* Find the net of portname in the subcell and make it a
|
||||
* port if it is not already. It is possible that the
|
||||
* preferred node name is in the merge list, so the merging
|
||||
* code may need to replace it with another name.
|
||||
*/
|
||||
|
||||
if (portdef)
|
||||
{
|
||||
|
|
@ -1897,6 +1896,8 @@ esHierVisit(hc, cdata)
|
|||
freeMagic(p);
|
||||
devMergeList = NULL;
|
||||
}
|
||||
else if (esDistrJunct)
|
||||
EFHierVisitDevs(hcf, devDistJunctHierVisit, (ClientData)NULL);
|
||||
|
||||
/* Output devices */
|
||||
EFHierVisitDevs(hcf, spcdevHierVisit, (ClientData)NULL);
|
||||
|
|
|
|||
|
|
@ -1553,10 +1553,15 @@ subcktVisit(use, hierName, is_top)
|
|||
}
|
||||
}
|
||||
|
||||
/* SPICE subcircuit names must begin with A-Z. This will also be */
|
||||
/* enforced when writing X subcircuit calls. */
|
||||
/* SPICE subcircuit names must begin with A-Z. */
|
||||
subcktname = def->def_name;
|
||||
while (!isalpha(*subcktname)) subcktname++;
|
||||
if (!isalpha(*subcktname))
|
||||
{
|
||||
subcktname = mallocMagic(2 + strlen(def->def_name));
|
||||
sprintf(subcktname, "x%s", def->def_name);
|
||||
freeMagic(def->def_name);
|
||||
def->def_name = subcktname;
|
||||
}
|
||||
|
||||
if (tchars > 80) fprintf(esSpiceF, "\n+");
|
||||
fprintf(esSpiceF, " %s", subcktname); /* subcircuit model name */
|
||||
|
|
@ -1664,7 +1669,13 @@ topVisit(def, doStub)
|
|||
/* SPICE subcircuit names must begin with A-Z. This will also be */
|
||||
/* enforced when writing X subcircuit calls. */
|
||||
subcktname = def->def_name;
|
||||
while (!isalpha(*subcktname)) subcktname++;
|
||||
if (!isalpha(*subcktname))
|
||||
{
|
||||
subcktname = mallocMagic(2 + strlen(def->def_name));
|
||||
sprintf(subcktname, "x%s", def->def_name);
|
||||
freeMagic(def->def_name);
|
||||
def->def_name = subcktname;
|
||||
}
|
||||
|
||||
fprintf(esSpiceF, ".subckt %s", subcktname);
|
||||
tchars = 8 + strlen(subcktname);
|
||||
|
|
@ -1924,7 +1935,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
|
||||
hierD = extHierSDAttr(&dev->dev_terms[pn]);
|
||||
|
||||
resclass == (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain :
|
||||
resclass = (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain :
|
||||
esFetInfo[dev->dev_type].resClassSource;
|
||||
|
||||
// For parameter a<n> followed by parameter p<n>,
|
||||
|
|
@ -1987,7 +1998,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
|
|||
pn = plist->parm_type[1] - '0';
|
||||
if (pn >= dev->dev_nterm) pn = dev->dev_nterm - 1;
|
||||
|
||||
resclass == (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain :
|
||||
resclass = (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain :
|
||||
esFetInfo[dev->dev_type].resClassSource;
|
||||
|
||||
hierD = extHierSDAttr(&dev->dev_terms[pn]);
|
||||
|
|
@ -2219,47 +2230,39 @@ getCurDevMult()
|
|||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
* swapDrainSource
|
||||
*
|
||||
* Swap drain and source ordering and the related stuff
|
||||
* including the drain/source area parameters
|
||||
*
|
||||
* This is typycally called if any terminal is marked with attribute "D" or "S"
|
||||
* This is typically called if any terminal is marked with attribute "D" or "S"
|
||||
* (label "D$" or "S$" at poly-diffusion interface),
|
||||
* then swap order of source and drain compared to the default ordering.
|
||||
*
|
||||
* Note:
|
||||
* Before calling this function, ensure that dev->dev_nterm >= 3
|
||||
*
|
||||
* Results:
|
||||
* None
|
||||
*
|
||||
* Side effects:
|
||||
* Soure (dev->dev_terms[1]) and drain (dev->dev_terms[2]) terminals
|
||||
* are swapped.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
swapDrainSource(dev, source, drain)
|
||||
swapDrainSource(dev)
|
||||
Dev *dev;
|
||||
DevTerm **source, **drain;
|
||||
{
|
||||
DevParam *plist;
|
||||
|
||||
/* swap drain/source ordering */
|
||||
if (drain) *drain = &dev->dev_terms[1];
|
||||
if (source) *source = &dev->dev_terms[2];
|
||||
|
||||
/* Swap drain/source-related parameters. Note that the parameter */
|
||||
/* *definitions* are swapped, so if this is done, it must be */
|
||||
/* reverted before the next device is processed. */
|
||||
DevTerm tmpTerm;
|
||||
|
||||
plist = efGetDeviceParams(EFDevTypes[dev->dev_type]);
|
||||
while (plist != NULL)
|
||||
{
|
||||
// Diagnostic
|
||||
// TxPrintf(" * param: %s; type: %c%c\n", plist->parm_name, plist->parm_type[0], plist->parm_type[1]);
|
||||
|
||||
/* Swap drain/source parameters only */
|
||||
if (!(strcmp(plist->parm_type, "a1")) || !(strcmp(plist->parm_type, "p1")))
|
||||
plist->parm_type[1] = '0' + 2;
|
||||
|
||||
else if (!(strcmp(plist->parm_type, "a2")) || !(strcmp(plist->parm_type, "p2")))
|
||||
plist->parm_type[1] = '0' + 1;
|
||||
|
||||
/* move pointer */
|
||||
plist = plist->parm_next;
|
||||
}
|
||||
/* swap original terminals */
|
||||
memcpy(&tmpTerm, &(dev->dev_terms[1]), sizeof(DevTerm));
|
||||
memcpy(&(dev->dev_terms[1]), &(dev->dev_terms[2]), sizeof(DevTerm));
|
||||
memcpy(&(dev->dev_terms[2]), &tmpTerm, sizeof(DevTerm));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2309,7 +2312,7 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
DevTerm *gate, *source, *drain;
|
||||
EFNode *subnode, *snode, *dnode, *subnodeFlat = NULL;
|
||||
int l, w, i, parmval;
|
||||
bool subAP= FALSE, hierS, hierD, extHierSDAttr(), swapped = FALSE ;
|
||||
bool subAP= FALSE, hierS, hierD, extHierSDAttr();
|
||||
float sdM;
|
||||
char name[12], devchar;
|
||||
bool has_model = TRUE;
|
||||
|
|
@ -2331,8 +2334,11 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
gate = &dev->dev_terms[0];
|
||||
if (dev->dev_nterm >= 2)
|
||||
source = drain = &dev->dev_terms[1];
|
||||
|
||||
if (dev->dev_nterm >= 3)
|
||||
{
|
||||
drain = &dev->dev_terms[2];
|
||||
|
||||
/* If any terminal is marked with attribute "D" or "S" */
|
||||
/* (label "D$" or "S$" at poly-diffusion interface), */
|
||||
/* then force order of source and drain accordingly. */
|
||||
|
|
@ -2342,11 +2348,8 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
(dev->dev_terms[2].dterm_attrs &&
|
||||
!strcmp(dev->dev_terms[2].dterm_attrs, "S")))
|
||||
{
|
||||
swapDrainSource(dev, &source, &drain);
|
||||
swapped = True;
|
||||
swapDrainSource(dev);
|
||||
}
|
||||
else
|
||||
drain = &dev->dev_terms[2];
|
||||
}
|
||||
subnode = dev->dev_subsnode;
|
||||
|
||||
|
|
@ -2852,9 +2855,6 @@ spcdevVisit(dev, hc, scale, trans)
|
|||
}
|
||||
fprintf(esSpiceF, "\n");
|
||||
|
||||
/* If S/D parameters on a subcircuit were swapped, put them back */
|
||||
if (swapped) swapDrainSource(dev, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -4083,7 +4083,7 @@ update_w(resClass, w, n)
|
|||
{
|
||||
(nc->m_w.widths) = (float *)mallocMagic((unsigned)sizeof(float)
|
||||
* efNumResistClasses);
|
||||
for (i = 0; i < EFDevNumTypes; i++)
|
||||
for (i = 0; i < efNumResistClasses; i++)
|
||||
nc->m_w.widths[i] = 0.0;
|
||||
}
|
||||
nc->m_w.widths[resClass] += (float)w;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "extflat/EFint.h"
|
||||
#include "extract/extract.h"
|
||||
#include "extract/extractInt.h"
|
||||
#include "select/select.h"
|
||||
#include "utils/malloc.h"
|
||||
|
||||
/* Forward declarations */
|
||||
|
|
@ -505,7 +506,7 @@ antennacheckVisit(dev, hc, scale, trans, editUse)
|
|||
/* To do: Mark tiles so area count can be progressive */
|
||||
|
||||
DBTreeCopyConnect(&scx, &DBConnectTbl[t], 0,
|
||||
DBConnectTbl, &TiPlaneRect, FALSE, extPathUse);
|
||||
DBConnectTbl, &TiPlaneRect, SEL_NO_LABELS, extPathUse);
|
||||
|
||||
/* Search planes of tie types and accumulate all tiedown areas */
|
||||
gdas.accum = (dlong)0;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header$";
|
|||
#include "utils/malloc.h"
|
||||
#include "extflat/extflat.h"
|
||||
#include "extflat/EFint.h"
|
||||
#include "tiles/tile.h"
|
||||
#include "extract/extract.h" /* for device class list */
|
||||
|
||||
/*
|
||||
|
|
@ -183,6 +184,7 @@ efBuildNode(def, isSubsnode, nodeName, nodeCap, x, y, layerName, av, ac)
|
|||
newname = (EFNodeName *) mallocMagic((unsigned)(sizeof (EFNodeName)));
|
||||
newname->efnn_hier = EFStrToHN((HierName *) NULL, nodeName);
|
||||
newname->efnn_port = -1; /* No port assignment */
|
||||
newname->efnn_refc = 0; /* Only reference is self */
|
||||
newname->efnn_next = NULL;
|
||||
HashSetValue(he, (char *) newname);
|
||||
}
|
||||
|
|
@ -453,6 +455,8 @@ efBuildEquiv(def, nodeName1, nodeName2)
|
|||
nn1 = (EFNodeName *) HashGetValue(he1);
|
||||
nn2 = (EFNodeName *) HashGetValue(he2);
|
||||
|
||||
if (nn1 == nn2) return; /* These nodes already merged */
|
||||
|
||||
if (nn2 == (EFNodeName *) NULL)
|
||||
{
|
||||
/* Create nodeName1 if it doesn't exist */
|
||||
|
|
@ -481,11 +485,35 @@ efBuildEquiv(def, nodeName1, nodeName2)
|
|||
return; /* Repeated "equiv" statement */
|
||||
if (nn1->efnn_node != nn2->efnn_node)
|
||||
{
|
||||
struct efnode *node1 = nn1->efnn_node;
|
||||
struct efnode *node2 = nn2->efnn_node;
|
||||
HashSearch hs;
|
||||
|
||||
if (efWarn)
|
||||
efReadError("Merged nodes %s and %s\n", nodeName1, nodeName2);
|
||||
efNodeMerge(&nn1->efnn_node, &nn2->efnn_node);
|
||||
if (nn1->efnn_port > 0) nn2->efnn_port = nn1->efnn_port;
|
||||
else if (nn2->efnn_port > 0) nn1->efnn_port = nn2->efnn_port;
|
||||
|
||||
/* If a node has been merged away, make sure that its name */
|
||||
/* and all aliases point to the merged name's hash. */
|
||||
|
||||
if (nn1->efnn_node == NULL)
|
||||
{
|
||||
nn2->efnn_refc += nn1->efnn_refc + 1;
|
||||
HashStartSearch(&hs);
|
||||
while (he1 = HashNext(&def->def_nodes, &hs))
|
||||
if ((EFNodeName *)HashGetValue(he1) == nn1)
|
||||
HashSetValue(he1, (char *)nn2);
|
||||
}
|
||||
else if (nn2->efnn_node == NULL)
|
||||
{
|
||||
nn1->efnn_refc += nn2->efnn_refc + 1;
|
||||
HashStartSearch(&hs);
|
||||
while (he2 = HashNext(&def->def_nodes, &hs))
|
||||
if ((EFNodeName *)HashGetValue(he2) == nn2)
|
||||
HashSetValue(he2, (char *)nn1);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -1553,6 +1581,7 @@ efNodeAddName(node, he, hn)
|
|||
newnn->efnn_node = node;
|
||||
newnn->efnn_hier = hn;
|
||||
newnn->efnn_port = -1;
|
||||
newnn->efnn_refc = 0;
|
||||
HashSetValue(he, (char *) newnn);
|
||||
|
||||
/* If the node is a port of the top level cell, denoted by flag */
|
||||
|
|
@ -1861,7 +1890,15 @@ efFreeNodeTable(table)
|
|||
{
|
||||
for (hn = nn->efnn_hier; hn; hn = hn->hn_parent)
|
||||
(void) HashFind(&efFreeHashTable, (char *) hn);
|
||||
freeMagic((char *) nn);
|
||||
|
||||
/* Node equivalences made by "equiv" statements are handled */
|
||||
/* by reference count. Don't free the node structure until */
|
||||
/* all references have been seen. */
|
||||
|
||||
if (nn->efnn_refc > 0)
|
||||
nn->efnn_refc--;
|
||||
else
|
||||
freeMagic((char *) nn);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ EFFlatBuildOneLevel(def, flags)
|
|||
efFlatRootUse.use_def = efFlatRootDef;
|
||||
|
||||
/* Record all nodes down the hierarchy from here */
|
||||
flatnodeflags = FLATNODE_STDCELL; /* No FLATDNODE_DOWARN flag */
|
||||
flatnodeflags = 0; /* No FLATNODE_DOWARN */
|
||||
efFlatNodes(&efFlatContext, (ClientData)flatnodeflags);
|
||||
|
||||
/* Expand all subcells that contain connectivity information but */
|
||||
|
|
@ -219,10 +219,6 @@ EFFlatBuildOneLevel(def, flags)
|
|||
if ((usecount == 0) && (HashGetNumEntries(&efFlatRootUse.use_def->def_devs) == 0))
|
||||
efFlatRootUse.use_def->def_flags |= DEF_NODEVICES;
|
||||
|
||||
/* Record all local nodes */
|
||||
efAddNodes(&efFlatContext, FALSE);
|
||||
efAddConns(&efFlatContext, TRUE);
|
||||
|
||||
efFlatKills(&efFlatContext);
|
||||
if (!(flags & EF_NONAMEMERGE))
|
||||
efFlatGlob();
|
||||
|
|
@ -297,6 +293,9 @@ EFFlatDone()
|
|||
* Adds node names to the table of flattened node names efNodeHashTable.
|
||||
* May merge nodes from the list efNodeList as per the connection
|
||||
* list hc->hc_use->use_def->def_conns.
|
||||
*
|
||||
* Note:
|
||||
* stdcell = TRUE is only used when writing DEF files.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -441,12 +440,10 @@ efAddNodes(hc, stdcell)
|
|||
EFNode *node, *newnode;
|
||||
EFAttr *ap, *newap;
|
||||
HierName *hierName;
|
||||
float scale;
|
||||
int size, asize;
|
||||
HashEntry *he;
|
||||
bool is_subcircuit = (def->def_flags & DEF_SUBCIRCUIT) ? TRUE : FALSE;
|
||||
|
||||
scale = def->def_scale;
|
||||
size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (EFPerimArea);
|
||||
|
||||
for (node = (EFNode *) def->def_firstn.efnode_next;
|
||||
|
|
@ -465,10 +462,6 @@ efAddNodes(hc, stdcell)
|
|||
newap = (EFAttr *) mallocMagic((unsigned)(asize));
|
||||
(void) strcpy(newap->efa_text, ap->efa_text);
|
||||
GeoTransRect(&hc->hc_trans, &ap->efa_loc, &newap->efa_loc);
|
||||
newap->efa_loc.r_xbot = (int)((float)(newap->efa_loc.r_xbot) * scale);
|
||||
newap->efa_loc.r_xtop = (int)((float)(newap->efa_loc.r_xtop) * scale);
|
||||
newap->efa_loc.r_ybot = (int)((float)(newap->efa_loc.r_ybot) * scale);
|
||||
newap->efa_loc.r_ytop = (int)((float)(newap->efa_loc.r_ytop) * scale);
|
||||
|
||||
newap->efa_type = ap->efa_type;
|
||||
newap->efa_next = newnode->efnode_attrs;
|
||||
|
|
@ -491,13 +484,8 @@ efAddNodes(hc, stdcell)
|
|||
efNumResistClasses * sizeof (EFPerimArea));
|
||||
GeoTransRect(&hc->hc_trans, &node->efnode_loc, &newnode->efnode_loc);
|
||||
|
||||
/* Scale the result by "scale" --- hopefully we end up with an integer */
|
||||
/* We don't scale the transform because the scale may be non-integer */
|
||||
/* and the Transform type has integers only. */
|
||||
newnode->efnode_loc.r_xbot = (int)((float)(newnode->efnode_loc.r_xbot) * scale);
|
||||
newnode->efnode_loc.r_xtop = (int)((float)(newnode->efnode_loc.r_xtop) * scale);
|
||||
newnode->efnode_loc.r_ybot = (int)((float)(newnode->efnode_loc.r_ybot) * scale);
|
||||
newnode->efnode_loc.r_ytop = (int)((float)(newnode->efnode_loc.r_ytop) * scale);
|
||||
/* Add each name for this node to the hash table */
|
||||
newnode->efnode_name = (EFNodeName *) NULL;
|
||||
|
||||
/* Prepend to global node list */
|
||||
newnode->efnode_next = efNodeList.efnode_next;
|
||||
|
|
@ -505,9 +493,6 @@ efAddNodes(hc, stdcell)
|
|||
efNodeList.efnode_next->efnhdr_prev = (EFNodeHdr *) newnode;
|
||||
efNodeList.efnode_next = (EFNodeHdr *) newnode;
|
||||
|
||||
/* Add each name for this node to the hash table */
|
||||
newnode->efnode_name = (EFNodeName *) NULL;
|
||||
|
||||
for (nn = node->efnode_name; nn; nn = nn->efnn_next)
|
||||
{
|
||||
/*
|
||||
|
|
@ -546,6 +531,7 @@ efAddNodes(hc, stdcell)
|
|||
newname->efnn_node = newnode;
|
||||
newname->efnn_hier = hierName;
|
||||
newname->efnn_port = -1;
|
||||
newname->efnn_refc = 0;
|
||||
if (newnode->efnode_name)
|
||||
{
|
||||
newname->efnn_next = newnode->efnode_name->efnn_next;
|
||||
|
|
@ -557,6 +543,7 @@ efAddNodes(hc, stdcell)
|
|||
newnode->efnode_name = newname;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/utils.h"
|
||||
#include "extflat/extflat.h"
|
||||
#include "extflat/EFint.h"
|
||||
#include "tiles/tile.h"
|
||||
#include "extract/extract.h"
|
||||
|
||||
/* Root of the tree being flattened */
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ typedef struct efnn
|
|||
struct efnn *efnn_next; /* Next name for this node */
|
||||
HierName *efnn_hier; /* HierName for this node */
|
||||
int efnn_port; /* Port number for this node */
|
||||
unsigned char efnn_refc; /* #times referenced in hash */
|
||||
} EFNodeName;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -727,13 +727,17 @@ extOutputNodes(nodeList, outFile)
|
|||
fprintf(outFile, "\"\n");
|
||||
}
|
||||
|
||||
/* Output the alternate names for the node */
|
||||
/* Output the alternate names for the node. Avoid generating */
|
||||
/* unnecessary "equiv A A" entries for labels on disconnected */
|
||||
/* nets. */
|
||||
|
||||
for (ll = reg->nreg_labels; ll; ll = ll->ll_next)
|
||||
if (ll->ll_label->lab_text == text)
|
||||
{
|
||||
for (ll = ll->ll_next; ll; ll = ll->ll_next)
|
||||
if (extLabType(ll->ll_label->lab_text, LABTYPE_NAME))
|
||||
fprintf(outFile, "equiv \"%s\" \"%s\"\n",
|
||||
if (strcmp(text, ll->ll_label->lab_text))
|
||||
fprintf(outFile, "equiv \"%s\" \"%s\"\n",
|
||||
text, ll->ll_label->lab_text);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1817,26 +1821,8 @@ extOutputDevices(def, transList, outFile)
|
|||
extTransFindSubs(reg->treg_tile, t, tmask, def, &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;
|
||||
/* Device node is the global substrate. */
|
||||
node = glob_subsnode;
|
||||
}
|
||||
else if (node == NULL) {
|
||||
/* See if there is another matching device record */
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ ClientData extUnInit = (ClientData) CLIENTDEFAULT;
|
|||
int extOutputUsesFunc();
|
||||
FILE *extFileOpen();
|
||||
|
||||
void extCellFile();
|
||||
Plane* extCellFile();
|
||||
void extHeader();
|
||||
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ void extHeader();
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
Plane *
|
||||
ExtCell(def, outName, doLength)
|
||||
CellDef *def; /* Cell being extracted */
|
||||
char *outName; /* Name of output file; if NULL, derive from def name */
|
||||
|
|
@ -95,6 +95,7 @@ ExtCell(def, outName, doLength)
|
|||
{
|
||||
char *filename;
|
||||
FILE *f;
|
||||
Plane *savePlane;
|
||||
bool doLocal;
|
||||
|
||||
doLocal = (ExtOptions & EXT_DOLOCAL) ? TRUE : FALSE;
|
||||
|
|
@ -115,7 +116,7 @@ ExtCell(def, outName, doLength)
|
|||
}
|
||||
|
||||
extNumFatal = extNumWarnings = 0;
|
||||
extCellFile(def, f, doLength);
|
||||
savePlane = extCellFile(def, f, doLength);
|
||||
(void) fclose(f);
|
||||
|
||||
if (extNumFatal > 0 || extNumWarnings > 0)
|
||||
|
|
@ -129,6 +130,7 @@ ExtCell(def, outName, doLength)
|
|||
extNumWarnings, extNumWarnings != 1 ? "s" : "");
|
||||
TxPrintf("\n");
|
||||
}
|
||||
return savePlane;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -219,6 +221,137 @@ extFileOpen(def, file, mode, doLocal, prealfile)
|
|||
return (PaOpen(name, mode, ".ext", ".", ".", prealfile));
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* extPrepSubstrate ---
|
||||
*
|
||||
* Prepare a replacement plane for the plane representing the substrate, as
|
||||
* defined in ExtCurStyle->exts_globSubstratePlane. The target CellDef is
|
||||
* searched for types that shield (i.e., isolate) a section of the layout
|
||||
* from the global substrate. The tile type that represents the substrate
|
||||
* is painted into the isolated regions.
|
||||
*
|
||||
* The purpose of this method is to deal with the common methodology in
|
||||
* which the substrate is not represented by any tile type, because no mask
|
||||
* is defined for the substrate. Typically, an entire cell such as a digital
|
||||
* standard cell may be placed on the default substrate or in a deep nwell
|
||||
* region. It is therefore necessary to be able to detect what is underneath
|
||||
* a cell on the plane representing the substrate to determine if the area is
|
||||
* the default substrate or an isolated region. If an isolated region, it
|
||||
* must be painted with a tile type so that the extraction code can tag the
|
||||
* tiles with a Region and assign it a node. This code creates the substrate
|
||||
* paint in the isolated regions for the duration of the extration, then
|
||||
* reverts back to the original plane afterward.
|
||||
*
|
||||
* Results:
|
||||
* Returns a Plane structure that is the original substrate plane from
|
||||
* CellDef "def", with isolated substrate regions filled with the
|
||||
* substrate tile type. If there are no isolated substrate regions,
|
||||
* or if a substrate plane or substrate type is not defined by the
|
||||
* technology, then the routine returns NULL.
|
||||
*
|
||||
* Side effects:
|
||||
* All modifications are limited to the returned plane structure.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Plane *
|
||||
extPrepSubstrate(def)
|
||||
CellDef *def;
|
||||
{
|
||||
SearchContext scx;
|
||||
CellUse dummy;
|
||||
TileType subType;
|
||||
TileTypeBitMask subMask, notSubMask;
|
||||
Plane *subPlane, *savePlane;
|
||||
int pNum;
|
||||
|
||||
/* Determine if substrate copying is required. */
|
||||
|
||||
if (ExtCurStyle->exts_globSubstratePlane == -1) return NULL;
|
||||
|
||||
/* Find a type to use for the substrate, and the mask of all types */
|
||||
/* in the same plane as the substrate that are not connected to the */
|
||||
/* substrate. If there is not a simple type representing the substrate */
|
||||
/* then do not attempt to resolve substrate regions. */
|
||||
|
||||
TTMaskZero(&subMask);
|
||||
TTMaskSetMask(&subMask, &ExtCurStyle->exts_globSubstrateTypes);
|
||||
|
||||
for (subType = TT_TECHDEPBASE; subType < DBNumUserLayers; subType++)
|
||||
if (TTMaskHasType(&subMask, subType))
|
||||
if (DBPlane(subType) == ExtCurStyle->exts_globSubstratePlane)
|
||||
break;
|
||||
|
||||
TTMaskCom2(¬SubMask, &subMask);
|
||||
TTMaskAndMask(¬SubMask, &DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
|
||||
|
||||
if (subType == DBNumUserLayers) return NULL;
|
||||
|
||||
/* Generate the full flattened substrate into ha->ha_cumFlat (which */
|
||||
/* was empty initially). This adds layer geometry for the */
|
||||
/* substrate in the typical case where the substrate may be space */
|
||||
/* (implicitly defined substrate). */
|
||||
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
scx.scx_area = def->cd_bbox;
|
||||
scx.scx_use = &dummy;
|
||||
dummy.cu_def = def;
|
||||
dummy.cu_id = NULL;
|
||||
|
||||
subPlane = DBCellGenerateSubstrate(&scx, subType, ¬SubMask,
|
||||
&ExtCurStyle->exts_globSubstrateShieldTypes, def);
|
||||
if (subPlane != NULL)
|
||||
{
|
||||
pNum = ExtCurStyle->exts_globSubstratePlane;
|
||||
savePlane = def->cd_planes[pNum];
|
||||
def->cd_planes[pNum] = subPlane;
|
||||
return savePlane;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* ExtRevertSubstrate ---
|
||||
*
|
||||
* This routine swaps the substrate plane of CellDef "def" with the plane
|
||||
* structure provided in the argument "savePlane". It should be called at
|
||||
* the end of extraction. "savePlane" should be the pointer to the substrate
|
||||
* plane of "def" before it was swapped out for the modified plane created by
|
||||
* the routine "extPrepSubstrate", above. The calling routine is responsible
|
||||
* for knowing if extPrepSubstrate returned NULL in which case there is
|
||||
* nothing to revert.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Side effects:
|
||||
* The CellDef "def" has its substrate plane swapped out for "savePlane",
|
||||
* and the original substrate plane and its contents are freed.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
ExtRevertSubstrate(def, savePlane)
|
||||
CellDef *def;
|
||||
Plane *savePlane;
|
||||
{
|
||||
int pNum;
|
||||
Plane *subPlane;
|
||||
|
||||
pNum = ExtCurStyle->exts_globSubstratePlane;
|
||||
subPlane = def->cd_planes[pNum];
|
||||
def->cd_planes[pNum] = savePlane;
|
||||
DBFreePaintPlane(subPlane);
|
||||
TiFreePlane(subPlane);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -240,7 +373,7 @@ extFileOpen(def, file, mode, doLocal, prealfile)
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
Plane *
|
||||
extCellFile(def, f, doLength)
|
||||
CellDef *def; /* Def to be extracted */
|
||||
FILE *f; /* Output to this file */
|
||||
|
|
@ -250,9 +383,13 @@ extCellFile(def, f, doLength)
|
|||
*/
|
||||
{
|
||||
NodeRegion *reg;
|
||||
Plane *saveSub;
|
||||
|
||||
UndoDisable();
|
||||
|
||||
/* Prep any isolated substrate areas */
|
||||
saveSub = extPrepSubstrate(def);
|
||||
|
||||
/* Output the header: timestamp, technology, calls on cell uses */
|
||||
if (!SigInterruptPending) extHeader(def, f);
|
||||
|
||||
|
|
@ -274,6 +411,7 @@ extCellFile(def, f, doLength)
|
|||
extLength(extParentUse, f);
|
||||
|
||||
UndoEnable();
|
||||
return saveSub;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -897,6 +897,9 @@ extSideOverlap(tp, esws)
|
|||
subcap = (ExtCurStyle->exts_perimCap[ta][outtype] *
|
||||
MIN(areaAccountedFor, length));
|
||||
rbp->nreg_cap -= subcap;
|
||||
/* Ignore residual error at ~zero zeptoFarads. Probably */
|
||||
/* there should be better handling of round-off here. */
|
||||
if ((rbp->nreg_cap > -0.001) && (rbp->nreg_cap < 0.001)) rbp->nreg_cap = 0;
|
||||
if (CAP_DEBUG)
|
||||
extNregAdjustCap(rbp, -subcap, "obsolete_perimcap");
|
||||
} else if (CAP_DEBUG)
|
||||
|
|
|
|||
|
|
@ -484,7 +484,10 @@ extHardFreeAll(def, tReg)
|
|||
|
||||
/* Free all LabelLists and then the region */
|
||||
for (ll = reg->treg_labels; ll; ll = ll->ll_next)
|
||||
{
|
||||
if (ll->ll_label->lab_flags & LABEL_GENERATE) freeMagic(ll->ll_label);
|
||||
freeMagic((char *) ll);
|
||||
}
|
||||
freeMagic((char *) reg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,16 +60,34 @@ int extHierConnectFunc2();
|
|||
int extHierConnectFunc3();
|
||||
Node *extHierNewNode();
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* extHierSubShieldFunc -- */
|
||||
/* */
|
||||
/* Simple callback function for extHierSubstrate() that halts the */
|
||||
/* search if any substrate shield type is found in the search area */
|
||||
/* */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/*----------------------------------------------*/
|
||||
/* extHierSubstrate */
|
||||
/* */
|
||||
/* Find the substrate node of a child cell and */
|
||||
/* make a connection between parent and child */
|
||||
/* substrates. If either of the substrate */
|
||||
/* nodes is already in the hash table, then the */
|
||||
/* table will be updated as necessary. */
|
||||
/*----------------------------------------------*/
|
||||
int
|
||||
extHierSubShieldFunc(tile)
|
||||
Tile *tile;
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* extHierSubstrate -- */
|
||||
/* */
|
||||
/* Find the substrate node of a child cell and make a connection */
|
||||
/* between parent and child substrates. If either of the */
|
||||
/* substrate nodes is already in the hash table, then the table */
|
||||
/* will be updated as necessary. */
|
||||
/* */
|
||||
/* This function also determines if a child cell's substrate is */
|
||||
/* isolated by a substrate shield type, in which case no merge is */
|
||||
/* done. */
|
||||
/* */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void
|
||||
extHierSubstrate(ha, use, x, y)
|
||||
|
|
@ -84,6 +102,8 @@ extHierSubstrate(ha, use, x, y)
|
|||
Node *node1, *node2;
|
||||
char *name1, *name2, *childname;
|
||||
CellDef *def;
|
||||
Rect subArea;
|
||||
int pNum;
|
||||
|
||||
NodeRegion *extFindNodes();
|
||||
|
||||
|
|
@ -107,6 +127,49 @@ extHierSubstrate(ha, use, x, y)
|
|||
|
||||
/* Find the child's substrate node */
|
||||
nodeList = extFindNodes(use->cu_def, (Rect *) NULL, TRUE);
|
||||
if (nodeList == NULL)
|
||||
{
|
||||
ExtResetTiles(use->cu_def, extUnInit);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the child's substrate node is covered by any substrate */
|
||||
/* shield type (e.g., deep nwell). This is a stupid-simple check */
|
||||
/* on the node's lower left point. This will fail if (1) only */
|
||||
/* space exists on the substrate plane in the child cell, or (2) if */
|
||||
/* some but not all devices in the child are covered by a shield */
|
||||
/* type. Item (1) is handled by checking if the region point is */
|
||||
/* outside the cell bound and using the cell bound as the search */
|
||||
/* area if so. However, it really should look for a device in the */
|
||||
/* subcell that connects to the substrate. Item (2) is up to the */
|
||||
/* designer to avoid (but should be flagged as an extraction */
|
||||
/* error). */
|
||||
|
||||
if (GEO_ENCLOSE(&nodeList->nreg_ll, &use->cu_def->cd_bbox))
|
||||
{
|
||||
GeoTransPoint(&use->cu_transform, &nodeList->nreg_ll, &subArea.r_ll);
|
||||
subArea.r_ur.p_x = subArea.r_ll.p_x + 1;
|
||||
subArea.r_ur.p_y = subArea.r_ll.p_y + 1;
|
||||
}
|
||||
else
|
||||
subArea = ha->ha_subArea;
|
||||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
{
|
||||
if (TTMaskIntersect(&DBPlaneTypes[pNum],
|
||||
&ExtCurStyle->exts_globSubstrateShieldTypes))
|
||||
{
|
||||
if (DBSrPaintArea((Tile *) NULL,
|
||||
def->cd_planes[pNum], &subArea,
|
||||
&ExtCurStyle->exts_globSubstrateShieldTypes,
|
||||
extHierSubShieldFunc, (ClientData)NULL) != 0)
|
||||
{
|
||||
freeMagic(nodeList);
|
||||
ExtResetTiles(use->cu_def, extUnInit);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure substrate labels are represented */
|
||||
ExtLabelRegions(use->cu_def, ExtCurStyle->exts_nodeConn, &nodeList,
|
||||
|
|
@ -196,6 +259,8 @@ extHierConnections(ha, cumFlat, oneFlat)
|
|||
/* Look for sticky labels in the child cell that are not */
|
||||
/* connected to any geometry. */
|
||||
|
||||
if (!(ExtOptions & EXT_DOLABELCHECK)) return;
|
||||
|
||||
for (lab = sourceDef->cd_labels; lab; lab = lab->lab_next)
|
||||
{
|
||||
CellDef *cumDef = cumFlat->et_use->cu_def;
|
||||
|
|
@ -283,6 +348,8 @@ extHierConnectFunc1(oneTile, ha)
|
|||
/* This allows the extractor to catch "sticky" labels that are not */
|
||||
/* attached to a physical layer in the parent cell. */
|
||||
|
||||
if (!(ExtOptions & EXT_DOLABELCHECK)) return 0;
|
||||
|
||||
// NOTE by Tim, 9/10/2014: This generates phantom nodes when the
|
||||
// labels are created by the "hard" node search; I think this code
|
||||
// should be restricted to sticky labels only. But not certain.
|
||||
|
|
@ -330,31 +397,7 @@ extHierConnectFunc1(oneTile, ha)
|
|||
node1->node_names = node2->node_names;
|
||||
freeMagic((char *) node2);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Copy this label to the parent def with a */
|
||||
/* special flag, so we can output it as a node */
|
||||
/* and then delete it. Don't duplicate labels */
|
||||
/* that are already in the parent. */
|
||||
|
||||
for (newlab = ha->ha_parentUse->cu_def->cd_labels;
|
||||
newlab; newlab = newlab->lab_next)
|
||||
if (!strcmp(newlab->lab_text, lab->lab_text))
|
||||
break;
|
||||
|
||||
if (newlab == NULL)
|
||||
{
|
||||
n = sizeof(Label) + strlen(lab->lab_text)
|
||||
- sizeof lab->lab_text + 1;
|
||||
newlab = (Label *)mallocMagic((unsigned)n);
|
||||
bcopy((char *)lab, (char *)newlab, (int)n);
|
||||
|
||||
newlab->lab_next = ha->ha_parentUse->cu_def->cd_labels;
|
||||
ha->ha_parentUse->cu_def->cd_labels = newlab;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/signals.h"
|
||||
#include "windows/windows.h"
|
||||
#include "dbwind/dbwind.h"
|
||||
#include "select/select.h"
|
||||
#include "utils/styles.h"
|
||||
#include "utils/stack.h"
|
||||
#include "utils/main.h"
|
||||
|
|
@ -368,7 +369,7 @@ extLengthYank(use, labList)
|
|||
scx.scx_trans = GeoIdentityTransform;
|
||||
GEO_EXPAND(&lab->lab_rect, 1, &scx.scx_area);
|
||||
DBTreeCopyConnect(&scx, &DBConnectTbl[lab->lab_type], 0,
|
||||
DBConnectTbl, &TiPlaneRect, TRUE, extPathUse);
|
||||
DBConnectTbl, &TiPlaneRect, SEL_DO_LABELS, extPathUse);
|
||||
}
|
||||
|
||||
if (DebugIsSet(extDebugID, extDebLength))
|
||||
|
|
|
|||
|
|
@ -616,6 +616,16 @@ closeit:
|
|||
return (ret);
|
||||
}
|
||||
|
||||
/* Linked list structure to use to store the substrate plane from each */
|
||||
/* extracted CellDef so that they can be returned to the original after */
|
||||
/* extraction. */
|
||||
|
||||
struct saveList {
|
||||
Plane *sl_plane;
|
||||
CellDef *sl_def;
|
||||
struct saveList *sl_next;
|
||||
};
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -645,7 +655,9 @@ extExtractStack(stack, doExtract, rootDef)
|
|||
{
|
||||
int fatal = 0, warnings = 0;
|
||||
bool first = TRUE;
|
||||
Plane *savePlane;
|
||||
CellDef *def;
|
||||
struct saveList *newsl, *sl = (struct saveList *)NULL;
|
||||
|
||||
while (def = (CellDef *) StackPop(stack))
|
||||
{
|
||||
|
|
@ -654,7 +666,16 @@ extExtractStack(stack, doExtract, rootDef)
|
|||
{
|
||||
if (doExtract)
|
||||
{
|
||||
ExtCell(def, (char *) NULL, (def == rootDef));
|
||||
savePlane = ExtCell(def, (char *) NULL, (def == rootDef));
|
||||
if (savePlane != NULL)
|
||||
{
|
||||
newsl = (struct saveList *)mallocMagic(sizeof(struct saveList));
|
||||
newsl->sl_plane = savePlane;
|
||||
newsl->sl_def = def;
|
||||
newsl->sl_next = sl;
|
||||
sl = newsl;
|
||||
}
|
||||
|
||||
fatal += extNumFatal;
|
||||
warnings += extNumWarnings;
|
||||
}
|
||||
|
|
@ -668,6 +689,16 @@ extExtractStack(stack, doExtract, rootDef)
|
|||
}
|
||||
}
|
||||
|
||||
/* Replace any modified substrate planes */
|
||||
for (; sl; sl = sl->sl_next)
|
||||
{
|
||||
ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
|
||||
// DBFreePaintPlane(sl->sl_plane);
|
||||
// TiFreePlane(sl->sl_plane);
|
||||
|
||||
freeMagic(sl);
|
||||
}
|
||||
|
||||
if (!doExtract)
|
||||
{
|
||||
TxPrintf("\n");
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ ExtLabelRegions(def, connTo, nodeList, clipArea)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if ((found == FALSE) && (nodeList != NULL))
|
||||
if ((found == FALSE) && (nodeList != NULL) && (ExtOptions & EXT_DOLABELCHECK))
|
||||
{
|
||||
// Unconnected node label. This may be a "sticky label".
|
||||
// If it is not connected to TT_SPACE, then create a new
|
||||
|
|
|
|||
|
|
@ -429,14 +429,12 @@ extSubtreeInteraction(ha)
|
|||
NodeRegion *reg;
|
||||
SearchContext scx;
|
||||
|
||||
/* Copy parent paint into ha->ha_cumFlat (which was initially empty) */
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
scx.scx_area = ha->ha_interArea;
|
||||
scx.scx_use = ha->ha_parentUse;
|
||||
|
||||
/* Copy parent paint into ha->ha_cumFlat */
|
||||
DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, ha->ha_cumFlat.et_use);
|
||||
#ifdef notdef
|
||||
extCopyPaint(ha->ha_parentUse->cu_def, &ha->ha_interArea, cumDef);
|
||||
#endif /* notdef */
|
||||
|
||||
/*
|
||||
* First element on the subtree list will be parent mask info.
|
||||
|
|
@ -446,9 +444,6 @@ extSubtreeInteraction(ha)
|
|||
oneDef = oneFlat->et_use->cu_def;
|
||||
DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, oneFlat->et_use);
|
||||
|
||||
#ifdef notdef
|
||||
extCopyPaint(ha->ha_parentUse->cu_def, &ha->ha_interArea, oneDef);
|
||||
#endif /* notdef */
|
||||
oneFlat->et_nodes = extFindNodes(oneDef, &ha->ha_clipArea, FALSE);
|
||||
if ((ExtOptions & (EXT_DOCOUPLING|EXT_DOADJUST))
|
||||
== (EXT_DOCOUPLING|EXT_DOADJUST))
|
||||
|
|
@ -743,6 +738,7 @@ extSubtreeFunc(scx, ha)
|
|||
hy.hy_area = &ha->ha_subArea;
|
||||
hy.hy_target = oneFlat->et_use;
|
||||
hy.hy_prefix = TRUE;
|
||||
|
||||
(void) DBArraySr(use, &ha->ha_subArea, extHierYankFunc, (ClientData) &hy);
|
||||
|
||||
/*
|
||||
|
|
@ -767,6 +763,8 @@ extSubtreeFunc(scx, ha)
|
|||
*/
|
||||
if (extFirstPass)
|
||||
{
|
||||
extFirstPass = FALSE;
|
||||
|
||||
// On the first pass, run through et_lookName's label list.
|
||||
// Copy any sticky labels to cumUse->cu_def, so that the labels
|
||||
// can be found even when there is no geometry underneath in
|
||||
|
|
@ -796,7 +794,6 @@ extSubtreeFunc(scx, ha)
|
|||
cumUse->cu_def->cd_labels = newlab;
|
||||
}
|
||||
}
|
||||
extFirstPass = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -861,9 +858,6 @@ extSubtreeFunc(scx, ha)
|
|||
newscx.scx_area = ha->ha_subArea;
|
||||
newscx.scx_trans = GeoIdentityTransform;
|
||||
DBCellCopyPaint(&newscx, &DBAllButSpaceBits, 0, cumUse);
|
||||
#ifdef notdef
|
||||
extCopyPaint(oneFlat->et_use->cu_def, &ha->ha_subArea, cumUse->cu_def);
|
||||
#endif /* notdef */
|
||||
extHierCopyLabels(oneFlat->et_use->cu_def, cumUse->cu_def);
|
||||
|
||||
/* Prepend this tree to the list of trees we've processed so far */
|
||||
|
|
@ -1216,7 +1210,6 @@ extSubtreeHardSearch(et, arg)
|
|||
HierExtractArg *ha = arg->hw_ha;
|
||||
ExtTree *oneFlat;
|
||||
|
||||
|
||||
arg->hw_proc = extHardProc;
|
||||
if (et == &ha->ha_cumFlat)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -148,6 +148,8 @@ ExtractTest(w, cmd)
|
|||
|
||||
if (cmd->tx_argc == 1)
|
||||
{
|
||||
Plane *savePlane;
|
||||
|
||||
selectedCell = CmdGetSelectedCell((Transform *) NULL);
|
||||
if (selectedCell == NULL)
|
||||
{
|
||||
|
|
@ -156,7 +158,8 @@ ExtractTest(w, cmd)
|
|||
}
|
||||
|
||||
extDispInit(selectedCell->cu_def, w);
|
||||
ExtCell(selectedCell->cu_def, selectedCell->cu_def->cd_name, FALSE);
|
||||
savePlane = ExtCell(selectedCell->cu_def, selectedCell->cu_def->cd_name, FALSE);
|
||||
ExtRevertSubstrate(selectedCell->cu_def, savePlane);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ extern char *extDevTable[];
|
|||
#define EXT_DOLENGTH 0x10 /* Extract pathlengths */
|
||||
#define EXT_DOALL 0x1f /* ALL OF THE ABOVE */
|
||||
#define EXT_DOLOCAL 0x20 /* Write to local directory only */
|
||||
#define EXT_DOLABELCHECK 0x40 /* Check for connections by label */
|
||||
|
||||
extern int ExtOptions; /* Bitmask of above */
|
||||
|
||||
|
|
@ -75,7 +76,8 @@ extern void ExtTechInit();
|
|||
extern void ExtTechFinal();
|
||||
extern void ExtSetStyle();
|
||||
extern void ExtPrintStyle();
|
||||
extern void ExtCell();
|
||||
extern void ExtRevertSubstrate();
|
||||
extern Plane *ExtCell();
|
||||
|
||||
extern int ExtGetGateTypesMask();
|
||||
extern int ExtGetDiffTypesMask();
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ int gaDebNoClean = 0;
|
|||
|
||||
/* Used in the "*garoute split" command */
|
||||
PlaneMask gaSplitPlaneMask;
|
||||
void (*gaSplitPaintPlane)();
|
||||
int (*gaSplitPaintPlane)();
|
||||
Rect gaSplitArea;
|
||||
int gaSplitType;
|
||||
|
||||
|
|
|
|||
|
|
@ -1546,24 +1546,20 @@ DefReadComponents(f, rootDef, sname, oscale, total)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Does use name contain brackets? If so, this can */
|
||||
/* interfere with magic's use of arrays. */
|
||||
/* NOTE: This has been commented out. I think */
|
||||
/* the only confusion is in ext2spice and can be */
|
||||
/* avoided by allowing any bracket notation in an */
|
||||
/* instance name other than that used by the .ext */
|
||||
/* file for dealing with arrays, which uses the */
|
||||
/* specific syntax [xlo:xsep:xhi][ylo:ysep:yhi] and */
|
||||
/* is easy enough to distinguish. */
|
||||
/* Magic prohibits slashes and commas in use names */
|
||||
/* when using the "identify" command. Removing these */
|
||||
/* restrictions (at least the slash) is quite complex, */
|
||||
/* but really should be taken care of, since no other */
|
||||
/* tools consider this an illegal use, that I'm aware */
|
||||
/* of. */
|
||||
|
||||
/*
|
||||
dptr = strchr(usename, '[');
|
||||
if (dptr != NULL) {
|
||||
for (dptr = usename; *dptr; dptr++)
|
||||
if ((*dptr == '/') || (*dptr == ','))
|
||||
{
|
||||
LefError(DEF_WARNING, "Character in instance name "
|
||||
"converted to underscore.\n");
|
||||
*dptr = '_';
|
||||
dptr = strchr(dptr + 1, ']');
|
||||
if (dptr != NULL) *dptr = '_';
|
||||
}
|
||||
*/
|
||||
|
||||
token = LefNextToken(f, TRUE);
|
||||
|
||||
|
|
|
|||
40
lef/lefCmd.c
40
lef/lefCmd.c
|
|
@ -92,6 +92,11 @@ CmdLef(w, cmd)
|
|||
* other than pin area surrounding labels,
|
||||
* with the indicated setback distance.
|
||||
*/
|
||||
int lefPinOnly = -1; /* If >= 0, make pins only where labels
|
||||
* are defined, not the whole net. Values
|
||||
* > 0 limit how far pins can extend into
|
||||
* the interior of the cell.
|
||||
*/
|
||||
bool lefTopLayer = FALSE; /* If TRUE, only output the topmost
|
||||
* layer used by a pin, and make
|
||||
* all layers below it obstructions.
|
||||
|
|
@ -234,6 +239,17 @@ CmdLef(w, cmd)
|
|||
i++;
|
||||
}
|
||||
}
|
||||
else if (!strncmp(cmd->tx_argv[i], "-pinonly", 8))
|
||||
{
|
||||
lefPinOnly = 0;
|
||||
if ((i < (cmd->tx_argc - 1)) &&
|
||||
StrIsNumeric(cmd->tx_argv[i + 1]))
|
||||
{
|
||||
lefPinOnly = cmdParseCoord(w, cmd->tx_argv[i + 1],
|
||||
FALSE, TRUE);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9))
|
||||
lefTopLayer = TRUE;
|
||||
else if (!strncmp(cmd->tx_argv[i], "-nomaster", 9))
|
||||
|
|
@ -244,8 +260,8 @@ CmdLef(w, cmd)
|
|||
}
|
||||
else goto wrongNumArgs;
|
||||
}
|
||||
LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, lefTopLayer,
|
||||
lefDoMaster, recurse);
|
||||
LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, lefPinOnly,
|
||||
lefTopLayer, lefDoMaster, recurse);
|
||||
}
|
||||
break;
|
||||
case LEF_WRITE:
|
||||
|
|
@ -286,6 +302,23 @@ CmdLef(w, cmd)
|
|||
else
|
||||
TxPrintf("The \"-hide\" option is only for lef write\n");
|
||||
}
|
||||
else if (!strncmp(cmd->tx_argv[i], "-pinonly", 8))
|
||||
{
|
||||
if (is_lef)
|
||||
{
|
||||
lefPinOnly = 0;
|
||||
if ((i < (cmd->tx_argc - 1)) &&
|
||||
StrIsNumeric(cmd->tx_argv[i + 1]))
|
||||
{
|
||||
lefPinOnly = cmdParseCoord(w, cmd->tx_argv[i + 1],
|
||||
FALSE, TRUE);
|
||||
cargs--;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
TxPrintf("The \"-pinonly\" option is only for lef write\n");
|
||||
}
|
||||
else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9))
|
||||
{
|
||||
if (is_lef)
|
||||
|
|
@ -339,7 +372,8 @@ CmdLef(w, cmd)
|
|||
DefWriteCell(selectedUse->cu_def, namep, allSpecial, units);
|
||||
else
|
||||
LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def
|
||||
== EditRootDef, lefTech, lefHide, lefTopLayer, lefDoMaster);
|
||||
== EditRootDef, lefTech, lefHide, lefPinOnly,
|
||||
lefTopLayer, lefDoMaster);
|
||||
break;
|
||||
case LEF_HELP:
|
||||
wrongNumArgs:
|
||||
|
|
|
|||
|
|
@ -1095,11 +1095,12 @@ LefWritePinHeader(f, lab)
|
|||
*/
|
||||
|
||||
void
|
||||
lefWriteMacro(def, f, scale, setback, toplayer, domaster)
|
||||
lefWriteMacro(def, f, scale, setback, pinonly, toplayer, domaster)
|
||||
CellDef *def; /* Def for which to generate LEF output */
|
||||
FILE *f; /* Output to this file */
|
||||
float scale; /* Output distance units conversion factor */
|
||||
int setback; /* If >= 0, hide all detail except pins inside setback */
|
||||
int pinonly; /* If >= 0, only place pins where labels are defined */
|
||||
bool toplayer; /* If TRUE, only output topmost layer of pins */
|
||||
bool domaster; /* If TRUE, write masterslice layers */
|
||||
{
|
||||
|
|
@ -1421,8 +1422,19 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster)
|
|||
Rect carea;
|
||||
labelLinkedList *newlll;
|
||||
|
||||
SelectChunk(&scx, lab->lab_type, 0, &carea, FALSE);
|
||||
if (GEO_RECTNULL(&carea)) carea = labr;
|
||||
if (pinonly == 0)
|
||||
carea = labr;
|
||||
else
|
||||
{
|
||||
SelectChunk(&scx, lab->lab_type, 0, &carea, FALSE);
|
||||
if (GEO_RECTNULL(&carea)) carea = labr;
|
||||
else if (pinonly > 0)
|
||||
{
|
||||
Rect psetback;
|
||||
GEO_EXPAND(&boundary, -pinonly, &psetback);
|
||||
SelRemoveArea(&psetback, &DBAllButSpaceAndDRCBits);
|
||||
}
|
||||
}
|
||||
|
||||
/* Note that a sticky label could be placed over multiple */
|
||||
/* tile types, which would cause SelectChunk to fail. So */
|
||||
|
|
@ -1445,16 +1457,47 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster)
|
|||
Rect carea;
|
||||
|
||||
/* For -hide with setback, select the entire net and then */
|
||||
/* remove the part inside the setback area. Note that this */
|
||||
/* does not check if this causes the label to disappear. */
|
||||
/* remove the part inside the setback area. */
|
||||
|
||||
SelectNet(&scx, lab->lab_type, 0, NULL, FALSE);
|
||||
GEO_EXPAND(&boundary, -setback, &carea);
|
||||
SelRemoveArea(&carea, &DBAllButSpaceAndDRCBits);
|
||||
|
||||
/* Apply any additional setback from the "-pinonly" option */
|
||||
if (pinonly > setback)
|
||||
{
|
||||
Rect psetback;
|
||||
GEO_EXPAND(&boundary, -pinonly, &psetback);
|
||||
SelRemoveArea(&psetback, &DBAllButSpaceAndDRCBits);
|
||||
}
|
||||
|
||||
/* Paint over the label area so that labels do not simply */
|
||||
/* disappear by being inside the setback area. */
|
||||
|
||||
pNum = DBPlane(lab->lab_type);
|
||||
DBPaintPlane(SelectDef->cd_planes[pNum], &labr,
|
||||
DBStdPaintTbl(lab->lab_type, pNum), (PaintUndoInfo *) NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectNet(&scx, lab->lab_type, 0, NULL, FALSE);
|
||||
|
||||
/* Apply any pin setback */
|
||||
if (pinonly >= 0)
|
||||
{
|
||||
Rect psetback;
|
||||
GEO_EXPAND(&boundary, -pinonly, &psetback);
|
||||
SelRemoveArea(&psetback, &DBAllButSpaceAndDRCBits);
|
||||
|
||||
/* Paint over the label area so that labels do not simply */
|
||||
/* disappear by being inside the setback area. */
|
||||
|
||||
pNum = DBPlane(lab->lab_type);
|
||||
DBPaintPlane(SelectDef->cd_planes[pNum], &labr,
|
||||
DBStdPaintTbl(lab->lab_type, pNum), (PaintUndoInfo *) NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// Search for gate and diff types and accumulate antenna
|
||||
// areas. For gates, check for all gate types tied to
|
||||
// devices with MOSFET types (including "msubcircuit", etc.).
|
||||
|
|
@ -1964,11 +2007,13 @@ lefGetProperties(stackItem, i, clientData)
|
|||
*/
|
||||
|
||||
void
|
||||
LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, lefDoMaster, recurse)
|
||||
LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefPinOnly, lefTopLayer,
|
||||
lefDoMaster, recurse)
|
||||
CellUse *rootUse;
|
||||
bool writeTopCell;
|
||||
bool lefTech;
|
||||
int lefHide;
|
||||
int lefPinOnly;
|
||||
bool lefTopLayer;
|
||||
bool lefDoMaster;
|
||||
bool recurse;
|
||||
|
|
@ -2040,7 +2085,7 @@ LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, lefDoMaster, r
|
|||
{
|
||||
def->cd_client = (ClientData) 0;
|
||||
if (!SigInterruptPending)
|
||||
lefWriteMacro(def, f, scale, lefHide, lefTopLayer, lefDoMaster);
|
||||
lefWriteMacro(def, f, scale, lefHide, lefPinOnly, lefTopLayer, lefDoMaster);
|
||||
}
|
||||
|
||||
/* End the LEF file */
|
||||
|
|
@ -2104,12 +2149,14 @@ lefDefPushFunc(use, recurse)
|
|||
*/
|
||||
|
||||
void
|
||||
LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefTopLayer, lefDoMaster)
|
||||
LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefPinOnly, lefTopLayer,
|
||||
lefDoMaster)
|
||||
CellDef *def; /* Cell being written */
|
||||
char *outName; /* Name of output file, or NULL. */
|
||||
bool isRoot; /* Is this the root cell? */
|
||||
bool lefTech; /* Output layer information if TRUE */
|
||||
int lefHide; /* Hide detail other than pins if >= 0 */
|
||||
int lefPinOnly; /* Only generate pins on label areas */
|
||||
bool lefTopLayer; /* Use only topmost layer of pin if TRUE */
|
||||
bool lefDoMaster; /* Write masterslice layers if TRUE */
|
||||
{
|
||||
|
|
@ -2145,7 +2192,7 @@ LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefTopLayer, lefDoMaster)
|
|||
HashKill(&propHashTbl);
|
||||
HashKill(&siteHashTbl);
|
||||
}
|
||||
lefWriteMacro(def, f, scale, lefHide, lefTopLayer, lefDoMaster);
|
||||
lefWriteMacro(def, f, scale, lefHide, lefPinOnly, lefTopLayer, lefDoMaster);
|
||||
|
||||
/* End the LEF file */
|
||||
fprintf(f, "END LIBRARY\n\n");
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/styles.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/main.h"
|
||||
#include "select/select.h"
|
||||
#include "netmenu/nmInt.h"
|
||||
|
||||
/* The following owns describe the cell currently being highlighted,
|
||||
|
|
@ -294,7 +295,7 @@ NMShowUnderBox()
|
|||
&DBAllButSpaceBits);
|
||||
DBCellClearDef(nmscShowUse->cu_def);
|
||||
DBTreeCopyConnect(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||
DBConnectTbl, &TiPlaneRect, TRUE, nmscShowUse);
|
||||
DBConnectTbl, &TiPlaneRect, SEL_DO_LABELS, nmscShowUse);
|
||||
DBWAreaChanged(nmscShowDef, &nmscShowDef->cd_bbox, DBW_ALLWINDOWS,
|
||||
&DBAllButSpaceBits);
|
||||
NMShowCell(nmscShowUse, rootDef);
|
||||
|
|
@ -418,6 +419,6 @@ nmSRNFunc(rect, name, label, cdarg)
|
|||
scx.scx_trans = GeoIdentityTransform;
|
||||
|
||||
DBTreeCopyConnect(&scx, &DBConnectTbl[label->lab_type], 0,
|
||||
DBConnectTbl, &TiPlaneRect, TRUE, nmscShowUse);
|
||||
DBConnectTbl, &TiPlaneRect, SEL_DO_LABELS, nmscShowUse);
|
||||
return(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -538,7 +538,8 @@ PlotSetParam(name, value)
|
|||
{
|
||||
int j;
|
||||
|
||||
TxError("%s is not a supported plot type. Plot types are:\n");
|
||||
TxError("%s is not a supported plot type. Plot types are:\n",
|
||||
value);
|
||||
for (j = 0 ; plotTypeNames[j] != NULL; j++)
|
||||
{
|
||||
TxError("\t%s\n", plotTypeNames[j]);
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ PlowRandomTest(def)
|
|||
static char *dirnames[] = { "up", "down", "right", "left" };
|
||||
Rect plowRect;
|
||||
int dir, plowDir;
|
||||
Plane *savePlane;
|
||||
|
||||
#ifdef notdef
|
||||
strcpy(goodName, tempgood);
|
||||
|
|
@ -101,7 +102,8 @@ PlowRandomTest(def)
|
|||
sprintf(tempExt, "%s.ext", tempName);
|
||||
|
||||
/* Generate "good" extracted file */
|
||||
ExtCell(def, goodName, FALSE);
|
||||
savePlane = ExtCell(def, goodName, FALSE);
|
||||
ExtRevertSubstrate(def, savePlane);
|
||||
(void) sprintf(command, "sedplow %s", goodExt);
|
||||
system(command);
|
||||
#endif /* notdef */
|
||||
|
|
@ -136,7 +138,8 @@ PlowRandomTest(def)
|
|||
|
||||
#ifdef notdef
|
||||
/* Extract to the temp file */
|
||||
ExtCell(def, tempName, FALSE);
|
||||
savePlane = ExtCell(def, tempName, FALSE);
|
||||
ExtRevertSubstrate(def, savePlane);
|
||||
(void) sprintf(command, "sedplow %s", tempExt);
|
||||
system(command);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/geofast.h"
|
||||
#include "tiles/tile.h"
|
||||
#include "utils/hash.h"
|
||||
#include "utils/stack.h"
|
||||
#include "database/database.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "textio/textio.h"
|
||||
|
|
@ -29,30 +30,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "textio/txcommands.h"
|
||||
#include "resis/resis.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Rect area; /* Area to process */
|
||||
TileTypeBitMask *connectMask; /* Connection mask for search */
|
||||
TileType dinfo; /* Info about triangular search areas */
|
||||
} conSrArea;
|
||||
|
||||
struct conSrArg2
|
||||
{
|
||||
CellUse *csa2_use; /* Destination use */
|
||||
TileTypeBitMask *csa2_connect; /* Table indicating what connects
|
||||
* to what.
|
||||
*/
|
||||
SearchContext *csa2_topscx; /* Original top-level search context */
|
||||
int csa2_xMask; /* Cell window mask for search */
|
||||
Rect *csa2_bounds; /* Area that limits the search */
|
||||
|
||||
conSrArea *csa2_list; /* List of areas to process */
|
||||
int csa2_top; /* Index of next area to process */
|
||||
int csa2_size; /* Max. number bins in area list */
|
||||
};
|
||||
|
||||
#define CSA2_LIST_START_SIZE 256
|
||||
|
||||
extern int dbcUnconnectFunc();
|
||||
extern int dbcConnectLabelFunc();
|
||||
extern int dbcConnectFuncDCS();
|
||||
|
|
@ -67,7 +44,6 @@ TileTypeBitMask ResSubsTypeBitMask;
|
|||
/* Forward declarations */
|
||||
extern void ResCalcPerimOverlap();
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -100,7 +76,7 @@ dbcConnectFuncDCS(tile, cx)
|
|||
TileType dinfo = 0;
|
||||
SearchContext *scx = cx->tc_scx;
|
||||
SearchContext scx2;
|
||||
int pNum;
|
||||
int i, pNum;
|
||||
CellDef *def;
|
||||
ExtDevice *devptr;
|
||||
TerminalPath tpath;
|
||||
|
|
@ -296,29 +272,29 @@ dbcConnectFuncDCS(tile, cx)
|
|||
newarea.r_ytop += 1;
|
||||
}
|
||||
|
||||
/* Check if any of the last 5 entries has the same type and */
|
||||
/* area. If so, don't duplicate the existing entry. */
|
||||
/* (NOTE: Connect masks are all from the same table, so */
|
||||
/* they can be compared by address, no need for TTMaskEqual)*/
|
||||
|
||||
for (i = csa2->csa2_lasttop; (i >= 0) && (i > csa2->csa2_lasttop - 5); i--)
|
||||
if (connectMask == csa2->csa2_list[i].connectMask)
|
||||
if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea))
|
||||
return 0;
|
||||
|
||||
/* Register the area and connection mask as needing to be processed */
|
||||
|
||||
if (++csa2->csa2_top == csa2->csa2_size)
|
||||
if (++csa2->csa2_top == CSA2_LIST_SIZE)
|
||||
{
|
||||
/* Reached list size limit---need to enlarge the list */
|
||||
/* Double the size of the list every time we hit the limit */
|
||||
|
||||
conSrArea *newlist;
|
||||
int i, lastsize = csa2->csa2_size;
|
||||
|
||||
csa2->csa2_size *= 2;
|
||||
|
||||
newlist = (conSrArea *)mallocMagic(csa2->csa2_size * sizeof(conSrArea));
|
||||
memcpy((void *)newlist, (void *)csa2->csa2_list,
|
||||
(size_t)lastsize * sizeof(conSrArea));
|
||||
// for (i = 0; i < lastsize; i++)
|
||||
// {
|
||||
// newlist[i].area = csa2->csa2_list[i].area;
|
||||
// newlist[i].connectMask = csa2->csa2_list[i].connectMask;
|
||||
// newlist[i].dinfo = csa2->csa2_list[i].dinfo;
|
||||
// }
|
||||
freeMagic((char *)csa2->csa2_list);
|
||||
newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
|
||||
StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
|
||||
csa2->csa2_list = newlist;
|
||||
csa2->csa2_top = 0;
|
||||
}
|
||||
|
||||
csa2->csa2_list[csa2->csa2_top].area = newarea;
|
||||
|
|
@ -443,10 +419,11 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse)
|
|||
csa2.csa2_connect = connect;
|
||||
csa2.csa2_topscx = scx;
|
||||
|
||||
csa2.csa2_size = CSA2_LIST_START_SIZE;
|
||||
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_START_SIZE
|
||||
* sizeof(conSrArea));
|
||||
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
|
||||
csa2.csa2_top = -1;
|
||||
csa2.csa2_lasttop = -1;
|
||||
|
||||
csa2.csa2_stack = StackNew(100);
|
||||
|
||||
if (first)
|
||||
{
|
||||
|
|
@ -474,7 +451,22 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse)
|
|||
newmask = csa2.csa2_list[csa2.csa2_top].connectMask;
|
||||
scx->scx_area = csa2.csa2_list[csa2.csa2_top].area;
|
||||
newtype = csa2.csa2_list[csa2.csa2_top].dinfo;
|
||||
csa2.csa2_top--;
|
||||
if (csa2.csa2_top == 0)
|
||||
{
|
||||
if (StackLook(csa2.csa2_stack) != (ClientData)NULL)
|
||||
{
|
||||
freeMagic(csa2.csa2_list);
|
||||
csa2.csa2_list = (conSrArea *)StackPop(csa2.csa2_stack);
|
||||
csa2.csa2_top = CSA2_LIST_SIZE - 1;
|
||||
}
|
||||
else
|
||||
csa2.csa2_top--;
|
||||
}
|
||||
else
|
||||
csa2.csa2_top--;
|
||||
|
||||
csa2.csa2_lasttop = csa2.csa2_top;
|
||||
|
||||
if (newtype & TT_DIAGONAL)
|
||||
DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFuncDCS,
|
||||
(ClientData) &csa2);
|
||||
|
|
@ -482,6 +474,7 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse)
|
|||
DBTreeSrTiles(scx, newmask, xMask, dbcConnectFuncDCS, (ClientData) &csa2);
|
||||
}
|
||||
freeMagic((char *)csa2.csa2_list);
|
||||
StackFree(csa2.csa2_stack);
|
||||
|
||||
for (CurrentT = DevList; CurrentT != NULL; CurrentT=CurrentT->nextDev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,10 +37,10 @@ resNode *ResNodeQueue=NULL; /* Pending nodes */
|
|||
resNode *ResOriginNode=NULL; /* node where R=0 */
|
||||
resNode *resCurrentNode;
|
||||
int ResTileCount=0; /* Number of tiles rn_status */
|
||||
extern Region *ResFirst();
|
||||
extern Region *ResFirst();
|
||||
extern Tile *FindStartTile();
|
||||
extern int ResEachTile();
|
||||
extern int ResLaplaceTile();
|
||||
extern int ResEachTile();
|
||||
extern int ResLaplaceTile();
|
||||
extern ResSimNode *ResInitializeNode();
|
||||
|
||||
extern HashTable ResNodeTable;
|
||||
|
|
@ -217,6 +217,18 @@ ResMakePortBreakpoints(def)
|
|||
plane = def->cd_planes[DBPlane(node->rs_ttype)];
|
||||
rect = &(node->rs_bbox);
|
||||
|
||||
/* Beware of zero-area ports */
|
||||
if (rect->r_xbot == rect->r_xtop)
|
||||
{
|
||||
rect->r_xbot--;
|
||||
rect->r_xtop++;
|
||||
}
|
||||
if (rect->r_ybot == rect->r_ytop)
|
||||
{
|
||||
rect->r_ybot--;
|
||||
rect->r_ytop++;
|
||||
}
|
||||
|
||||
TTMaskSetOnlyType(&mask, node->rs_ttype);
|
||||
(void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask,
|
||||
ResAddBreakpointFunc, (ClientData)node);
|
||||
|
|
@ -561,19 +573,18 @@ ResProcessTiles(goodies, origin)
|
|||
*
|
||||
* Side effects: Produces a resistance network for the node.
|
||||
*
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bool
|
||||
ResExtractNet(startlist,goodies,cellname)
|
||||
ResExtractNet(startlist, goodies, cellname)
|
||||
ResFixPoint *startlist;
|
||||
ResGlobalParams *goodies;
|
||||
char *cellname;
|
||||
{
|
||||
SearchContext scx;
|
||||
int pNum;
|
||||
ResDevTile *DevTiles,*lasttile;
|
||||
ResDevTile *DevTiles, *lasttile;
|
||||
TileTypeBitMask FirstTileMask;
|
||||
Point startpoint;
|
||||
ResFixPoint *fix;
|
||||
|
|
@ -581,10 +592,10 @@ ResExtractNet(startlist,goodies,cellname)
|
|||
|
||||
/* Make sure all global network variables are reset */
|
||||
|
||||
ResResList=NULL;
|
||||
ResNodeList=NULL;
|
||||
ResDevList=NULL;
|
||||
ResNodeQueue=NULL;
|
||||
ResResList = NULL;
|
||||
ResNodeList = NULL;
|
||||
ResDevList = NULL;
|
||||
ResNodeQueue = NULL;
|
||||
ResContactList = NULL;
|
||||
ResOriginNode = NULL;
|
||||
|
||||
|
|
@ -630,17 +641,16 @@ ResExtractNet(startlist,goodies,cellname)
|
|||
|
||||
DBCellClearDef(ResUse->cu_def);
|
||||
|
||||
|
||||
/* Copy Paint */
|
||||
/* Copy Paint */
|
||||
DevTiles = NULL;
|
||||
lasttile = NULL;
|
||||
for (fix = startlist; fix != NULL;fix=fix->fp_next)
|
||||
for (fix = startlist; fix != NULL; fix = fix->fp_next)
|
||||
{
|
||||
ResDevTile *newdevtiles,*tmp;
|
||||
ResDevTile *newdevtiles, *tmp;
|
||||
|
||||
#ifdef ARIEL
|
||||
if ((ResOptionsFlags & ResOpt_Power) &&
|
||||
strcmp(fix->fp_name,goodies->rg_name) != 0) continue;
|
||||
strcmp(fix->fp_name, goodies->rg_name) != 0) continue;
|
||||
#endif
|
||||
|
||||
scx.scx_area.r_ll.p_x = fix->fp_loc.p_x-2;
|
||||
|
|
@ -649,10 +659,10 @@ ResExtractNet(startlist,goodies,cellname)
|
|||
scx.scx_area.r_ur.p_y = fix->fp_loc.p_y+2;
|
||||
startpoint = fix->fp_loc;
|
||||
|
||||
// Because fix->fp_ttype might come from a label with a sticky type
|
||||
// that does not correspond exactly to the layer underneath, include
|
||||
// all connecting types.
|
||||
/* TTMaskSetOnlyType(&FirstTileMask,fix->fp_ttype); */
|
||||
/* Because fix->fp_ttype might come from a label with a sticky type
|
||||
* that does not correspond exactly to the layer underneath, include
|
||||
* all connecting types.
|
||||
*/
|
||||
TTMaskSetMask(&FirstTileMask, &DBConnectTbl[fix->fp_ttype]);
|
||||
|
||||
newdevtiles = DBTreeCopyConnectDCS(&scx, &FirstTileMask, 0,
|
||||
|
|
@ -662,13 +672,9 @@ ResExtractNet(startlist,goodies,cellname)
|
|||
if (newdevtiles)
|
||||
{
|
||||
if (DevTiles)
|
||||
{
|
||||
lasttile->nextDev = newdevtiles;
|
||||
}
|
||||
else
|
||||
{
|
||||
DevTiles = newdevtiles;
|
||||
}
|
||||
lasttile = tmp;
|
||||
}
|
||||
}
|
||||
|
|
@ -682,7 +688,7 @@ ResExtractNet(startlist,goodies,cellname)
|
|||
&DBAllButSpaceAndDRCBits,
|
||||
ResConnectWithSD, extUnInit, ResFirst,
|
||||
ResEach);
|
||||
ExtResetTiles(ResUse->cu_def,extUnInit);
|
||||
ExtResetTiles(ResUse->cu_def, extUnInit);
|
||||
|
||||
/*
|
||||
* dissolve the contacts and find which tiles now cover the point
|
||||
|
|
@ -697,7 +703,7 @@ ResExtractNet(startlist,goodies,cellname)
|
|||
{
|
||||
Plane *plane = ResUse->cu_def->cd_planes[pNum];
|
||||
Rect *rect = &ResUse->cu_def->cd_bbox;
|
||||
ResFracture(plane,rect);
|
||||
ResFracture(plane, rect);
|
||||
(void) DBSrPaintClient((Tile *) NULL,plane,rect,
|
||||
&DBAllButSpaceAndDRCBits,
|
||||
(ClientData) CLIENTDEFAULT, ResAddPlumbing,
|
||||
|
|
|
|||
216
resis/ResPrint.c
216
resis/ResPrint.c
|
|
@ -48,52 +48,52 @@ extern ResSimNode *ResInitializeNode();
|
|||
*/
|
||||
|
||||
void
|
||||
ResPrintExtRes(outextfile,resistors,nodename)
|
||||
FILE *outextfile;
|
||||
resResistor *resistors;
|
||||
char *nodename;
|
||||
ResPrintExtRes(outextfile, resistors, nodename)
|
||||
FILE *outextfile;
|
||||
resResistor *resistors;
|
||||
char *nodename;
|
||||
|
||||
{
|
||||
int nodenum=0;
|
||||
char newname[MAXNAME];
|
||||
HashEntry *entry;
|
||||
ResSimNode *node,*ResInitializeNode();
|
||||
int nodenum=0;
|
||||
char newname[MAXNAME];
|
||||
HashEntry *entry;
|
||||
ResSimNode *node, *ResInitializeNode();
|
||||
|
||||
for (; resistors != NULL; resistors=resistors->rr_nextResistor)
|
||||
{
|
||||
/*
|
||||
These names shouldn't be null; they should either be set by
|
||||
the device name or by the node printing routine. This
|
||||
code is included in case the resistor network is printed
|
||||
before the nodes.
|
||||
*/
|
||||
if (resistors->rr_connection1->rn_name == NULL)
|
||||
{
|
||||
(void)sprintf(newname,"%s%s%d",nodename,".r",nodenum++);
|
||||
entry = HashFind(&ResNodeTable,newname);
|
||||
node = ResInitializeNode(entry);
|
||||
resistors->rr_connection1->rn_name = node->name;
|
||||
node->oldname = nodename;
|
||||
}
|
||||
if (resistors->rr_connection2->rn_name == NULL)
|
||||
{
|
||||
(void)sprintf(newname,"%s%s%d",nodename,".r",nodenum++);
|
||||
entry = HashFind(&ResNodeTable,newname);
|
||||
node = ResInitializeNode(entry);
|
||||
resistors->rr_connection2->rn_name = node->name;
|
||||
node->oldname = nodename;
|
||||
}
|
||||
if (ResOptionsFlags & ResOpt_DoExtFile)
|
||||
{
|
||||
fprintf(outextfile, "resist \"%s\" \"%s\" %g\n",
|
||||
for (; resistors != NULL; resistors = resistors->rr_nextResistor)
|
||||
{
|
||||
/*
|
||||
* These names shouldn't be null; they should either be set by
|
||||
* the device name or by the node printing routine. This
|
||||
* code is included in case the resistor network is printed
|
||||
* before the nodes.
|
||||
*/
|
||||
|
||||
if (resistors->rr_connection1->rn_name == NULL)
|
||||
{
|
||||
(void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++);
|
||||
entry = HashFind(&ResNodeTable, newname);
|
||||
node = ResInitializeNode(entry);
|
||||
resistors->rr_connection1->rn_name = node->name;
|
||||
node->oldname = nodename;
|
||||
}
|
||||
if (resistors->rr_connection2->rn_name == NULL)
|
||||
{
|
||||
(void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++);
|
||||
entry = HashFind(&ResNodeTable, newname);
|
||||
node = ResInitializeNode(entry);
|
||||
resistors->rr_connection2->rn_name = node->name;
|
||||
node->oldname = nodename;
|
||||
}
|
||||
if (ResOptionsFlags & ResOpt_DoExtFile)
|
||||
{
|
||||
fprintf(outextfile, "resist \"%s\" \"%s\" %g\n",
|
||||
resistors->rr_connection1->rn_name,
|
||||
resistors->rr_connection2->rn_name,
|
||||
resistors->rr_value / (float)ExtCurStyle->exts_resistScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -166,7 +166,10 @@ ResPrintExtDev(outextfile, devices)
|
|||
break;
|
||||
}
|
||||
|
||||
fprintf(outextfile, " \"%s\"", subsName);
|
||||
if (devices->subs != NULL)
|
||||
fprintf(outextfile, " \"%s\"", devices->subs->name);
|
||||
else
|
||||
fprintf(outextfile, " \"%s\"", subsName);
|
||||
|
||||
fprintf(outextfile, " \"%s\" %d %s \"%s\" %d %s \"%s\" %d %s\n",
|
||||
devices->gate->name,
|
||||
|
|
@ -202,65 +205,64 @@ ResPrintExtNode(outextfile, nodelist, nodename)
|
|||
FILE *outextfile;
|
||||
resNode *nodelist;
|
||||
char *nodename;
|
||||
|
||||
{
|
||||
int nodenum=0;
|
||||
char newname[MAXNAME],tmpname[MAXNAME],*cp;
|
||||
HashEntry *entry;
|
||||
ResSimNode *node,*ResInitializeNode();
|
||||
bool DoKillNode = TRUE;
|
||||
resNode *snode = nodelist;
|
||||
int nodenum = 0;
|
||||
char newname[MAXNAME], tmpname[MAXNAME], *cp;
|
||||
HashEntry *entry;
|
||||
ResSimNode *node, *ResInitializeNode();
|
||||
bool DoKillNode = TRUE;
|
||||
resNode *snode = nodelist;
|
||||
|
||||
/* If any of the subnode names match the original node name, then */
|
||||
/* we don't want to rip out that node with a "killnode" statement. */
|
||||
/* If any of the subnode names match the original node name, then */
|
||||
/* we don't want to rip out that node with a "killnode" statement. */
|
||||
|
||||
for (; nodelist != NULL; nodelist = nodelist->rn_more)
|
||||
for (; nodelist != NULL; nodelist = nodelist->rn_more)
|
||||
{
|
||||
if (nodelist->rn_name != NULL)
|
||||
if (!strcmp(nodelist->rn_name, nodename))
|
||||
{
|
||||
DoKillNode = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ResOptionsFlags & ResOpt_DoExtFile) && DoKillNode)
|
||||
{
|
||||
fprintf(outextfile,"killnode \"%s\"\n",nodename);
|
||||
}
|
||||
if ((ResOptionsFlags & ResOpt_DoExtFile) && DoKillNode)
|
||||
{
|
||||
fprintf(outextfile, "killnode \"%s\"\n", nodename);
|
||||
}
|
||||
|
||||
/* Create "rnode" entries for each subnode */
|
||||
/* Create "rnode" entries for each subnode */
|
||||
|
||||
for (; snode != NULL; snode = snode->rn_more)
|
||||
{
|
||||
if (snode->rn_name == NULL)
|
||||
{
|
||||
(void)sprintf(tmpname,"%s",nodename);
|
||||
for (; snode != NULL; snode = snode->rn_more)
|
||||
{
|
||||
if (snode->rn_name == NULL)
|
||||
{
|
||||
(void)sprintf(tmpname,"%s",nodename);
|
||||
|
||||
cp = tmpname + strlen(tmpname) - 1;
|
||||
if (*cp == '!' || *cp == '#') *cp = '\0';
|
||||
cp = tmpname + strlen(tmpname) - 1;
|
||||
if (*cp == '!' || *cp == '#') *cp = '\0';
|
||||
|
||||
(void)sprintf(newname,"%s%s%d",tmpname,".n",nodenum++);
|
||||
entry = HashFind(&ResNodeTable,newname);
|
||||
node = ResInitializeNode(entry);
|
||||
snode->rn_name = node->name;
|
||||
node->oldname = nodename;
|
||||
}
|
||||
(void)sprintf(newname, "%s%s%d", tmpname, ".n", nodenum++);
|
||||
entry = HashFind(&ResNodeTable, newname);
|
||||
node = ResInitializeNode(entry);
|
||||
snode->rn_name = node->name;
|
||||
node->oldname = nodename;
|
||||
}
|
||||
|
||||
if (ResOptionsFlags & ResOpt_DoExtFile)
|
||||
{
|
||||
/* rnode name R C x y type (R is always 0) */
|
||||
fprintf(outextfile, "rnode \"%s\" 0 %g %d %d %d\n",
|
||||
if (ResOptionsFlags & ResOpt_DoExtFile)
|
||||
{
|
||||
/* rnode name R C x y type (R is always 0) */
|
||||
fprintf(outextfile, "rnode \"%s\" 0 %g %d %d %d\n",
|
||||
snode->rn_name,
|
||||
(snode->rn_float.rn_area/
|
||||
ExtCurStyle->exts_capScale),
|
||||
(snode->rn_float.rn_area / ExtCurStyle->exts_capScale),
|
||||
snode->rn_loc.p_x,
|
||||
snode->rn_loc.p_y,
|
||||
/* the following is TEMPORARILY set to 0 */
|
||||
0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -276,39 +278,39 @@ ResPrintExtNode(outextfile, nodelist, nodename)
|
|||
*/
|
||||
|
||||
void
|
||||
ResPrintStats(goodies,name)
|
||||
ResGlobalParams *goodies;
|
||||
char *name;
|
||||
ResPrintStats(goodies, name)
|
||||
ResGlobalParams *goodies;
|
||||
char *name;
|
||||
{
|
||||
static int totalnets=0,totalnodes=0,totalresistors=0;
|
||||
int nodes,resistors;
|
||||
resNode *node;
|
||||
resResistor *res;
|
||||
static int totalnets = 0, totalnodes = 0, totalresistors = 0;
|
||||
int nodes, resistors;
|
||||
resNode *node;
|
||||
resResistor *res;
|
||||
|
||||
if (goodies == NULL)
|
||||
{
|
||||
if (goodies == NULL)
|
||||
{
|
||||
TxError("nets:%d nodes:%d resistors:%d\n",
|
||||
totalnets,totalnodes,totalresistors);
|
||||
totalnets=0;
|
||||
totalnodes=0;
|
||||
totalresistors=0;
|
||||
return;
|
||||
}
|
||||
nodes=0;
|
||||
resistors=0;
|
||||
totalnets++;
|
||||
for (node = ResNodeList; node != NULL; node=node->rn_more)
|
||||
totalnets, totalnodes, totalresistors);
|
||||
totalnets = 0;
|
||||
totalnodes = 0;
|
||||
totalresistors = 0;
|
||||
return;
|
||||
}
|
||||
nodes = 0;
|
||||
resistors = 0;
|
||||
totalnets++;
|
||||
for (node = ResNodeList; node != NULL; node=node->rn_more)
|
||||
|
||||
{
|
||||
nodes++;
|
||||
totalnodes++;
|
||||
}
|
||||
for (res = ResResList; res != NULL; res=res->rr_nextResistor)
|
||||
{
|
||||
resistors++;
|
||||
totalresistors++;
|
||||
}
|
||||
TxError("%s %d %d\n",name,nodes,resistors);
|
||||
{
|
||||
nodes++;
|
||||
totalnodes++;
|
||||
}
|
||||
for (res = ResResList; res != NULL; res=res->rr_nextResistor)
|
||||
{
|
||||
resistors++;
|
||||
totalresistors++;
|
||||
}
|
||||
TxError("%s %d %d\n", name, nodes, resistors);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -323,8 +325,8 @@ ResPrintStats(goodies,name)
|
|||
|
||||
void
|
||||
resWriteNodeName(fp, nodeptr)
|
||||
FILE *fp;
|
||||
resNode *nodeptr;
|
||||
FILE *fp;
|
||||
resNode *nodeptr;
|
||||
{
|
||||
if (nodeptr->rn_name == NULL)
|
||||
fprintf(fp, "N%d", nodeptr->rn_id);
|
||||
|
|
|
|||
|
|
@ -27,12 +27,13 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "textio/textio.h"
|
||||
#include "extract/extract.h"
|
||||
#include "extract/extractInt.h"
|
||||
#include "extflat/extflat.h"
|
||||
#include "windows/windows.h"
|
||||
#include "dbwind/dbwind.h"
|
||||
#include "utils/utils.h"
|
||||
#include "utils/tech.h"
|
||||
#include "textio/txcommands.h"
|
||||
#include "resis/resis.h"
|
||||
#include "resis/resis.h"
|
||||
|
||||
|
||||
/* constants defining where various fields can be found in .sim files. */
|
||||
|
|
@ -49,11 +50,10 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#define COUPLEVALUE 3
|
||||
#define REALNAME 1
|
||||
#define ALIASNAME 2
|
||||
#define NODECIFCOMMAND 0
|
||||
#define NODENODENAME 1
|
||||
#define NODENODEX 2
|
||||
#define NODENODEY 3
|
||||
#define NODETYPE 4
|
||||
#define NODES_NODENAME 0
|
||||
#define NODES_NODEX 1
|
||||
#define NODES_NODEY 2
|
||||
#define NODES_NODETYPE 3
|
||||
#define NODE_BBOX_LL_X 5
|
||||
#define NODE_BBOX_LL_Y 6
|
||||
#define NODE_BBOX_UR_X 7
|
||||
|
|
@ -119,10 +119,10 @@ extern void ResSimProcessDrivePoints();
|
|||
*/
|
||||
|
||||
int
|
||||
ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc)
|
||||
ResReadSim(simfile, fetproc, capproc, resproc, attrproc, mergeproc, subproc)
|
||||
char *simfile;
|
||||
int (*fetproc)(),(*capproc)(),(*resproc)();
|
||||
int (*attrproc)(),(*mergeproc)();
|
||||
int (*fetproc)(), (*capproc)(), (*resproc)();
|
||||
int (*attrproc)(), (*mergeproc)(), (*subproc)();
|
||||
|
||||
{
|
||||
char line[MAXLINE][MAXTOKEN];
|
||||
|
|
@ -172,6 +172,8 @@ ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc)
|
|||
line[ATTRIBUTEVALUE],
|
||||
simfile, &extfile);
|
||||
break;
|
||||
case 'x': fettype = DBNumTypes;
|
||||
break;
|
||||
case 'D':
|
||||
case 'c':
|
||||
case 'r': break;
|
||||
|
|
@ -184,6 +186,10 @@ ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc)
|
|||
TxError("Error in Reading device line of sim file.\n");
|
||||
result = 1;
|
||||
}
|
||||
else if (fettype == DBNumTypes)
|
||||
{
|
||||
result = (*subproc)(line);
|
||||
}
|
||||
else if (fettype != MINFINITY)
|
||||
{
|
||||
float sheetr;
|
||||
|
|
@ -229,13 +235,6 @@ ResReadNode(nodefile)
|
|||
char *cp;
|
||||
float lambda;
|
||||
|
||||
/* NOTE: Units from the .nodes file are in centimicrons.
|
||||
* Divide by the extract scale (exts_unitsPerLambda) to get back
|
||||
* to database units. This assumes that exts_unitsPerLambda doesn't
|
||||
* change between output and readback.
|
||||
*/
|
||||
lambda = (float)ExtCurStyle->exts_unitsPerLambda;
|
||||
|
||||
fp = PaOpen(nodefile,"r",".nodes",".", (char *) NULL, (char **) NULL);
|
||||
if (fp == NULL)
|
||||
{
|
||||
|
|
@ -244,19 +243,19 @@ ResReadNode(nodefile)
|
|||
}
|
||||
while (gettokens(line,fp) != 0)
|
||||
{
|
||||
entry = HashFind(&ResNodeTable,line[NODENODENAME]);
|
||||
entry = HashFind(&ResNodeTable,line[NODES_NODENAME]);
|
||||
node = ResInitializeNode(entry);
|
||||
|
||||
node->location.p_x = (int)((float)atof(line[NODENODEX]) / lambda);
|
||||
node->location.p_y = (int)((float)atof(line[NODENODEY]) / lambda);
|
||||
node->location.p_x = atoi(line[NODES_NODEX]);
|
||||
node->location.p_y = atoi(line[NODES_NODEY]);
|
||||
#ifdef ARIEL
|
||||
node->rs_bbox.r_xbot = (int)((float)atof(line[NODE_BBOX_LL_X]) / lambda);
|
||||
node->rs_bbox.r_ybot = (int)((float)atof(line[NODE_BBOX_LL_Y]) / lambda);
|
||||
node->rs_bbox.r_xtop = (int)((float)atof(line[NODE_BBOX_UR_X]) / lambda);
|
||||
node->rs_bbox.r_ytop = (int)((float)atof(line[NODE_BBOX_UR_Y]) / lambda);
|
||||
node->rs_bbox.r_xbot = atoi(line[NODE_BBOX_LL_X]);
|
||||
node->rs_bbox.r_ybot = atoi(line[NODE_BBOX_LL_Y]);
|
||||
node->rs_bbox.r_xtop = atoi(line[NODE_BBOX_UR_X]);
|
||||
node->rs_bbox.r_ytop = atoi(line[NODE_BBOX_UR_Y]);
|
||||
#endif
|
||||
if (cp = strchr(line[NODETYPE], ';')) *cp = '\0';
|
||||
node->type = DBTechNameType(line[NODETYPE]);
|
||||
if (cp = strchr(line[NODES_NODETYPE], ';')) *cp = '\0';
|
||||
node->type = DBTechNameType(line[NODES_NODETYPE]);
|
||||
|
||||
if (node->type == -1)
|
||||
{
|
||||
|
|
@ -317,6 +316,130 @@ gettokens(line,fp)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResSimSubckt-- Processes a subcircuit line from a sim file.
|
||||
* This uses the "user subcircuit" extension defined in
|
||||
* IRSIM, although it is mostly intended as a way to work
|
||||
* around the device type limitations of the .sim format
|
||||
* when using extresist.
|
||||
*
|
||||
* Results: returns 0 if line was added correctly.
|
||||
*
|
||||
* Side Effects: Allocates devices and adds nodes to the node hash table.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResSimSubckt(line)
|
||||
char line[][MAXTOKEN];
|
||||
{
|
||||
RDev *device;
|
||||
int rvalue, i, j, k;
|
||||
static int nowarning = TRUE;
|
||||
float lambda;
|
||||
TileType ttype = TT_SPACE;
|
||||
char *lptr = NULL, *wptr = NULL;
|
||||
|
||||
device = (RDev *) mallocMagic((unsigned) (sizeof(RDev)));
|
||||
|
||||
device->status = FALSE;
|
||||
device->nextDev = ResRDevList;
|
||||
|
||||
lambda = (float)ExtCurStyle->exts_unitsPerLambda / resscale;
|
||||
device->location.p_x = 0;
|
||||
device->location.p_y = 0;
|
||||
|
||||
device->rs_gattr=RDEV_NOATTR;
|
||||
device->rs_sattr=RDEV_NOATTR;
|
||||
device->rs_dattr=RDEV_NOATTR;
|
||||
|
||||
ResRDevList = device;
|
||||
device->layout = NULL;
|
||||
|
||||
/* The last argument is the name of the device */
|
||||
for (i = 1; line[i][0] != '\0'; i++);
|
||||
i--;
|
||||
|
||||
for (j = 0; j < EFDevNumTypes; j++)
|
||||
if (!strcmp(EFDevTypes[j], line[i]))
|
||||
break;
|
||||
|
||||
/* Read attributes, especially to pick up values for L, W, X, and Y,
|
||||
* that are critical for use by extresist.
|
||||
*/
|
||||
for (k = 1; line[k][0] != '\0'; k++)
|
||||
{
|
||||
char *eqptr;
|
||||
eqptr = strchr(line[k], '=');
|
||||
if (eqptr != NULL)
|
||||
{
|
||||
if (k < i) i = k;
|
||||
eqptr++;
|
||||
switch (line[k][0]) {
|
||||
case 'l':
|
||||
lptr = eqptr;
|
||||
break;
|
||||
case 'w':
|
||||
wptr = eqptr;
|
||||
break;
|
||||
case 'x':
|
||||
device->location.p_x = (int)((float)atof(eqptr) / lambda);
|
||||
break;
|
||||
case 'y':
|
||||
device->location.p_y = (int)((float)atof(eqptr) / lambda);
|
||||
break;
|
||||
case 't':
|
||||
ttype = (int)(atoi(eqptr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This should not be needed, as ext2sim should encode device type */
|
||||
/* in the attributes list. */
|
||||
if (ttype == TT_SPACE)
|
||||
{
|
||||
if (j == EFDevNumTypes)
|
||||
{
|
||||
TxError("Failure to find device type %s\n", line[i]);
|
||||
return 1;
|
||||
}
|
||||
ttype = extGetDevType(EFDevTypes[j]);
|
||||
}
|
||||
|
||||
device->rs_ttype = ttype;
|
||||
|
||||
if (lptr != NULL && wptr != NULL)
|
||||
{
|
||||
float rpersquare;
|
||||
ExtDevice *devptr;
|
||||
|
||||
devptr = ExtCurStyle->exts_device[ttype];
|
||||
rpersquare =(float)devptr->exts_linearResist;
|
||||
device->resistance = MagAtof(lptr) * rpersquare/MagAtof(wptr);
|
||||
}
|
||||
else
|
||||
device->resistance = 0;
|
||||
|
||||
rvalue = 0;
|
||||
for (k = 1; k < i; k++)
|
||||
{
|
||||
if (k > SUBS)
|
||||
{
|
||||
TxError("Device %s has more than 4 ports (not handled).\n", line[i]);
|
||||
break; /* No method to handle more ports than this */
|
||||
}
|
||||
rvalue += ResSimNewNode(line[k], k, device);
|
||||
}
|
||||
|
||||
return rvalue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -330,7 +453,7 @@ gettokens(line,fp)
|
|||
*/
|
||||
|
||||
int
|
||||
ResSimDevice(line,rpersquare,ttype)
|
||||
ResSimDevice(line, rpersquare, ttype)
|
||||
char line[][MAXTOKEN];
|
||||
float rpersquare;
|
||||
TileType ttype;
|
||||
|
|
@ -428,7 +551,7 @@ ResSimDevice(line,rpersquare,ttype)
|
|||
*/
|
||||
|
||||
int
|
||||
ResSimNewNode(line,type,device)
|
||||
ResSimNewNode(line, type, device)
|
||||
char line[];
|
||||
int type;
|
||||
RDev *device;
|
||||
|
|
@ -443,7 +566,7 @@ ResSimNewNode(line,type,device)
|
|||
TxError("Missing device connection\n");
|
||||
return(1);
|
||||
}
|
||||
entry = HashFind(&ResNodeTable,line);
|
||||
entry = HashFind(&ResNodeTable, line);
|
||||
node = ResInitializeNode(entry);
|
||||
tptr = (devPtr *) mallocMagic((unsigned) (sizeof(devPtr)));
|
||||
tptr->thisDev = device;
|
||||
|
|
@ -458,6 +581,8 @@ ResSimNewNode(line,type,device)
|
|||
break;
|
||||
case DRAIN: device->drain = node;
|
||||
break;
|
||||
case SUBS: device->subs = node;
|
||||
break;
|
||||
default: TxError("Bad Terminal Specifier\n");
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
130
resis/ResRex.c
130
resis/ResRex.c
|
|
@ -37,9 +37,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
|
||||
/* Time constants are produced by multiplying attofarads by milliohms, */
|
||||
/* giving zeptoseconds (yes, really. Look it up). This constant */
|
||||
/* converts zeptoseconds to nanoseconds. */
|
||||
/* converts zeptoseconds to picoseconds. */
|
||||
|
||||
#define Z_TO_N 1e12
|
||||
#define Z_TO_P 1e9
|
||||
|
||||
/* ResSimNode is a node read in from a sim file */
|
||||
|
||||
|
|
@ -105,8 +105,8 @@ ExtResisForDef(celldef, resisdata)
|
|||
HashInit(&ResNodeTable, INITFLATSIZE, HT_STRINGKEYS);
|
||||
/* read in .sim file */
|
||||
result = (ResReadSim(celldef->cd_name,
|
||||
ResSimDevice,ResSimCapacitor,ResSimResistor,
|
||||
ResSimAttribute,ResSimMerge) == 0);
|
||||
ResSimDevice, ResSimCapacitor, ResSimResistor,
|
||||
ResSimAttribute, ResSimMerge, ResSimSubckt) == 0);
|
||||
|
||||
if (result)
|
||||
/* read in .nodes file */
|
||||
|
|
@ -766,12 +766,12 @@ ResCheckPorts(cellDef)
|
|||
result = 0;
|
||||
if ((node = (ResSimNode *) HashGetValue(entry)) != NULL)
|
||||
{
|
||||
TxError("Port: name = %s exists, forcing drivepoint\n",
|
||||
TxPrintf("Port: name = %s exists, forcing drivepoint\n",
|
||||
lab->lab_text);
|
||||
TxError("Location is (%d, %d); drivepoint (%d, %d)\n",
|
||||
TxPrintf("Location is (%d, %d); drivepoint (%d, %d)\n",
|
||||
node->location.p_x, node->location.p_y,
|
||||
portloc.p_x, portloc.p_y);
|
||||
TxFlushErr();
|
||||
TxFlush();
|
||||
node->drivepoint = portloc;
|
||||
node->status |= FORCE;
|
||||
}
|
||||
|
|
@ -782,9 +782,9 @@ ResCheckPorts(cellDef)
|
|||
/* and a drivepoint. */
|
||||
|
||||
node = ResInitializeNode(entry);
|
||||
TxError("Port: name = %s is new node 0x%x\n",
|
||||
TxPrintf("Port: name = %s is new node 0x%x\n",
|
||||
lab->lab_text, node);
|
||||
TxError("Location is (%d, %d); drivepoint (%d, %d)\n",
|
||||
TxPrintf("Location is (%d, %d); drivepoint (%d, %d)\n",
|
||||
portloc.p_x, portloc.p_y,
|
||||
portloc.p_x, portloc.p_y);
|
||||
node->location = portloc;
|
||||
|
|
@ -1111,37 +1111,33 @@ ResCheckSimNodes(celldef, resisdata)
|
|||
|
||||
if (total)
|
||||
{
|
||||
TxError("Total Nets: %d\nNets extracted: "
|
||||
TxPrintf("Total Nets: %d\nNets extracted: "
|
||||
"%d (%f)\nNets output: %d (%f)\n", total, failed1,
|
||||
(float)failed1 / (float)total, failed3,
|
||||
(float)failed3 / (float)total);
|
||||
}
|
||||
else
|
||||
{
|
||||
TxError("Total Nodes: %d\n",total);
|
||||
TxPrintf("Total Nodes: %d\n",total);
|
||||
}
|
||||
|
||||
/* close output files */
|
||||
|
||||
if (ResExtFile != NULL)
|
||||
{
|
||||
(void) fclose(ResExtFile);
|
||||
}
|
||||
|
||||
if (ResLumpFile != NULL)
|
||||
{
|
||||
(void) fclose(ResLumpFile);
|
||||
}
|
||||
|
||||
if (ResFHFile != NULL)
|
||||
{
|
||||
(void) fclose(ResFHFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResFixUpConnections-- Changes the connection to a terminal of the sim
|
||||
* ResFixUpConnections-- Changes the connection to a terminal of the sim
|
||||
* device. The new name is formed by appending .t# to the old name.
|
||||
* The new name is added to the hash table of node names.
|
||||
*
|
||||
|
|
@ -1169,27 +1165,26 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
/* don't patch up networks. This cuts down on memory use. */
|
||||
|
||||
if ((ResOptionsFlags & (ResOpt_DoRsmFile | ResOpt_DoExtFile)) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (simDev->layout == NULL)
|
||||
{
|
||||
layoutDev->rd_status |= RES_DEV_SAVE;
|
||||
simDev->layout = layoutDev;
|
||||
}
|
||||
simDev->status |= TRUE;
|
||||
if (strcmp(nodename,oldnodename) != 0)
|
||||
if (strcmp(nodename, oldnodename) != 0)
|
||||
{
|
||||
strcpy(oldnodename,nodename);
|
||||
strcpy(oldnodename, nodename);
|
||||
}
|
||||
(void)sprintf(newname,"%s%s%d",nodename,".t",resNodeNum++);
|
||||
sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++);
|
||||
notdecremented = TRUE;
|
||||
|
||||
if (simDev->gate == simNode)
|
||||
{
|
||||
if ((gate=layoutDev->rd_fet_gate) != NULL)
|
||||
{
|
||||
/* cosmetic addition: If the layout device already has a */
|
||||
/* Cosmetic addition: If the layout device already has a */
|
||||
/* name, the new one won't be used, so we decrement resNodeNum */
|
||||
if (gate->rn_name != NULL)
|
||||
{
|
||||
|
|
@ -1197,45 +1192,41 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
notdecremented = FALSE;
|
||||
}
|
||||
|
||||
ResFixDevName(newname,GATE,simDev,gate);
|
||||
ResFixDevName(newname, GATE, simDev, gate);
|
||||
gate->rn_name = simDev->gate->name;
|
||||
(void)sprintf(newname,"%s%s%d",nodename,".t",resNodeNum++);
|
||||
sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++);
|
||||
}
|
||||
else
|
||||
{
|
||||
TxError("Missing gate connection\n");
|
||||
}
|
||||
}
|
||||
if (simDev->source == simNode)
|
||||
{
|
||||
if (simDev->drain == simNode)
|
||||
{
|
||||
if ((source=layoutDev->rd_fet_source) &&
|
||||
(drain=layoutDev->rd_fet_drain))
|
||||
if (((source = layoutDev->rd_fet_source) != NULL) &&
|
||||
((drain = layoutDev->rd_fet_drain) != NULL))
|
||||
{
|
||||
if (source->rn_name != NULL && notdecremented)
|
||||
{
|
||||
resNodeNum--;
|
||||
notdecremented = FALSE;
|
||||
}
|
||||
ResFixDevName(newname,SOURCE,simDev,source);
|
||||
ResFixDevName(newname, SOURCE, simDev, source);
|
||||
source->rn_name = simDev->source->name;
|
||||
(void)sprintf(newname,"%s%s%d",nodename,".t",resNodeNum++);
|
||||
(void)sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++);
|
||||
if (drain->rn_name != NULL) resNodeNum--;
|
||||
ResFixDevName(newname,DRAIN,simDev,drain);
|
||||
ResFixDevName(newname, DRAIN, simDev, drain);
|
||||
drain->rn_name = simDev->drain->name;
|
||||
/* one to each */
|
||||
}
|
||||
else
|
||||
{
|
||||
TxError("Missing SD connection\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (source=layoutDev->rd_fet_source)
|
||||
if ((source = layoutDev->rd_fet_source) != NULL)
|
||||
{
|
||||
if (drain=layoutDev->rd_fet_drain)
|
||||
if ((drain = layoutDev->rd_fet_drain) != NULL)
|
||||
{
|
||||
if (source != drain)
|
||||
{
|
||||
|
|
@ -1256,7 +1247,7 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
}
|
||||
layoutDev->rd_fet_drain = (resNode *)NULL;
|
||||
if (source->rn_name != NULL) resNodeNum--;
|
||||
ResFixDevName(newname,SOURCE,simDev,source);
|
||||
ResFixDevName(newname, SOURCE, simDev, source);
|
||||
source->rn_name = simDev->source->name;
|
||||
}
|
||||
else
|
||||
|
|
@ -1266,22 +1257,20 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
resNodeNum--;
|
||||
notdecremented = FALSE;
|
||||
}
|
||||
ResFixDevName(newname,SOURCE,simDev,source);
|
||||
ResFixDevName(newname, SOURCE, simDev, source);
|
||||
source->rn_name = simDev->source->name;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
TxError("missing SD connection\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (simDev->drain == simNode)
|
||||
{
|
||||
if (source=layoutDev->rd_fet_source)
|
||||
if ((source = layoutDev->rd_fet_source) != NULL)
|
||||
{
|
||||
if (drain=layoutDev->rd_fet_drain)
|
||||
if ((drain = layoutDev->rd_fet_drain) != NULL)
|
||||
{
|
||||
if (drain != source)
|
||||
{
|
||||
|
|
@ -1321,14 +1310,10 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TxError("missing SD connection\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resNodeNum--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1346,7 +1331,7 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
*/
|
||||
|
||||
void
|
||||
ResFixDevName(line,type,device,layoutnode)
|
||||
ResFixDevName(line, type, device, layoutnode)
|
||||
char line[];
|
||||
int type;
|
||||
RDev *device;
|
||||
|
|
@ -1359,13 +1344,13 @@ ResFixDevName(line,type,device,layoutnode)
|
|||
|
||||
if (layoutnode->rn_name != NULL)
|
||||
{
|
||||
entry = HashFind(&ResNodeTable,layoutnode->rn_name);
|
||||
entry = HashFind(&ResNodeTable, layoutnode->rn_name);
|
||||
node = ResInitializeNode(entry);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = HashFind(&ResNodeTable,line);
|
||||
entry = HashFind(&ResNodeTable, line);
|
||||
node = ResInitializeNode(entry);
|
||||
}
|
||||
tptr = (devPtr *) mallocMagic((unsigned) (sizeof(devPtr)));
|
||||
|
|
@ -1397,7 +1382,7 @@ ResFixDevName(line,type,device,layoutnode)
|
|||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResSortByGate--sorts device pointers whose terminal field is either
|
||||
* ResSortByGate -- sorts device pointers whose terminal field is either
|
||||
* drain or source by gate node number, then by drain (source) number.
|
||||
* This places devices with identical connections next to one
|
||||
* another.
|
||||
|
|
@ -1448,8 +1433,8 @@ ResSortByGate(DevpointerList)
|
|||
last = NULL;
|
||||
while (working != NULL && (current = working->nextDev) != NULL)
|
||||
{
|
||||
RDev *w = working->thisDev;
|
||||
RDev *c = current->thisDev;
|
||||
RDev *w = working->thisDev;
|
||||
RDev *c = current->thisDev;
|
||||
|
||||
if (w->gate > c->gate)
|
||||
{
|
||||
|
|
@ -1503,17 +1488,12 @@ ResSortByGate(DevpointerList)
|
|||
else
|
||||
{
|
||||
if (working->nextDev != NULL)
|
||||
{
|
||||
TxError("Bad Device pointer in sort\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
working->nextDev = gatelist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -1536,13 +1516,11 @@ ResWriteLumpFile(node)
|
|||
{
|
||||
if (gparams.rg_nodecap != 0)
|
||||
{
|
||||
lumpedres = (int)((gparams.rg_Tdi/gparams.rg_nodecap
|
||||
-(float)(gparams.rg_bigdevres))/OHMSTOMILLIOHMS);
|
||||
lumpedres = (int)((gparams.rg_Tdi / gparams.rg_nodecap
|
||||
- (float)(gparams.rg_bigdevres)) / OHMSTOMILLIOHMS);
|
||||
}
|
||||
else
|
||||
{
|
||||
lumpedres = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1636,35 +1614,35 @@ ResWriteExtFile(celldef, node, tol, rctol, nidx, eidx)
|
|||
|
||||
RCdev = gparams.rg_bigdevres * gparams.rg_nodecap;
|
||||
|
||||
if (tol == 0.0 ||(node->status & FORCE) ||
|
||||
(ResOptionsFlags & ResOpt_ExtractAll)||
|
||||
(ResOptionsFlags & ResOpt_Simplify)==0||
|
||||
(rctol+1)*RCdev < rctol*gparams.rg_Tdi)
|
||||
if (tol == 0.0 || (node->status & FORCE) ||
|
||||
(ResOptionsFlags & ResOpt_ExtractAll) ||
|
||||
(ResOptionsFlags & ResOpt_Simplify) == 0 ||
|
||||
(rctol + 1) * RCdev < rctol * gparams.rg_Tdi)
|
||||
{
|
||||
ASSERT(gparams.rg_Tdi != -1,"ResWriteExtFile");
|
||||
(void)sprintf(newname,"%s",node->name);
|
||||
cp = newname+strlen(newname)-1;
|
||||
ASSERT(gparams.rg_Tdi != -1, "ResWriteExtFile");
|
||||
(void)sprintf(newname,"%s", node->name);
|
||||
cp = newname + strlen(newname)-1;
|
||||
if (*cp == '!' || *cp == '#') *cp = '\0';
|
||||
if ((rctol+1)*RCdev < rctol*gparams.rg_Tdi ||
|
||||
if ((rctol + 1) * RCdev < rctol * gparams.rg_Tdi ||
|
||||
(ResOptionsFlags & ResOpt_Tdi) == 0)
|
||||
{
|
||||
if ((ResOptionsFlags & (ResOpt_RunSilent|ResOpt_Tdi)) == ResOpt_Tdi)
|
||||
if ((ResOptionsFlags & (ResOpt_RunSilent | ResOpt_Tdi)) == ResOpt_Tdi)
|
||||
{
|
||||
TxError("Adding %s; Tnew = %.2fns,Told = %.2fns\n",
|
||||
node->name,gparams.rg_Tdi/Z_TO_N, RCdev/Z_TO_N);
|
||||
TxPrintf("Adding %s; Tnew = %.2fns, Told = %.2fns\n",
|
||||
node->name, gparams.rg_Tdi / Z_TO_P, RCdev / Z_TO_P);
|
||||
}
|
||||
}
|
||||
for (ptr = node->firstDev; ptr != NULL; ptr=ptr->nextDev)
|
||||
{
|
||||
if (layoutDev = ResGetDevice(&ptr->thisDev->location))
|
||||
{
|
||||
ResFixUpConnections(ptr->thisDev,layoutDev,node,newname);
|
||||
ResFixUpConnections(ptr->thisDev, layoutDev, node, newname);
|
||||
}
|
||||
}
|
||||
if (ResOptionsFlags & ResOpt_DoExtFile)
|
||||
{
|
||||
ResPrintExtNode(ResExtFile,ResNodeList,node->name);
|
||||
ResPrintExtRes(ResExtFile,ResResList,newname);
|
||||
ResPrintExtNode(ResExtFile, ResNodeList, node->name);
|
||||
ResPrintExtRes(ResExtFile, ResResList, newname);
|
||||
}
|
||||
if (ResOptionsFlags & ResOpt_FastHenry)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -293,6 +293,7 @@ typedef struct rdev
|
|||
struct ressimnode *gate; /* Terminals of transistor. */
|
||||
struct ressimnode *source;
|
||||
struct ressimnode *drain;
|
||||
struct ressimnode *subs; /* Used with subcircuit type only */
|
||||
Point location; /* Location of lower left point of */
|
||||
/* device. */
|
||||
float resistance; /* "Resistance" of device. */
|
||||
|
|
@ -519,6 +520,7 @@ typedef struct capval
|
|||
#define GATE 1
|
||||
#define SOURCE 2
|
||||
#define DRAIN 3
|
||||
#define SUBS 4
|
||||
|
||||
#define DRIVEONLY 0x00001000
|
||||
#define ORIGIN 0x00000008
|
||||
|
|
@ -610,6 +612,7 @@ extern int ResSimCapacitor();
|
|||
extern int ResSimResistor();
|
||||
extern int ResSimAttribute();
|
||||
extern int ResSimMerge();
|
||||
extern int ResSimSubckt();
|
||||
extern int dbSrConnectStartFunc();
|
||||
extern int ResEach(),ResAddPlumbing(),ResRemovePlumbing();
|
||||
extern float ResCalculateChildCapacitance();
|
||||
|
|
|
|||
|
|
@ -52,26 +52,6 @@ int rtrDelta; /* Change in layer width */
|
|||
* is used to clear the markings again.
|
||||
*/
|
||||
|
||||
/* The following structure is used to hold several pieces
|
||||
* of information that must be passed through multiple
|
||||
* levels of search function.
|
||||
*/
|
||||
|
||||
struct conSrArg
|
||||
{
|
||||
CellDef *csa_def; /* Definition being searched. */
|
||||
int csa_pNum; /* Index of plane being searched. */
|
||||
TileTypeBitMask *csa_connect; /* Table indicating what connects
|
||||
* to what.
|
||||
*/
|
||||
int (*csa_clientFunc)(); /* Client function to call. */
|
||||
ClientData csa_clientData; /* Argument for clientFunc. */
|
||||
bool csa_clear; /* FALSE means pass 1, TRUE
|
||||
* means pass 2.
|
||||
*/
|
||||
Rect csa_bounds; /* Area that limits search. */
|
||||
};
|
||||
|
||||
/*
|
||||
* The search path is maintained on the C runtime stack
|
||||
* with rtrTileStack sructures. Each entry on the stack
|
||||
|
|
|
|||
|
|
@ -253,6 +253,144 @@ selClearFunc(scx)
|
|||
else return 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* selIntersectPaintFunc2 ---
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
selIntersectPaintFunc2(tile, rect)
|
||||
Tile *tile; /* The tile to copy paint from. */
|
||||
Rect *rect; /* Area to clip to */
|
||||
{
|
||||
Rect r;
|
||||
|
||||
TiToRect(tile, &r);
|
||||
GEOCLIP(&r, rect); /* Clip out the intersection area */
|
||||
DBPaint(SelectDef, &r, TiGetTypeExact(tile)); /* Paint back into SelectDef */
|
||||
return 0; /* Keep the search going. */
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* selIntersectPaintFunc --
|
||||
*
|
||||
* Erase paint of types in rMask from the area of the tile.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
selIntersectPaintFunc(tile)
|
||||
Tile *tile; /* The tile to copy paint from. */
|
||||
{
|
||||
TileTypeBitMask tMask;
|
||||
Rect r;
|
||||
int pNum;
|
||||
|
||||
TiToRect(tile, &r);
|
||||
|
||||
for (pNum = 0; pNum < DBNumPlanes; pNum++)
|
||||
{
|
||||
DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[pNum], &r,
|
||||
&DBAllButSpaceAndDRCBits, selIntersectPaintFunc2,
|
||||
(ClientData)&r);
|
||||
}
|
||||
return 0; /* Keep the search going. */
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* SelectIntersect --
|
||||
*
|
||||
* This procedure selects all information that falls in a given area
|
||||
* and contains the intersection of all the supplied types.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* The indicated information is added to the select cell, and
|
||||
* outlined on the screen. Only information of particular
|
||||
* types, and in expanded cells (according to xMask) is
|
||||
* selected.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
SelectIntersect(scx, type, xMask, negate)
|
||||
SearchContext *scx; /* Describes the area in which material
|
||||
* is to be selected. The resulting
|
||||
* coordinates should map to the coordinates
|
||||
* of EditRootDef. The cell use should be
|
||||
* the root of a window.
|
||||
*/
|
||||
TileType type; /* Indicates which layer to intersect with
|
||||
* the current selection.
|
||||
*/
|
||||
int xMask; /* Indicates window (or windows) where cells
|
||||
* must be expanded for their contents to be
|
||||
* considered. 0 means treat everything as
|
||||
* expanded.
|
||||
*/
|
||||
bool negate; /* If true, search on NOT(type) */
|
||||
{
|
||||
TileTypeBitMask tMask, rMask;
|
||||
TileType s, t;
|
||||
int plane;
|
||||
SearchContext scx2;
|
||||
|
||||
/* The source definition may not change */
|
||||
if (SelectRootDef != scx->scx_use->cu_def) return;
|
||||
|
||||
SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
|
||||
|
||||
/* Copy SelectDef contents (paint only) into Select2Def */
|
||||
DBCellClearDef(Select2Def);
|
||||
scx2.scx_use = SelectUse;
|
||||
scx2.scx_area = SelectUse->cu_bbox;
|
||||
GeoTransTrans(&GeoIdentityTransform, &SelectUse->cu_transform, &scx2.scx_trans);
|
||||
DBCellCopyAllPaint(&scx2, &DBAllButSpaceAndDRCBits, CU_DESCEND_NO_LOCK,
|
||||
Select2Use);
|
||||
|
||||
/* Clear the original selection */
|
||||
DBCellClearDef(SelectDef);
|
||||
|
||||
/* Select all paint of type "type" and copy into SelectDef */
|
||||
TTMaskSetOnlyType(&tMask, type);
|
||||
|
||||
plane = DBPlane(type);
|
||||
(void) DBCellCopyAllPaint(scx, &tMask, xMask, SelectUse);
|
||||
|
||||
/* Scan Select2Def for all geometry inside the area of "type", and */
|
||||
/* copy back to SelectDef as "type" */
|
||||
|
||||
if (negate)
|
||||
{
|
||||
TTMaskCom(&tMask);
|
||||
TTMaskAndMask(&tMask, &DBPlaneTypes[plane]);
|
||||
}
|
||||
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[plane],
|
||||
&scx->scx_area, &tMask, selIntersectPaintFunc, (ClientData)NULL);
|
||||
|
||||
if (negate) TTMaskSetOnlyType(&tMask, type); /* Restore original mask */
|
||||
|
||||
DBEraseMask(SelectDef, &TiPlaneRect, &tMask);
|
||||
|
||||
/* Display the new selection. */
|
||||
|
||||
SelRememberForUndo(FALSE, SelectRootDef, &scx->scx_area);
|
||||
DBReComputeBbox(SelectDef);
|
||||
DBWHLRedraw(SelectRootDef, &scx->scx_area, TRUE);
|
||||
DBWAreaChanged(SelectDef, &SelectDef->cd_extended, DBW_ALLWINDOWS,
|
||||
&DBAllButSpaceBits);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
|
|
@ -749,7 +887,7 @@ SelectRegion(scx, type, xMask, pArea, less)
|
|||
UndoDisable();
|
||||
DBCellClearDef(Select2Def);
|
||||
DBTreeCopyConnect(scx, &connections[type], xMask, connections,
|
||||
&TiPlaneRect, TRUE, Select2Use);
|
||||
&TiPlaneRect, SelectDoLabels, Select2Use);
|
||||
UndoEnable();
|
||||
|
||||
/* Now transfer what we found into the main selection cell. Pick
|
||||
|
|
@ -850,7 +988,7 @@ SelectNet(scx, type, xMask, pArea, less)
|
|||
UndoDisable();
|
||||
DBCellClearDef(Select2Def);
|
||||
DBTreeCopyConnect(scx, &mask, xMask, DBConnectTbl,
|
||||
&TiPlaneRect, TRUE, Select2Use);
|
||||
&TiPlaneRect, SelectDoLabels, Select2Use);
|
||||
UndoEnable();
|
||||
|
||||
/* Network undo method added by Nishit and Tim, July 8-10, 2004 */
|
||||
|
|
@ -1074,7 +1212,7 @@ SelectAndCopy2(newSourceDef)
|
|||
SearchContext scx;
|
||||
Rect editArea, labelArea, expanded;
|
||||
int plane;
|
||||
void (*savedPaintPlane)();
|
||||
int (*savedPaintPlane)();
|
||||
extern int selACPaintFunc(); /* Forward reference. */
|
||||
extern int selACCellFunc();
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,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/geometry.h"
|
||||
|
|
@ -47,6 +48,7 @@ static int selStretchX, selStretchY; /* Stretch distances. Only one should
|
|||
* ever be non-zero.
|
||||
*/
|
||||
static TileType selStretchType; /* Type of material being stretched. */
|
||||
unsigned char SelectDoLabels = SEL_DO_LABELS; /* Whether or not to select subcell labels */
|
||||
|
||||
typedef struct planeAndArea
|
||||
{
|
||||
|
|
@ -716,6 +718,43 @@ SelectShort(char *lab1, char *lab2)
|
|||
destlab = selLabel;
|
||||
}
|
||||
|
||||
/* Was nothing selected? Then run the equivalent of "goto lab1 ; select net */
|
||||
if (srclab == NULL && destlab == NULL)
|
||||
{
|
||||
CellUse *use;
|
||||
TileType ttype;
|
||||
Rect rect;
|
||||
SearchContext scx;
|
||||
MagWindow *window;
|
||||
DBWclientRec *crec;
|
||||
int windowMask;
|
||||
|
||||
window = ToolGetBoxWindow(&rect, &windowMask);
|
||||
if (!window) return NULL;
|
||||
|
||||
use = (CellUse *)window->w_surfaceID;
|
||||
ttype = CmdFindNetProc(lab1, use, &rect, FALSE);
|
||||
if (ttype == TT_SPACE) return NULL;
|
||||
|
||||
bzero(&scx, sizeof(SearchContext));
|
||||
scx.scx_use = use;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
scx.scx_area = rect;
|
||||
crec = (DBWclientRec *)window->w_clientData;
|
||||
|
||||
SelectNet(&scx, ttype, crec->dbw_bitmask, (Rect *)NULL, FALSE);
|
||||
|
||||
for (selLabel = SelectDef->cd_labels; selLabel != NULL; selLabel =
|
||||
selLabel->lab_next)
|
||||
{
|
||||
if ((srclab == NULL) && Match(lab1, selLabel->lab_text))
|
||||
srclab = selLabel;
|
||||
|
||||
if ((destlab == NULL) && Match(lab2, selLabel->lab_text))
|
||||
destlab = selLabel;
|
||||
}
|
||||
}
|
||||
|
||||
/* Must be able to find both labels */
|
||||
if (srclab == NULL || destlab == NULL) return NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -372,7 +372,6 @@ SelectRemoveCellUse(use, trans)
|
|||
|
||||
{
|
||||
SearchContext scx;
|
||||
CellUse selectedUse;
|
||||
SelRemoveCellArgs args;
|
||||
|
||||
/* The search context is the area covered by the cell's bounding box in
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ extern void SelectRegion();
|
|||
extern void SelectInit();
|
||||
extern void SelectClear();
|
||||
extern void SelectCell();
|
||||
extern void SelectIntersect();
|
||||
extern void SelRemoveArea();
|
||||
extern int SelRemoveSel2();
|
||||
extern int SelectRemoveCellUse();
|
||||
|
|
@ -56,6 +57,15 @@ extern void SelectStretch();
|
|||
extern void SelectArray();
|
||||
extern void SelectDump();
|
||||
|
||||
/* Flag to indicate whether selection captures subcell labels */
|
||||
|
||||
extern unsigned char SelectDoLabels;
|
||||
|
||||
/* Flag values for SelectDoLabels: */
|
||||
#define SEL_NO_LABELS 0
|
||||
#define SEL_DO_LABELS 1
|
||||
#define SEL_SIMPLE_LABELS 2
|
||||
|
||||
/* The following is the root cell that contains the current selection. */
|
||||
|
||||
extern CellDef *SelectRootDef;
|
||||
|
|
|
|||
101
sim/SimDBstuff.c
101
sim/SimDBstuff.c
|
|
@ -31,6 +31,7 @@
|
|||
#include "utils/geofast.h"
|
||||
#include "tiles/tile.h"
|
||||
#include "utils/hash.h"
|
||||
#include "utils/stack.h"
|
||||
#include "database/database.h"
|
||||
#include "database/databaseInt.h"
|
||||
#include "textio/textio.h"
|
||||
|
|
@ -45,54 +46,6 @@
|
|||
#include "utils/styles.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
||||
/* The following structure is used to hold several pieces
|
||||
* of information that must be passed through multiple
|
||||
* levels of search function.
|
||||
*/
|
||||
|
||||
struct conSrArg
|
||||
{
|
||||
CellDef *csa_def; /* Definition being searched. */
|
||||
Plane *csa_plane; /* Current plane being searched. */
|
||||
TileTypeBitMask *csa_connect; /* Table indicating what connects
|
||||
* to what.
|
||||
*/
|
||||
int (*csa_clientFunc)(); /* Client function to call. */
|
||||
ClientData csa_clientData; /* Argument for clientFunc. */
|
||||
bool csa_clear; /* FALSE means pass 1, TRUE
|
||||
* means pass 2.
|
||||
*/
|
||||
Rect csa_bounds; /* Area that limits search. */
|
||||
};
|
||||
|
||||
/* For SimTreeSrConnect, the extraction proceeds in one pass, copying
|
||||
* all connected stuff from a hierarchy into a single cell. A list
|
||||
* is kept to record areas that still have to be searched for
|
||||
* hierarchical stuff.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Rect area; /* Area to process */
|
||||
TileTypeBitMask *connectMask; /* Connection mask for search */
|
||||
TileType dinfo; /* Info about triangular search areas */
|
||||
} conSrArea;
|
||||
|
||||
struct conSrArg2
|
||||
{
|
||||
CellUse *csa2_use; /* Destination use */
|
||||
TileTypeBitMask *csa2_connect; /* Table indicating what connects
|
||||
* to what.
|
||||
*/
|
||||
Rect *csa2_bounds; /* Area that limits the search */
|
||||
|
||||
conSrArea *csa2_list; /* List of areas to process */
|
||||
int csa2_top; /* Index of next area to process */
|
||||
int csa2_size; /* Max. number bins in area list */
|
||||
};
|
||||
|
||||
#define CSA2_LIST_START_SIZE 256
|
||||
|
||||
/* Forward declarations */
|
||||
|
||||
extern char *DBPrintUseId();
|
||||
|
|
@ -303,27 +256,29 @@ SimConnectFunc(tile, cx)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Check if any of the last 5 entries has the same type and */
|
||||
/* area. If so, don't duplicate the existing entry. */
|
||||
/* (NOTE: Connect masks are all from the same table, so */
|
||||
/* they can be compared by address, no need for TTMaskEqual)*/
|
||||
|
||||
for (i = csa2->csa2_lasttop; (i >= 0) && (i > csa2->csa2_lasttop - 5); i--)
|
||||
if (connectMask == csa2->csa2_list[i].connectMask)
|
||||
if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea))
|
||||
return 0;
|
||||
|
||||
/* Register the area and connection mask as needing to be processed */
|
||||
|
||||
if (++csa2->csa2_top == csa2->csa2_size)
|
||||
if (++csa2->csa2_top == CSA2_LIST_SIZE)
|
||||
{
|
||||
/* Reached list size limit---need to enlarge the list */
|
||||
/* Double the size of the list every time we hit the limit */
|
||||
|
||||
conSrArea *newlist;
|
||||
int i, lastsize = csa2->csa2_size;
|
||||
|
||||
csa2->csa2_size *= 2;
|
||||
|
||||
newlist = (conSrArea *)mallocMagic(csa2->csa2_size * sizeof(conSrArea));
|
||||
for (i = 0; i < lastsize; i++)
|
||||
{
|
||||
newlist[i].area = csa2->csa2_list[i].area;
|
||||
newlist[i].connectMask = csa2->csa2_list[i].connectMask;
|
||||
newlist[i].dinfo = csa2->csa2_list[i].dinfo;
|
||||
}
|
||||
freeMagic((char *)csa2->csa2_list);
|
||||
newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
|
||||
StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
|
||||
csa2->csa2_list = newlist;
|
||||
csa2->csa2_top = 0;
|
||||
}
|
||||
|
||||
csa2->csa2_list[csa2->csa2_top].area = newarea;
|
||||
|
|
@ -407,10 +362,11 @@ SimTreeCopyConnect(scx, mask, xMask, connect, area, destUse, Node_Name)
|
|||
csa2.csa2_bounds = area;
|
||||
csa2.csa2_connect = connect;
|
||||
|
||||
csa2.csa2_size = CSA2_LIST_START_SIZE;
|
||||
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_START_SIZE
|
||||
* sizeof(conSrArea));
|
||||
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
|
||||
csa2.csa2_top = -1;
|
||||
csa2.csa2_lasttop = -1;
|
||||
|
||||
csa2.csa2_stack = StackNew(100);
|
||||
|
||||
tpath.tp_first = tpath.tp_next = pathName;
|
||||
tpath.tp_last = pathName + MAXPATHNAME;
|
||||
|
|
@ -425,7 +381,21 @@ SimTreeCopyConnect(scx, mask, xMask, connect, area, destUse, Node_Name)
|
|||
newmask = csa2.csa2_list[csa2.csa2_top].connectMask;
|
||||
scx->scx_area = csa2.csa2_list[csa2.csa2_top].area;
|
||||
newtype = csa2.csa2_list[csa2.csa2_top].dinfo;
|
||||
csa2.csa2_top--;
|
||||
if (csa2.csa2_top == 0)
|
||||
{
|
||||
if (StackLook(csa2.csa2_stack) != (ClientData)NULL)
|
||||
{
|
||||
freeMagic(csa2.csa2_list);
|
||||
csa2.csa2_list = (conSrArea *)StackPop(csa2.csa2_stack);
|
||||
csa2.csa2_top = CSA2_LIST_SIZE - 1;
|
||||
}
|
||||
else
|
||||
csa2.csa2_top--;
|
||||
}
|
||||
else
|
||||
csa2.csa2_top--;
|
||||
|
||||
csa2.csa2_lasttop = csa2.csa2_top;
|
||||
|
||||
if (newtype & TT_DIAGONAL)
|
||||
SimTreeSrNMTiles(scx, newtype, newmask, xMask, &tpath,
|
||||
|
|
@ -435,6 +405,7 @@ SimTreeCopyConnect(scx, mask, xMask, connect, area, destUse, Node_Name)
|
|||
(ClientData) &csa2);
|
||||
}
|
||||
freeMagic((char *)csa2.csa2_list);
|
||||
StackFree(csa2.csa2_stack);
|
||||
|
||||
/* Recompute the bounding box of the destination and record
|
||||
* its area for redisplay.
|
||||
|
|
@ -636,7 +607,7 @@ SimSrConnect(def, startArea, mask, connect, bounds, func, clientData)
|
|||
csa.csa_clientData = clientData;
|
||||
csa.csa_clear = FALSE;
|
||||
csa.csa_connect = connect;
|
||||
csa.csa_plane = def->cd_planes[startPlane];
|
||||
csa.csa_pNum = startPlane;
|
||||
if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ proc readspice {netfile} {
|
|||
# Read data from file. Remove comment lines and concatenate
|
||||
# continuation lines.
|
||||
|
||||
puts stderr "Annotating port orders from $netfile"
|
||||
puts stdout "Annotating port orders from $netfile"
|
||||
flush stdout
|
||||
set fdata {}
|
||||
set lastline ""
|
||||
while {[gets $fnet line] >= 0} {
|
||||
|
|
@ -109,14 +110,20 @@ proc readspice {netfile} {
|
|||
# Make sure pins aren't duplicated by first moving all pin
|
||||
# indexes above the number of pins to check.
|
||||
|
||||
puts stdout "Annotating cell $cell"
|
||||
flush stdout
|
||||
set npins [expr {[llength $ftokens] - 1}]
|
||||
set highport [port last]
|
||||
set outport $highport
|
||||
if {$outport < $npins} {set outport $npins}
|
||||
set p [port first]
|
||||
while {$p != -1 && $p <= $highport} {
|
||||
if {$p == ""} {
|
||||
puts stderr "Error: $cell port numbering failed."
|
||||
break
|
||||
}
|
||||
set p1 [port $p next]
|
||||
set testpin [port $p name]
|
||||
set testpin [port $p name -quiet]
|
||||
if {$testpin != ""} {
|
||||
port $p index $outport
|
||||
incr outport
|
||||
|
|
@ -150,15 +157,15 @@ proc readspice {netfile} {
|
|||
# a port.
|
||||
|
||||
set testpin $pin
|
||||
set pinidx [port $testpin index]
|
||||
set pinidx [port $testpin index -quiet]
|
||||
|
||||
if {$pinidx == ""} {
|
||||
set testpin [string map {\[ < \] >]} $pin]
|
||||
set pinidx [port $testpin index]
|
||||
set pinidx [port $testpin index -quiet]
|
||||
}
|
||||
if {$pinidx == ""} {
|
||||
set testpin [string map {< \[ > \]} $pin]
|
||||
set pinidx [port $testpin index]
|
||||
set pinidx [port $testpin index -quiet]
|
||||
}
|
||||
|
||||
# Handle issues with case insensitivity by getting
|
||||
|
|
@ -167,9 +174,9 @@ proc readspice {netfile} {
|
|||
if {$pinidx == ""} {
|
||||
set highport [port last]
|
||||
for {set p 0} {$p <= $highport} {incr p} {
|
||||
set testpin [port $p name]
|
||||
set testpin [port $p name -quiet]
|
||||
if {[string tolower $testpin] == [string tolower $pin]} {
|
||||
set pinidx [port $testpin index]
|
||||
set pinidx [port $testpin index -quiet]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
# Revision 1
|
||||
# October 29, 2020
|
||||
# Revision 2 (names are hashed from properties)
|
||||
# March 9, 2021
|
||||
# Added spice-to-layout procedure
|
||||
#--------------------------------------------------------------
|
||||
# Sets up the environment for a toolkit. The toolkit must
|
||||
# supply a namespace that is the "library name". For each
|
||||
|
|
@ -105,6 +107,307 @@ magic::macro ^P "magic::gencell {} ; raise .params"
|
|||
|
||||
magic::tag select "[magic::tag select]; magic::gencell_update %1"
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Supporting procedures for netlist_to_layout procedure
|
||||
#--------------------------------------------------------------
|
||||
|
||||
# move_forward_by_width --
|
||||
#
|
||||
# Given an instance name, find the instance and position the
|
||||
# cursor box at the right side of the instance.
|
||||
|
||||
proc magic::move_forward_by_width {instname} {
|
||||
select cell $instname
|
||||
set anum [lindex [array -list count] 1]
|
||||
set xpitch [lindex [array -list pitch] 0]
|
||||
set bbox [box values]
|
||||
set posx [lindex $bbox 0]
|
||||
set posy [lindex $bbox 1]
|
||||
set width [expr [lindex $bbox 2] - $posx]
|
||||
set posx [expr $posx + $width + $xpitch * $anum]
|
||||
box position ${posx}i ${posy}i
|
||||
return [lindex $bbox 3]
|
||||
}
|
||||
|
||||
# get_and_move_inst --
|
||||
#
|
||||
# Given a cell name, creat an instance of the cell named "instname"
|
||||
# at the current cursor box position. If option "anum" is given
|
||||
# and > 1, then array the cell.
|
||||
|
||||
proc magic::get_and_move_inst {cellname instname {anum 1}} {
|
||||
set newinst [getcell $cellname]
|
||||
select cell $newinst
|
||||
if {$newinst == ""} {return}
|
||||
identify $instname
|
||||
if {$anum > 1} {array 1 $anum}
|
||||
set bbox [box values]
|
||||
set posx [lindex $bbox 2]
|
||||
set posy [lindex $bbox 1]
|
||||
box position ${posx}i ${posy}i
|
||||
return [lindex $bbox 3]
|
||||
}
|
||||
|
||||
# create_new_pin --
|
||||
#
|
||||
# Create a new pin of size 1um x 1um at the current cursor box
|
||||
# location. If "layer" is given, then create the pin on the
|
||||
# given layer. Otherwise, the pin is created on the m1 layer.
|
||||
|
||||
proc magic::create_new_pin {pinname portnum {layer m1}} {
|
||||
box size 1um 1um
|
||||
paint $layer
|
||||
label $pinname FreeSans 16 0 0 0 c $layer
|
||||
port make $portnum
|
||||
box move s 2um
|
||||
}
|
||||
|
||||
# generate_layout_add --
|
||||
#
|
||||
# Add a new subcircuit to a layout and seed it with components
|
||||
# as found in the list "complist", and add pins according to the
|
||||
# pin names in "subpins". Each entry in "complist" is a single
|
||||
# device line from a SPICE file.
|
||||
|
||||
proc magic::generate_layout_add {subname subpins complist library} {
|
||||
global PDKNAMESPACE
|
||||
|
||||
# Create a new subcircuit
|
||||
load $subname -quiet
|
||||
box 0 0 0 0
|
||||
|
||||
# Generate pins
|
||||
if {[llength $subpins] > 0} {
|
||||
set pinlist [split $subpins]
|
||||
set i 0
|
||||
foreach pin $pinlist {
|
||||
# Escape [ and ] in pin name
|
||||
set pin_esc [string map {\[ \\\[ \] \\\]} $pin]
|
||||
magic::create_new_pin $pin_esc $i
|
||||
incr i
|
||||
}
|
||||
}
|
||||
|
||||
# Set initial position for importing cells
|
||||
box size 0 0
|
||||
set posx 0
|
||||
set posy [expr {round(3 / [cif scale out])}]
|
||||
box position ${posx}i ${posy}i
|
||||
|
||||
# Seed layout with components
|
||||
foreach comp $complist {
|
||||
set pinlist {}
|
||||
set paramlist {}
|
||||
|
||||
# NOTE: This routine deals with subcircuit calls and devices
|
||||
# with models. It needs to determine when a device is instantiated
|
||||
# without a model, and ignore such devices.
|
||||
|
||||
# Parse SPICE line into pins, device name, and parameters. Make
|
||||
# sure parameters incorporate quoted expressions as {} or ''.
|
||||
|
||||
set rest $comp
|
||||
while {$rest != ""} {
|
||||
if {[regexp -nocase {^[ \t]*[^= \t]+=[^=]+} $rest]} {
|
||||
break
|
||||
} elseif {[regexp -nocase {^[ \t]*([^ \t]+)[ \t]*(.*)$} $rest \
|
||||
valid token rest]} {
|
||||
lappend pinlist $token
|
||||
} else {
|
||||
set rest ""
|
||||
}
|
||||
}
|
||||
|
||||
while {$rest != ""} {
|
||||
if {[regexp -nocase {^([^= \t]+)=\'([^\']+)\'[ \t]*(.*)} $rest \
|
||||
valid pname value rest]} {
|
||||
lappend paramlist [list $pname "{$value}"]
|
||||
} elseif {[regexp -nocase {^([^= \t]+)=\{([^\}]+)\}[ \t]*(.*)} $rest \
|
||||
valid pname value rest]} {
|
||||
lappend paramlist [list $pname "{$value}"]
|
||||
} elseif {[regexp -nocase {^([^= \t]+)=([^= \t]+)[ \t]*(.*)} $rest \
|
||||
valid pname value rest]} {
|
||||
lappend paramlist [list $pname $value]
|
||||
} else {
|
||||
puts stderr "Error parsing line \"$comp\""
|
||||
puts stderr "at: \"$rest\""
|
||||
set rest ""
|
||||
}
|
||||
}
|
||||
|
||||
if {[llength $pinlist] < 2} {
|
||||
puts stderr "Error: No device type found in line \"$comp\""
|
||||
puts stderr "Tokens found are: \"$pinlist\""
|
||||
continue
|
||||
}
|
||||
|
||||
set instname [lindex $pinlist 0]
|
||||
set devtype [lindex $pinlist end]
|
||||
set pinlist [lrange $pinlist 0 end-1]
|
||||
|
||||
set mult 1
|
||||
foreach param $paramlist {
|
||||
set parmname [lindex $param 0]
|
||||
set parmval [lindex $param 1]
|
||||
if {[string toupper $parmname] == "M"} {
|
||||
if {[catch {set mult [expr {int($parmval)}]}]} {
|
||||
set mult [expr [string trim $parmval "'"]]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# devtype is assumed to be in library. If not, it will attempt to
|
||||
# use 'getcell' on devtype. Note that this code depends on the
|
||||
# PDK setting varible PDKNAMESPACE.
|
||||
|
||||
if {$library != ""} {
|
||||
set libdev ${library}::${devtype}
|
||||
} else {
|
||||
set libdev ${PDKNAMESPACE}::${devtype}
|
||||
}
|
||||
|
||||
set outparts {}
|
||||
lappend outparts "magic::gencell $libdev $instname"
|
||||
|
||||
# Output all parameters. Parameters not used by the toolkit are
|
||||
# ignored by the toolkit.
|
||||
|
||||
lappend outparts "-spice"
|
||||
foreach param $paramlist {
|
||||
lappend outparts [string tolower [lindex $param 0]]
|
||||
lappend outparts [lindex $param 1]
|
||||
}
|
||||
|
||||
if {[catch {eval [join $outparts]}]} {
|
||||
# Assume this is not a gencell, and get an instance.
|
||||
magic::get_and_move_inst $devtype $instname $mult
|
||||
} else {
|
||||
# Move forward for next gencell
|
||||
magic::move_forward_by_width $instname
|
||||
}
|
||||
}
|
||||
save $subname
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Wrapper for generating an initial layout from a SPICE netlist
|
||||
# using the defined PDK toolkit procedures
|
||||
#
|
||||
# "netfile" is the name of a SPICE netlist
|
||||
# "library" is the name of the PDK library namespace
|
||||
#--------------------------------------------------------------
|
||||
|
||||
proc magic::netlist_to_layout {netfile library} {
|
||||
|
||||
if {![file exists $netfile]} {
|
||||
puts stderr "No such file $netfile"
|
||||
return
|
||||
}
|
||||
|
||||
# Read data from file. Remove comment lines and concatenate
|
||||
# continuation lines.
|
||||
|
||||
set topname [file rootname [file tail $netfile]]
|
||||
puts stdout "Creating layout from [file tail $netfile]"
|
||||
|
||||
if {[file ext $netfile] == ".cdl"} {
|
||||
set is_cdl true
|
||||
} else {
|
||||
set is_cdl false
|
||||
}
|
||||
|
||||
if [catch {open $netfile r} fnet] {
|
||||
puts stderr "Error: Cannot open file \"$netfile\" for reading."
|
||||
return
|
||||
}
|
||||
|
||||
set fdata {}
|
||||
set lastline ""
|
||||
while {[gets $fnet line] >= 0} {
|
||||
# Handle CDL format *.PININFO (convert to .PININFO ...)
|
||||
if {$is_cdl && ([string range $line 0 1] == "*.")} {
|
||||
if {[string tolower [string range $line 2 8]] == "pininfo"} {
|
||||
set line [string range $line 1 end]
|
||||
}
|
||||
}
|
||||
if {[string index $line 0] != "*"} {
|
||||
if {[string index $line 0] == "+"} {
|
||||
if {[string range $line end end] != " "} {
|
||||
append lastline " "
|
||||
}
|
||||
append lastline [string range $line 1 end]
|
||||
} else {
|
||||
lappend fdata $lastline
|
||||
set lastline $line
|
||||
}
|
||||
}
|
||||
}
|
||||
lappend fdata $lastline
|
||||
close $fnet
|
||||
|
||||
set insub false
|
||||
set incmd false
|
||||
set subname ""
|
||||
set subpins ""
|
||||
set complist {}
|
||||
set toplist {}
|
||||
|
||||
# suspendall
|
||||
|
||||
set ignorekeys {.global .ic .option .end}
|
||||
|
||||
# Parse the file
|
||||
foreach line $fdata {
|
||||
if {$incmd} {
|
||||
if {[regexp -nocase {^[ \t]*\.endc} $line]} {
|
||||
set incmd false
|
||||
}
|
||||
} elseif {! $insub} {
|
||||
set ftokens [split $line]
|
||||
set keyword [string tolower [lindex $ftokens 0]]
|
||||
|
||||
if {[lsearch $ignorekeys $keyword] != -1} {
|
||||
continue
|
||||
} elseif {$keyword == ".command"} {
|
||||
set incmd true
|
||||
} elseif {$keyword == ".subckt"} {
|
||||
set subname [lindex $ftokens 1]
|
||||
set subpins [lrange $ftokens 2 end]
|
||||
set insub true
|
||||
} elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \
|
||||
valid instname rest]} {
|
||||
lappend toplist $line
|
||||
} elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \
|
||||
valid instname rest]} {
|
||||
# These are testbench devices and should be ignored
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if {[regexp -nocase {^[ \t]*\.ends} $line]} {
|
||||
set insub false
|
||||
magic::generate_layout_add $subname $subpins $complist $library
|
||||
set subname ""
|
||||
set subpins ""
|
||||
set complist {}
|
||||
} elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \
|
||||
valid instname rest]} {
|
||||
lappend complist $line
|
||||
} elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \
|
||||
valid instname rest]} {
|
||||
# These are testbench devices and should be ignored
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Add in any top-level components (not in subcircuits)
|
||||
if {[llength $toplist] > 0} {
|
||||
magic::generate_layout_add $topname "" $toplist $library
|
||||
}
|
||||
|
||||
# resumeall
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# gencell
|
||||
#
|
||||
|
|
@ -184,6 +487,11 @@ proc magic::gencell {gencell_name {instname {}} args} {
|
|||
set gencell_type $gencell_name
|
||||
}
|
||||
|
||||
# Check that the device exists as a gencell, or else return an error
|
||||
if {[namespace eval ::${library} info commands ${gencell_type}_convert] == ""} {
|
||||
error "No import routine for ${library} library cell ${gencell_type}!"
|
||||
}
|
||||
|
||||
if {$instname == {}} {
|
||||
# Case: Interactive, new device with parameters in args (if any)
|
||||
if {$spicemode == 1} {
|
||||
|
|
@ -237,6 +545,7 @@ proc magic::gencell {gencell_name {instname {}} args} {
|
|||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
|
|
@ -436,6 +745,14 @@ proc magic::gencell_change {instname gencell_type library parameters} {
|
|||
# then keep the old instance name.
|
||||
if {[string first $old_gname $instname] != 0} {
|
||||
set newinstname $instname
|
||||
} else {
|
||||
# The buttons "Apply" and "Okay" need to be changed for the new
|
||||
# instance name
|
||||
catch {.params.buttons.apply config -command \
|
||||
"magic::gencell_change $newinstname $gencell_type $library {}"}
|
||||
catch {.params.buttons.okay config -command \
|
||||
"magic::gencell_change $newinstname $gencell_type $library {} ;\
|
||||
destroy .params"}
|
||||
}
|
||||
}
|
||||
identify $newinstname
|
||||
|
|
|
|||
|
|
@ -58,11 +58,31 @@ proc magic::makecrashbackup {} {
|
|||
global Opts
|
||||
|
||||
*bypass crash save
|
||||
if {$Opts(backupinterval) > 0} {
|
||||
after $Opts(backupinterval) magic::makecrashbackup
|
||||
if {![catch set Opts(backupinterval)]} {
|
||||
if {$Opts(backupinterval) > 0} {
|
||||
after $Opts(backupinterval) magic::makecrashbackup
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# magic::crashbackups ---
|
||||
#
|
||||
# Create periodic backups. Options are:
|
||||
#
|
||||
# start: Begin periodic backups. If interval is not
|
||||
# specified, then set interval to 10 minutes.
|
||||
#
|
||||
# resume: Resume periodic backups if started and stopped,
|
||||
# but not if disabled or never started.
|
||||
#
|
||||
# stop: Stop periodic backups.
|
||||
#
|
||||
# disable: Disable periodic backups; set to state of
|
||||
# never having been started.
|
||||
#
|
||||
#----------------------------------------------------------------
|
||||
|
||||
proc magic::crashbackups {{option start}} {
|
||||
global Opts
|
||||
|
||||
|
|
@ -71,12 +91,25 @@ proc magic::crashbackups {{option start}} {
|
|||
if {[catch set Opts(backupinterval)]} {
|
||||
set Opts(backupinterval) 600000
|
||||
}
|
||||
after $Opts(backupinterval) magic::makecrashbackup
|
||||
if {$Opts(backupinterval) > 0} {
|
||||
after $Opts(backupinterval) magic::makecrashbackup
|
||||
}
|
||||
}
|
||||
resume {
|
||||
if {![catch set Opts(backupinterval)]} {
|
||||
if {$Opts(backupinterval) > 0} {
|
||||
after $Opts(backupinterval) magic::makecrashbackup
|
||||
}
|
||||
}
|
||||
}
|
||||
stop -
|
||||
cancel {
|
||||
after cancel magic::makecrashbackup
|
||||
}
|
||||
disable {
|
||||
after cancel magic::makecrashbackup
|
||||
unset Opts(backupinterval)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -123,12 +156,17 @@ proc magic::popstack {} {
|
|||
} else {
|
||||
set ltag [tag load]
|
||||
tag load {}
|
||||
suspendall
|
||||
load [lindex $editstack end]
|
||||
set snaptype [snap]
|
||||
snap internal
|
||||
view [lindex $editstack end-1]
|
||||
tag load $ltag
|
||||
set editstack [lrange $editstack 0 end-2]
|
||||
snap $snaptype
|
||||
catch {magic::cellmanager}
|
||||
catch {magic::captions}
|
||||
resumeall
|
||||
tag load $ltag
|
||||
set editstack [lrange $editstack 0 end-2]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -554,7 +554,6 @@ set Opts(crosshair) 0
|
|||
set Opts(hidelocked) 0
|
||||
set Opts(hidespecial) 0
|
||||
set Opts(toolbar) 0
|
||||
set Opts(scale) 1.0
|
||||
set Opts(toolscale) 1.0
|
||||
set Opts(drc) 1
|
||||
set Opts(autobuttontext) 1
|
||||
|
|
@ -1135,6 +1134,16 @@ proc magic::openwrapper {{cell ""} {framename ""}} {
|
|||
toplevel $framename
|
||||
tkwait visibility $framename
|
||||
|
||||
# Get scale from the TkDefaultFont size, unless Opts(scale) is already
|
||||
# set. On standard displays, an "M" in the Sans font is usually 10
|
||||
# pixels wide, and 22 on high resolution displays, so this maps to
|
||||
# a scale of 1 on standard displays and a scale of 2 on high resolution
|
||||
# displays. Make sure scale doesn't go to zero or bad things happen.
|
||||
|
||||
if [catch {set Opts(scale)}] {
|
||||
set Opts(scale) [expr {max(1, int([font measure TkDefaultFont M] / 10))}]
|
||||
}
|
||||
|
||||
# Resize the window
|
||||
if {[catch {wm geometry ${framename} $Winopts(${framename},geometry)}]} {
|
||||
catch {wm geometry ${framename} $Opts(geometry)}
|
||||
|
|
|
|||
11
utils/main.c
11
utils/main.c
|
|
@ -770,6 +770,12 @@ mainInitAfterArgs()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void tcl_exit_hook(ClientData clientData)
|
||||
{
|
||||
TxResetTerminal();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* mainInitFinal:
|
||||
|
|
@ -794,6 +800,9 @@ mainInitFinal()
|
|||
char *rname;
|
||||
int result;
|
||||
|
||||
/* Reset terminal if exit is called inside a TCL script */
|
||||
Tcl_SetExitProc(tcl_exit_hook);
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
|
||||
/* Read in system pre-startup file, if it exists. */
|
||||
|
|
@ -1187,6 +1196,8 @@ mainInitFinal()
|
|||
UndoFlush();
|
||||
TxClearPoint();
|
||||
|
||||
Tcl_SetExitProc(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,8 +26,17 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <signal.h>
|
||||
#include <unistd.h> /* for getpid() */
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/main.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "utils/signals.h"
|
||||
#include "windows/windows.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
||||
#ifndef SIGEMT
|
||||
#define SIGEMT 7 /* EMT instruction (SIGUNUSED) */
|
||||
|
|
@ -57,17 +66,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "utils/signals.h"
|
||||
#include "windows/windows.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
||||
|
||||
#ifndef FASYNC
|
||||
# define FASYNC 00100 /* kludge for SUN2s */
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue