Merge branch 'master' of https://github.com/RTimothyEdwards/magic into spice_hier

This commit is contained in:
Dan Moore 2021-05-17 10:05:21 -07:00
commit dde3d75256
75 changed files with 3726 additions and 1106 deletions

View File

@ -1 +1 @@
8.3.125 8.3.164

View File

@ -48,12 +48,14 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
int calmaNonManhattan; int calmaNonManhattan;
int CalmaFlattenLimit = 10; int CalmaFlattenLimit = 10;
int NameConvertErrors = 0;
extern HashTable calmaDefInitHash; extern HashTable calmaDefInitHash;
/* forward declarations */ /* forward declarations */
int calmaElementSref(); int calmaElementSref();
bool calmaParseElement(); bool calmaParseElement();
void calmaUniqueCell();
/* Structure used when flattening the GDS hierarchy on read-in */ /* Structure used when flattening the GDS hierarchy on read-in */
@ -306,8 +308,8 @@ calmaParseStructure(filename)
if (!calmaReadStringRecord(CALMA_STRNAME, &strname)) goto syntaxerror; if (!calmaReadStringRecord(CALMA_STRNAME, &strname)) goto syntaxerror;
TxPrintf("Reading \"%s\".\n", strname); TxPrintf("Reading \"%s\".\n", strname);
if (CalmaReadOnly) /* Used for read-only and annotated LEF views */
filepos = ftello(calmaInputFile); filepos = ftello(calmaInputFile);
/* Set up the cell definition */ /* Set up the cell definition */
he = HashFind(&calmaDefInitHash, strname); he = HashFind(&calmaDefInitHash, strname);
@ -348,51 +350,76 @@ calmaParseStructure(filename)
freeMagic(newname); freeMagic(newname);
} }
} }
if (CalmaUnique) calmaUniqueCell(strname); /* Ensure uniqueness */
cifReadCellDef = calmaFindCell(strname, &was_called, &predefined); cifReadCellDef = calmaFindCell(strname, &was_called, &predefined);
HashSetValue(he, cifReadCellDef);
if (predefined == TRUE) if (predefined == TRUE)
{ {
calmaNextCell(); bool isAbstract;
return TRUE;
/* 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); else
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))
{ {
if (SigInterruptPending) DBCellClearDef(cifReadCellDef);
goto done; DBCellSetAvail(cifReadCellDef);
if (nsrefs > osrefs && (nsrefs % 100) == 0) cifCurReadPlanes = cifSubcellPlanes;
TxPrintf(" %d uses\n", nsrefs); cifReadCellDef->cd_flags &= ~CDDEREFERENCE;
osrefs = nsrefs;
/* 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; 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 */ /* Writing the file position into a string is slow, but */
/* it prevents requiring special handling when printing */ /* it prevents requiring special handling when printing */
/* out the properties. */ /* out the properties. */
char *fpcopy = (char *)mallocMagic(20); 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); sprintf(fpcopy, "%"DLONG_PREFIX"d", (dlong) filepos);
DBPropPut(cifReadCellDef, "GDS_START", (ClientData)fpcopy); DBPropPut(cifReadCellDef, "GDS_START", (ClientData)fpcopy);
@ -403,9 +430,11 @@ calmaParseStructure(filename)
DBPropPut(cifReadCellDef, "GDS_FILE", (ClientData)fncopy); DBPropPut(cifReadCellDef, "GDS_FILE", (ClientData)fncopy);
/* Do not lock the cell, or else we can't save the */ if (predefined)
/* magic cell with its GDS pointers to disk. . . */ {
/* cifReadCellDef->cd_flags |= CDNOEDIT; */ if (strname != NULL) freeMagic(strname);
return TRUE;
}
} }
/* Check if the cell name matches the pattern list of cells to flatten */ /* 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)); 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); READI2(propAttrType);
if (propAttrType == CALMA_PROP_USENAME) if (propAttrType == CALMA_PROP_USENAME)
{ {
char *s;
if (!calmaReadStringRecord(CALMA_PROPVALUE, &useid)) if (!calmaReadStringRecord(CALMA_PROPVALUE, &useid))
return -1; 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) else if (propAttrType == CALMA_PROP_ARRAY_LIMITS)
{ {
@ -981,9 +1045,38 @@ calmaElementSref(filename)
} }
} }
/* If cell has children in addition to paint to be flattened, */ /* When not reading with VENDORGDS, if a cell has contents */
/* then also generate an instance of the cell. */ /* 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 else
{ {
use = DBCellNewUse(def, (useid) ? useid : (char *) NULL); use = DBCellNewUse(def, (useid) ? useid : (char *) NULL);
@ -1045,6 +1138,65 @@ gdsCopyPaintFunc(tile, gdsCopyRec)
return 0; 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);
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *

View File

@ -87,6 +87,12 @@ bool CalmaNoDuplicates = FALSE; /* If TRUE, then if a cell exists in
* in the GDS file, then the cell in * in the GDS file, then the cell in
* the GDS file is skipped. * 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 void calmaUnexpected();
extern int calmaWriteInitFunc(); extern int calmaWriteInitFunc();

View File

@ -613,7 +613,7 @@ calmaFullDump(def, fi, outf, filename)
FILE *outf; FILE *outf;
char *filename; char *filename;
{ {
int version, rval, i; int version, rval;
char *libname = NULL, uniqlibname[4]; char *libname = NULL, uniqlibname[4];
char *sptr, *viewopts; char *sptr, *viewopts;
bool isAbstract; bool isAbstract;
@ -657,24 +657,29 @@ calmaFullDump(def, fi, outf, filename)
viewopts = (char *)DBPropGet(def, "LEFview", &isAbstract); viewopts = (char *)DBPropGet(def, "LEFview", &isAbstract);
if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix"))) if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
{ {
/* Generate a SHORT name for this cell (else it is easy to run into the /* 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 * GDS 32-character cellname limit). Save it in the hash record. The
* chance of generating the same prefix for a library that has items * chance of generating the same prefix for a library that has items
* with conflicting names is vanishingly small, but to be pedantic, store * 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 * 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) while (TRUE)
{ {
HashEntry *he2; HashEntry *he2;
for (i = 0; i < 2; i++) { rval = random() % 26;
rval = random() % 62; rval = 'A' + rval;
rval = (rval < 26) ? ('A' + rval) : ((rval < 52) ? ('a' + rval - 26) : uniqlibname[0] = (char)(rval & 127);
('0' + rval - 52)); rval = random() % 36;
uniqlibname[i] = (char)(rval & 127); rval = (rval < 26) ? ('A' + rval) : ('0' + rval - 26);
} uniqlibname[1] = (char)(rval & 127);
uniqlibname[2] = '_'; uniqlibname[2] = '_';
uniqlibname[3] = '\0'; uniqlibname[3] = '\0';
he2 = HashLookOnly(&calmaPrefixHash, uniqlibname); he2 = HashLookOnly(&calmaPrefixHash, uniqlibname);
@ -809,6 +814,13 @@ calmaProcessDef(def, outf, do_library)
if (isReadOnly && hasContent && CalmaAddendum) return (0); 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 * Output the definitions for any of our descendants that have
* not already been output. Numbers are assigned to the subcells * not already been output. Numbers are assigned to the subcells

View File

@ -33,6 +33,7 @@ extern bool CalmaDoLower;
extern bool CalmaAddendum; extern bool CalmaAddendum;
extern bool CalmaNoDuplicates; extern bool CalmaNoDuplicates;
extern bool CalmaNoDateStamp; extern bool CalmaNoDateStamp;
extern bool CalmaUnique;
extern bool CalmaMergeTiles; extern bool CalmaMergeTiles;
extern bool CalmaFlattenArrays; extern bool CalmaFlattenArrays;
extern bool CalmaNoDRCCheck; extern bool CalmaNoDRCCheck;

View File

@ -34,6 +34,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "calma/calma.h" /* for CalmaContactArrays */ #include "calma/calma.h" /* for CalmaContactArrays */
#include "commands/commands.h" /* for CmdFindNetProc() */ #include "commands/commands.h" /* for CmdFindNetProc() */
#include "select/selInt.h" /* for select use and def */ #include "select/selInt.h" /* for select use and def */
#include "select/select.h"
#include "utils/stack.h" #include "utils/stack.h"
#include "utils/malloc.h" #include "utils/malloc.h"
#include "utils/maxrect.h" #include "utils/maxrect.h"
@ -4786,7 +4787,7 @@ CIFGenLayer(op, area, cellDef, origDef, temps, hier, clientdata)
scx.scx_use = CIFDummyUse; scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform; scx.scx_trans = GeoIdentityTransform;
DBTreeCopyConnect(&scx, &DBConnectTbl[ttype], 0, DBTreeCopyConnect(&scx, &DBConnectTbl[ttype], 0,
DBConnectTbl, &TiPlaneRect, FALSE, Select2Use); DBConnectTbl, &TiPlaneRect, SEL_NO_LABELS, Select2Use);
cifSrTiles(op, area, Select2Def, temps, cifPaintFunc, cifSrTiles(op, area, Select2Def, temps, cifPaintFunc,
(ClientData) CIFPaintTable); (ClientData) CIFPaintTable);
DBCellClearDef(Select2Def); DBCellClearDef(Select2Def);

View File

@ -110,6 +110,7 @@ bool cmdDumpParseArgs();
#define CALMA_POLYS 19 #define CALMA_POLYS 19
#define CALMA_PATHS 20 #define CALMA_PATHS 20
#define CALMA_UNDEFINED 21 #define CALMA_UNDEFINED 21
#define CALMA_UNIQUE 22
#define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */ #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", "library [yes|no] do not output the top level, only subcells",
"lower [yes|no] allow both upper and lower case in labels", "lower [yes|no] allow both upper and lower case in labels",
"merge [yes|no] merge tiles into polygons in the output", "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", "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" "read file read Calma GDS-II format from \"file\"\n"
" into edit cell", " into edit cell",
"readonly [yes|no] set cell as read-only and generate output from GDS file", "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", " put wire paths into individual subcells",
"undefined [allow|disallow]\n" "undefined [allow|disallow]\n"
" [dis]allow writing of GDS with calls to undefined cells", " [dis]allow writing of GDS with calls to undefined cells",
"unique [yes|no] rename any cells with names duplicated in the GDS",
NULL NULL
}; };
@ -599,6 +601,26 @@ CmdCalma(w, cmd)
CalmaNoDuplicates = (option < 4) ? FALSE : TRUE; CalmaNoDuplicates = (option < 4) ? FALSE : TRUE;
return; 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: case CALMA_NO_STAMP:
if (cmd->tx_argc == 2) if (cmd->tx_argc == 2)
{ {
@ -857,6 +879,9 @@ CmdCellname(w, cmd)
IDX_ORIENTATION, IDX_RENAME, IDX_READWRITE, IDX_ORIENTATION, IDX_RENAME, IDX_READWRITE,
IDX_MODIFIED } optionType; IDX_MODIFIED } optionType;
static char *cmdCellnameYesNo[] = {
"no", "false", "off", "0", "yes", "true", "on", "1", 0 };
if (strstr(cmd->tx_argv[0], "in")) if (strstr(cmd->tx_argv[0], "in"))
is_cellname = FALSE; is_cellname = FALSE;
else else
@ -1072,7 +1097,10 @@ CmdCellname(w, cmd)
} }
else if (locargc == 4) 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 */ /* Check if file is already read-write */
if (!(cellDef->cd_flags & CDNOEDIT)) if (!(cellDef->cd_flags & CDNOEDIT))
@ -1084,13 +1112,11 @@ CmdCellname(w, cmd)
if (cellDef->cd_fd == -1) if (cellDef->cd_fd == -1)
dbReadOpen(cellDef, NULL, TRUE, NULL); dbReadOpen(cellDef, NULL, TRUE, NULL);
if (cellDef->cd_fd != -1) if (cellDef->cd_fd == -1)
cellDef->cd_flags &= ~CDNOEDIT; TxError("Overriding advisory lock held on cell %s\n",
else cellDef->cd_name);
TxError("Advisory lock held on cell %s\n", cellDef->cd_name);
#else
cellDef->cd_flags &= ~CDNOEDIT;
#endif #endif
cellDef->cd_flags &= ~CDNOEDIT;
WindAreaChanged(w, &w->w_screenArea); WindAreaChanged(w, &w->w_screenArea);
CmdSetWindCaption(EditCellUse, EditRootDef); CmdSetWindCaption(EditCellUse, EditRootDef);
} }
@ -3921,6 +3947,216 @@ CmdDrc(w, cmd)
return; 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);
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *

View File

@ -880,6 +880,7 @@ cmdExpandFunc(use, windowMask)
#define DOLENGTH 4 #define DOLENGTH 4
#define DOLOCAL 5 #define DOLOCAL 5
#define DORESISTANCE 6 #define DORESISTANCE 6
#define DOLABELCHECK 7
#define LENCLEAR 0 #define LENCLEAR 0
#define LENDRIVER 1 #define LENDRIVER 1
@ -922,6 +923,7 @@ CmdExtract(w, cmd)
"length compute driver-receiver pathlengths", "length compute driver-receiver pathlengths",
"local put all generated files in the current directory", "local put all generated files in the current directory",
"resistance estimate resistance", "resistance estimate resistance",
"labelcheck check for connections through sticky labels",
NULL NULL
}; };
static char *cmdExtLength[] = static char *cmdExtLength[] =
@ -1141,6 +1143,7 @@ CmdExtract(w, cmd)
TxPrintf("%s length\n", OPTSET(EXT_DOLENGTH)); TxPrintf("%s length\n", OPTSET(EXT_DOLENGTH));
TxPrintf("%s local\n", OPTSET(EXT_DOLOCAL)); TxPrintf("%s local\n", OPTSET(EXT_DOLOCAL));
TxPrintf("%s resistance\n", OPTSET(EXT_DORESISTANCE)); TxPrintf("%s resistance\n", OPTSET(EXT_DORESISTANCE));
TxPrintf("%s label check\n", OPTSET(EXT_DOLABELCHECK));
return; return;
#undef OPTSET #undef OPTSET
} }
@ -1169,6 +1172,7 @@ CmdExtract(w, cmd)
case DOLENGTH: option = EXT_DOLENGTH; break; case DOLENGTH: option = EXT_DOLENGTH; break;
case DOLOCAL: option = EXT_DOLOCAL; break; case DOLOCAL: option = EXT_DOLOCAL; break;
case DORESISTANCE: option = EXT_DORESISTANCE; break; case DORESISTANCE: option = EXT_DORESISTANCE; break;
case DOLABELCHECK: option = EXT_DOLABELCHECK; break;
} }
if (no) ExtOptions &= ~option; if (no) ExtOptions &= ~option;
else ExtOptions |= option; else ExtOptions |= option;

View File

@ -1865,6 +1865,7 @@ flatCopyAllLabels(scx, lab, tpath, targetUse)
{ {
Rect labTargetRect; Rect labTargetRect;
int targetPos; int targetPos;
int flags = 0;
CellDef *def; CellDef *def;
char labelname[1024]; char labelname[1024];
char *n, *f, c; char *n, *f, c;
@ -1894,6 +1895,8 @@ flatCopyAllLabels(scx, lab, tpath, targetUse)
* not a port; possibly we should retain ports taken from the * not a port; possibly we should retain ports taken from the
* top level cell, but certainly not any others. * 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 */ /* To-do Feb. 2008: Translate target rotation and offset */
@ -1903,7 +1906,7 @@ flatCopyAllLabels(scx, lab, tpath, targetUse)
strcpy(n, lab->lab_text); strcpy(n, lab->lab_text);
DBPutFontLabel(def, &labTargetRect, lab->lab_font, lab->lab_size, DBPutFontLabel(def, &labTargetRect, lab->lab_font, lab->lab_size,
lab->lab_rotate, &lab->lab_offset, targetPos, lab->lab_rotate, &lab->lab_offset, targetPos,
f, lab->lab_type, 0); f, lab->lab_type, flags);
*n = c; *n = c;
return 0; return 0;
@ -1932,7 +1935,7 @@ CmdFlatten(w, cmd)
TxCommand *cmd; TxCommand *cmd;
{ {
int rval, xMask; int rval, xMask;
bool dolabels, dobox, toplabels, invert; bool dolabels, dobox, toplabels, invert, doports;
char *destname; char *destname;
CellDef *newdef; CellDef *newdef;
CellUse *newuse; CellUse *newuse;
@ -1944,6 +1947,7 @@ CmdFlatten(w, cmd)
dolabels = TRUE; dolabels = TRUE;
toplabels = FALSE; toplabels = FALSE;
dobox = FALSE; dobox = FALSE;
doports = TRUE;
rval = 0; rval = 0;
if (cmd->tx_argc > 2) if (cmd->tx_argc > 2)
@ -1978,6 +1982,9 @@ CmdFlatten(w, cmd)
case 't': case 't':
toplabels = (invert) ? FALSE : TRUE; toplabels = (invert) ? FALSE : TRUE;
break; break;
case 'p':
doports = (invert) ? FALSE : TRUE;
break;
case 's': case 's':
xMask = (invert) ? CU_DESCEND_NO_SUBCKT : CU_DESCEND_ALL; xMask = (invert) ? CU_DESCEND_NO_SUBCKT : CU_DESCEND_ALL;
break; break;
@ -1985,7 +1992,7 @@ CmdFlatten(w, cmd)
xMask = (invert) ? CU_DESCEND_NO_VENDOR : CU_DESCEND_ALL; xMask = (invert) ? CU_DESCEND_NO_VENDOR : CU_DESCEND_ALL;
break; break;
default: default:
TxError("options are: -nolabels, -nosubcircuits " TxError("options are: -nolabels, -nosubcircuits, -noports, "
"-novendor, -dotoplabels, -dobox\n"); "-novendor, -dotoplabels, -dobox\n");
break; break;
} }

View File

@ -50,6 +50,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
void CmdPaintEraseButton(); void CmdPaintEraseButton();
/* See the SetLabel command */
extern Label *DefaultLabel;
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
@ -169,8 +172,8 @@ CmdLabel(w, cmd)
MagWindow *w; MagWindow *w;
TxCommand *cmd; TxCommand *cmd;
{ {
TileType type; TileType type = (TileType)(-1);
int pos, font = -1, size = 0, rotate = 0, offx = 0, offy = 0; int pos = -1, font = -1, size = 0, rotate = 0, offx = 0, offy = 0;
bool sticky = FALSE; bool sticky = FALSE;
int option; int option;
char *p; char *p;
@ -185,6 +188,22 @@ CmdLabel(w, cmd)
p = cmd->tx_argv[1]; 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. * Find and check validity of position.
*/ */
@ -220,13 +239,14 @@ CmdLabel(w, cmd)
else else
pos = GeoTransPos(&RootToEditTransform, pos); pos = GeoTransPos(&RootToEditTransform, pos);
} }
else pos = -1;
if (font >= 0) if (font >= 0)
{ {
char *yp = NULL; char *yp = NULL;
size = DBLambda[1]; if (DefaultLabel == NULL)
size = DBLambda[1];
if (cmd->tx_argc > 3) if (cmd->tx_argc > 3)
if (StrIsNumeric(cmd->tx_argv[3])) if (StrIsNumeric(cmd->tx_argv[3]))
size = cmdScaleCoord(w, cmd->tx_argv[3], TRUE, TRUE, 8); 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]); TxError("Unknown layer: %s\n", cmd->tx_argv[cmd->tx_argc - 1]);
return; return;
} }
} else type = -1; }
CmdLabelProc(p, font, size, rotate, offx, offy, pos, sticky, type); CmdLabelProc(p, font, size, rotate, offx, offy, pos, sticky, type);
} }
@ -1292,7 +1312,7 @@ complabel(const void *one, const void *two)
* or * or
* port makeall|renumber [connect_direction(s)] * port makeall|renumber [connect_direction(s)]
* or * 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 * 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 * 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 * "value" is a value string representing one of the valid port classes
* or uses. * 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: * Results:
* None. * None.
* *
@ -1346,7 +1369,7 @@ CmdPort(w, cmd)
int i, refidx, idx, pos, type, option, argc; int i, refidx, idx, pos, type, option, argc;
unsigned int dirmask; unsigned int dirmask;
bool found; bool found;
bool nonEdit = FALSE; bool nonEdit = FALSE, doQuiet = FALSE;
Label *lab, *sl; Label *lab, *sl;
Rect editBox, tmpArea; Rect editBox, tmpArea;
CellDef *editDef = EditCellUse->cu_def; CellDef *editDef = EditCellUse->cu_def;
@ -1441,6 +1464,16 @@ CmdPort(w, cmd)
argstart = 1; argstart = 1;
argc = cmd->tx_argc; argc = cmd->tx_argc;
if (argc > 1)
{
if (!strcmp(cmd->tx_argv[argc - 1], "-quiet"))
{
doQuiet = TRUE;
argc--;
}
}
if (argc > 6 || argc == 1) if (argc > 6 || argc == 1)
goto portWrongNumArgs; goto portWrongNumArgs;
else else
@ -1483,10 +1516,13 @@ CmdPort(w, cmd)
} }
if (lab == NULL) if (lab == NULL)
{ {
if (StrIsInt(cmd->tx_argv[1])) if (!doQuiet)
TxError("No label found with index %s.\n", cmd->tx_argv[1]); {
else if (StrIsInt(cmd->tx_argv[1]))
TxError("No port found with name %s.\n", 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; return;
} }
argstart = 2; argstart = 2;
@ -1554,7 +1590,7 @@ CmdPort(w, cmd)
/* label "lab" must already be a port */ /* label "lab" must already be a port */
if (!(lab->lab_flags & PORT_DIR_MASK)) 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"); TxError("The selected label is not a port.\n");
return; return;
} }
@ -1946,8 +1982,11 @@ parseindex:
if ((option != PORT_MAKEALL) && (lab->lab_flags & PORT_DIR_MASK)) if ((option != PORT_MAKEALL) && (lab->lab_flags & PORT_DIR_MASK))
{ {
/* For this syntax, the label must not already be a port */ /* For this syntax, the label must not already be a port */
TxError("The selected label is already a port.\n"); if (!doQuiet)
TxError("Do \"port help\" to get a list of options.\n"); {
TxError("The selected label is already a port.\n");
TxError("Do \"port help\" to get a list of options.\n");
}
return; return;
} }

View File

@ -54,6 +54,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
extern void DisplayWindow(); extern void DisplayWindow();
/* Used by CmdSetLabel() */
Label *DefaultLabel;
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -525,6 +528,26 @@ CmdSee(w, cmd)
return; 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 */ /* ARGSUSED */
void void
cmdSelectArea(layers, less) cmdSelectArea(layers, less, option)
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)
char *layers; /* Which layers are to be selected. */ char *layers; /* Which layers are to be selected. */
bool less; bool less;
int option; /* Option from defined list above */
{ {
SearchContext scx; SearchContext scx;
TileTypeBitMask mask; TileTypeBitMask mask;
@ -677,6 +624,7 @@ cmdSelectVisible(layers, less)
scx.scx_use = (CellUse *) window->w_surfaceID; scx.scx_use = (CellUse *) window->w_surfaceID;
scx.scx_trans = GeoIdentityTransform; scx.scx_trans = GeoIdentityTransform;
crec = (DBWclientRec *) window->w_clientData; crec = (DBWclientRec *) window->w_clientData;
if (option == SEL_VISIBLE)
{ {
int i; int i;
for (i = 0; i < DBNumUserLayers; i++) for (i = 0; i < DBNumUserLayers; i++)
@ -688,6 +636,85 @@ cmdSelectVisible(layers, less)
SelectArea(&scx, &mask, crec->dbw_bitmask); 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. * 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[] = static char *cmdSelectOption[] =
{ {
"area", "area",
"visible", "visible",
"cell", "cell",
"labels",
"intersection",
"clear", "clear",
"flat", "flat",
"help", "help",
@ -774,6 +784,8 @@ CmdSelect(w, cmd)
"[more | less] area [layers] [de]select all info under box in layers", "[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] visible [layers] [de]select all visible info under box in layers",
"[more | less | top] cell [name] [de]select cell under cursor, or \"name\"", "[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", "clear clear selection",
"flat flatten the contents of the selection", "flat flatten the contents of the selection",
"help print this message", "help print this message",
@ -819,7 +831,7 @@ CmdSelect(w, cmd)
* also used to step through multiple uses. * also used to step through multiple uses.
*/ */
static bool lessCycle = FALSE, lessCellCycle = FALSE; static bool lessCycle = FALSE, lessCellCycle = FALSE;
char path[200], *printPath, **msg, **optionArgs, *feedtext; char path[200], *printPath, **msg, **optionArgs, *feedtext, *pstr;
TerminalPath tpath; TerminalPath tpath;
CellUse *use; CellUse *use;
CellDef *rootBoxDef; CellDef *rootBoxDef;
@ -832,6 +844,7 @@ CmdSelect(w, cmd)
bool layerspec; bool layerspec;
bool degenerate; bool degenerate;
bool more = FALSE, less = FALSE, samePlace = TRUE; bool more = FALSE, less = FALSE, samePlace = TRUE;
unsigned char labelpolicy = SEL_DO_LABELS;
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
char *tclstr; char *tclstr;
Tcl_Obj *lobj; Tcl_Obj *lobj;
@ -851,7 +864,7 @@ CmdSelect(w, cmd)
/* See if "more" was given. If so, just strip off the "more" from /* See if "more" was given. If so, just strip off the "more" from
* the argument list and set the "more" flag. Similarly for options * 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) if (cmd->tx_argc >= 2)
@ -876,6 +889,7 @@ CmdSelect(w, cmd)
else if (!strncmp(cmd->tx_argv[1], "nocycle", arg1len)) else if (!strncmp(cmd->tx_argv[1], "nocycle", arg1len))
{ {
samePlace = FALSE; samePlace = FALSE;
labelpolicy = SEL_NO_LABELS;
more = FALSE; more = FALSE;
less = FALSE; less = FALSE;
type = TT_SELECTBASE - 1; /* avoid cycling between types */ type = TT_SELECTBASE - 1; /* avoid cycling between types */
@ -890,6 +904,24 @@ CmdSelect(w, cmd)
optionArgs = &cmd->tx_argv[2]; optionArgs = &cmd->tx_argv[2];
cmd->tx_argc--; 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)) else if (!strncmp(cmd->tx_argv[1], "top", arg1len))
{ {
@ -954,7 +986,7 @@ CmdSelect(w, cmd)
} }
if (!(more || less)) SelectClear(); if (!(more || less)) SelectClear();
if (cmd->tx_argc == 3) if (cmd->tx_argc == 3)
cmdSelectArea(optionArgs[1], less); cmdSelectArea(optionArgs[1], less, option);
else cmdSelectArea("*,label,subcell", less); else cmdSelectArea("*,label,subcell", less);
return; return;
@ -968,8 +1000,18 @@ CmdSelect(w, cmd)
if (cmd->tx_argc > 3) goto usageError; if (cmd->tx_argc > 3) goto usageError;
if (!(more || less)) SelectClear(); if (!(more || less)) SelectClear();
if (cmd->tx_argc == 3) if (cmd->tx_argc == 3)
cmdSelectVisible(optionArgs[1], less); cmdSelectArea(optionArgs[1], less, option);
else cmdSelectVisible("*,label,subcell", less); 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; return;
/*-------------------------------------------------------------------- /*--------------------------------------------------------------------
@ -982,6 +1024,14 @@ CmdSelect(w, cmd)
SelectClear(); SelectClear();
return; 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. * Print out help information.
*-------------------------------------------------------------------- *--------------------------------------------------------------------
@ -1526,6 +1576,13 @@ Okay:
DBWSetBox(scx.scx_use->cu_def, &r); DBWSetBox(scx.scx_use->cu_def, &r);
#ifdef MAGIC_WRAPPER #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); tclstr = Tcl_escape(printPath);
Tcl_SetResult(magicinterp, tclstr, TCL_DYNAMIC); Tcl_SetResult(magicinterp, tclstr, TCL_DYNAMIC);
#else #else
@ -1854,8 +1911,7 @@ cmdLabelFontFunc(label, cellUse, transform, font)
* Query or change properties of a (selected) label in the edit cell * Query or change properties of a (selected) label in the edit cell
* *
* Usage: * Usage:
* setlabel option [name] * setlabel [-default] option [name]
*
* *
* Option may be one of: * Option may be one of:
* text * text
@ -1875,6 +1931,11 @@ cmdLabelFontFunc(label, cellUse, transform, font)
* "setlabel font <name>" can be used without any select to load fonts * "setlabel font <name>" can be used without any select to load fonts
* from a startup script. * 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; TxCommand *cmd;
{ {
int pos = -1, font = -1, size = 0, rotate = 0, flags = 0; int pos = -1, font = -1, size = 0, rotate = 0, flags = 0;
int locargc, argstart = 1;
char **msg; char **msg;
Point offset; Point offset;
TileType ttype; TileType ttype;
int option; int option;
bool doDefault = FALSE;
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
Tcl_Obj *lobj; Tcl_Obj *lobj;
#endif #endif
@ -1921,10 +1984,34 @@ CmdSetLabel(w, cmd)
NULL 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; option = SETLABEL_HELP;
else else
option = Lookup(cmd->tx_argv[1], cmdLabelSetOption); option = Lookup(cmd->tx_argv[argstart], cmdLabelSetOption);
switch (option) switch (option)
{ {
@ -1943,20 +2030,27 @@ CmdSetLabel(w, cmd)
break; break;
case SETLABEL_TEXT: case SETLABEL_TEXT:
if (EditCellUse) if (doDefault)
{
TxError("Cannot set a default label text.\n");
}
else if (EditCellUse)
{ {
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL, SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelTextFunc, (cmd->tx_argc == 3) ? cmdLabelTextFunc, (locargc == 3) ?
(ClientData)cmd->tx_argv[2] : (ClientData)NULL); (ClientData)cmd->tx_argv[argstart + 1] : (ClientData)NULL);
} }
break; break;
case SETLABEL_FONT: 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 (font < -1 || font >= DBNumFonts)
{ {
if (DBNumFonts == 0) if (DBNumFonts == 0)
@ -1970,67 +2064,118 @@ CmdSetLabel(w, cmd)
else else
TxPrintf("%s\n", DBFontList[font]->mf_name); TxPrintf("%s\n", DBFontList[font]->mf_name);
} }
else if ((cmd->tx_argc == 3 || cmd->tx_argc == 4) && else if ((locargc == 3 || locargc == 4) &&
!StrIsInt(cmd->tx_argv[2])) !StrIsInt(cmd->tx_argv[argstart + 1]))
{ {
font = DBNameToFont(cmd->tx_argv[2]); font = DBNameToFont(cmd->tx_argv[argstart + 1]);
if (font < -1) if (font < -1)
{ {
float scale = 1.0; float scale = 1.0;
if ((cmd->tx_argc == 4) && StrIsNumeric(cmd->tx_argv[3])) if ((locargc == 4) && StrIsNumeric(cmd->tx_argv[argstart + 2]))
scale = (float)atof(cmd->tx_argv[3]); scale = (float)atof(cmd->tx_argv[argstart + 2]);
if (DBLoadFont(cmd->tx_argv[2], scale) != 0) if (DBLoadFont(cmd->tx_argv[argstart + 1], scale) != 0)
TxError("Error loading font \"%s\"\n", cmd->tx_argv[2]); TxError("Error loading font \"%s\"\n", cmd->tx_argv[argstart + 1]);
font = DBNameToFont(cmd->tx_argv[2]); font = DBNameToFont(cmd->tx_argv[argstart + 1]);
if (font < -1) break; 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, SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelFontFunc, (cmd->tx_argc == 3) ? cmdLabelFontFunc, (locargc == 3) ?
(ClientData)&font : (ClientData)NULL); (ClientData)&font : (ClientData)NULL);
} }
} }
break; break;
case SETLABEL_JUSTIFY: 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 (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, SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelJustFunc, (cmd->tx_argc == 3) ? cmdLabelJustFunc, (locargc == 3) ?
(ClientData)&pos : (ClientData)NULL); (ClientData)&pos : (ClientData)NULL);
} }
break; break;
case SETLABEL_SIZE: case SETLABEL_SIZE:
if (cmd->tx_argc == 3) if (locargc == 3)
{ {
if (StrIsNumeric(cmd->tx_argv[2])) if (StrIsNumeric(cmd->tx_argv[argstart + 1]))
size = cmdScaleCoord(w, cmd->tx_argv[2], TRUE, TRUE, 8); size = cmdScaleCoord(w, cmd->tx_argv[argstart + 1], TRUE, TRUE, 8);
if (size <= 0) break; 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, SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelSizeFunc, (cmd->tx_argc == 3) ? cmdLabelSizeFunc, (locargc == 3) ?
(ClientData)&size : (ClientData)NULL); (ClientData)&size : (ClientData)NULL);
} }
break; break;
case SETLABEL_OFFSET: case SETLABEL_OFFSET:
if (cmd->tx_argc == 3) if (locargc == 3)
{ {
char *yp; 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); offset.p_y = cmdScaleCoord(w, yp, TRUE, FALSE, 8);
} }
else else
@ -2039,67 +2184,138 @@ CmdSetLabel(w, cmd)
return; 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_x = cmdScaleCoord(w, cmd->tx_argv[argstart + 1], TRUE, TRUE, 8);
offset.p_y = cmdScaleCoord(w, cmd->tx_argv[3], TRUE, FALSE, 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, SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelOffsetFunc, (cmd->tx_argc != 2) ? cmdLabelOffsetFunc, (locargc != 2) ?
(ClientData)&offset : (ClientData)NULL); (ClientData)&offset : (ClientData)NULL);
} }
break; break;
case SETLABEL_ROTATE: case SETLABEL_ROTATE:
if (cmd->tx_argc == 3) if (locargc == 3)
{ {
if (StrIsInt(cmd->tx_argv[2])) if (StrIsInt(cmd->tx_argv[argstart + 1]))
rotate = atoi(cmd->tx_argv[2]); 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, SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelRotateFunc, (cmd->tx_argc == 3) ? cmdLabelRotateFunc, (locargc == 3) ?
(ClientData)&rotate : (ClientData)NULL); (ClientData)&rotate : (ClientData)NULL);
} }
break; break;
case SETLABEL_STICKY: 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) 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; break;
} }
flags = (option <= 3) ? 0 : LABEL_STICKY; 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, SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelStickyFunc, (cmd->tx_argc == 3) ? cmdLabelStickyFunc, (locargc == 3) ?
(ClientData)&flags : (ClientData)NULL); (ClientData)&flags : (ClientData)NULL);
} }
break; break;
case SETLABEL_LAYER: 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; ttype = -1;
else else
{ {
ttype = DBTechNoisyNameType(cmd->tx_argv[2]); ttype = DBTechNoisyNameType(cmd->tx_argv[argstart + 1]);
if (ttype < 0) break; 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, SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelLayerFunc, (cmd->tx_argc == 3) ? cmdLabelLayerFunc, (locargc == 3) ?
(ClientData)&ttype : (ClientData)NULL); (ClientData)&ttype : (ClientData)NULL);
} }
break; break;
@ -2113,7 +2329,7 @@ CmdSetLabel(w, cmd)
break; break;
default: default:
TxError("Unknown setlabel option \"%s\"\n", cmd->tx_argv[1]); TxError("Unknown setlabel option \"%s\"\n", cmd->tx_argv[argstart]);
break; break;
} }
} }

View File

@ -825,7 +825,6 @@ int cmdWhatPrintCell(tile, cxp)
} }
if (curlid == NULL) if (curlid == NULL)
{ {
TxPrintf(" %s ", CurrCellName);
curlid = (struct linked_id *)mallocMagic(sizeof(struct linked_id)); curlid = (struct linked_id *)mallocMagic(sizeof(struct linked_id));
curlid->lid_name = CurrCellName; curlid->lid_name = CurrCellName;
curlid->lid_next = *lid; curlid->lid_next = *lid;
@ -844,6 +843,41 @@ typedef struct labelstore
static int moreLabelEntries, labelEntryCount; static int moreLabelEntries, labelEntryCount;
static LabelStore *labelBlockTop, *labelEntry; 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. * Print out information about what's selected.
* *
* Usage: * Usage:
* what [-list] * what [-list[all]]
* *
* Results: * Results:
* None. * None.
@ -861,7 +895,8 @@ static LabelStore *labelBlockTop, *labelEntry;
* Information gets printed to identify the kinds of paint, plus * Information gets printed to identify the kinds of paint, plus
* labels and subcells, that are selected. * labels and subcells, that are selected.
* In the TCL version, the "-list" option puts the result in a * 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; int i, locargc;
bool foundAny; bool foundAny;
bool doList = FALSE; bool doList = FALSE, doListAll = FALSE;
TileTypeBitMask layers, maskBits, *rMask; TileTypeBitMask layers, maskBits, *rMask;
SearchContext scx;
CellUse *CheckUse; CellUse *CheckUse;
struct linked_id *lid;
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
Tcl_Obj *lobj, *paintobj, *labelobj, *cellobj; Tcl_Obj *lobj, *paintobj, *paintcellobj, *celllistobj, *labelobj, *cellobj;
extern int cmdWhatCellListFunc(); extern int cmdWhatCellListFunc();
#endif #endif
@ -890,14 +923,20 @@ CmdWhat(w, cmd)
locargc = cmd->tx_argc; locargc = cmd->tx_argc;
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
if ((locargc == 2) && !strncmp(cmd->tx_argv[locargc - 1], "-list", 5)) if (locargc == 2)
{ {
doList = TRUE; if (!strncmp(cmd->tx_argv[locargc - 1], "-list", 5))
locargc--; {
lobj = Tcl_NewListObj(0, NULL); if (!strncmp(cmd->tx_argv[locargc - 1], "-listall", 8))
paintobj = Tcl_NewListObj(0, NULL); doListAll = TRUE;
labelobj = Tcl_NewListObj(0, NULL); else
cellobj = Tcl_NewListObj(0, NULL); 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) if (locargc > 1)
{ {
@ -959,29 +998,69 @@ CmdWhat(w, cmd)
} }
if ((CheckUse != NULL) && (CheckUse->cu_def == SelectRootDef)) if ((CheckUse != NULL) && (CheckUse->cu_def == SelectRootDef))
{ {
scx.scx_use = CheckUse; CellUse *saveUse = EditCellUse;
scx.scx_area = SelectUse->cu_bbox; // BSI struct linked_id *lid, *lidp;
scx.scx_trans = GeoIdentityTransform; // BSI int pNum;
TxPrintf("Selected mask layers:\n"); EditCellUse = CheckUse;
if (!doListAll) TxPrintf("Selected mask layers:\n");
for (i = TT_SELECTBASE; i < DBNumUserLayers; i++) for (i = TT_SELECTBASE; i < DBNumUserLayers; i++)
{ {
if (TTMaskHasType(&layers, i)) if (TTMaskHasType(&layers, i))
{ {
lid = NULL;
TxPrintf(" %-8s (", DBTypeLongName(i));
TTMaskSetOnlyType(&maskBits, i); TTMaskSetOnlyType(&maskBits, i);
if (DBIsContact(i)) DBMaskAddStacking(&maskBits); if (DBIsContact(i)) DBMaskAddStacking(&maskBits);
DBTreeSrTiles(&scx, &maskBits, 0, cmdWhatPrintCell,
(ClientData)&lid); if (doListAll) paintcellobj = Tcl_NewListObj(0, NULL);
TxPrintf(")\n");
while (lid != 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); TxPrintf(" %-8s (", DBTypeLongName(i));
lid = lid->lid_next; 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 else
{ {
@ -1008,7 +1087,7 @@ CmdWhat(w, cmd)
qsort(labelBlockTop, labelEntryCount, sizeof(LabelStore), orderLabelFunc); qsort(labelBlockTop, labelEntryCount, sizeof(LabelStore), orderLabelFunc);
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
if (doList) if (doList || doListAll)
{ {
Tcl_Obj *newtriple; Tcl_Obj *newtriple;
for (labelEntry = labelBlockTop; labelEntryCount-- > 0; labelEntry++) for (labelEntry = labelBlockTop; labelEntryCount-- > 0; labelEntry++)
@ -1052,7 +1131,7 @@ CmdWhat(w, cmd)
foundAny = FALSE; foundAny = FALSE;
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
if (doList) if (doList || doListAll)
SelEnumCells(FALSE, (bool *) NULL, (SearchContext *) NULL, SelEnumCells(FALSE, (bool *) NULL, (SearchContext *) NULL,
cmdWhatCellListFunc, (ClientData) cellobj); cmdWhatCellListFunc, (ClientData) cellobj);
else else
@ -1061,7 +1140,7 @@ CmdWhat(w, cmd)
cmdWhatCellFunc, (ClientData) &foundAny); cmdWhatCellFunc, (ClientData) &foundAny);
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
if (doList) if (doList || doListAll)
{ {
Tcl_ListObjAppendElement(magicinterp, lobj, paintobj); Tcl_ListObjAppendElement(magicinterp, lobj, paintobj);
Tcl_ListObjAppendElement(magicinterp, lobj, labelobj); Tcl_ListObjAppendElement(magicinterp, lobj, labelobj);
@ -1926,7 +2005,7 @@ CmdXor(w, cmd)
PaintResultType DBXORResultTbl[NP][NT][NT]; PaintResultType DBXORResultTbl[NP][NT][NT];
PaintResultType (*curPaintSave)[NT][NT]; PaintResultType (*curPaintSave)[NT][NT];
void (*curPlaneSave)(); int (*curPlaneSave)();
int p, t, h; int p, t, h;

View File

@ -118,6 +118,7 @@ DBCellFindDup(use, parent)
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
* DBPlaceCell -- * DBPlaceCell --
* DBPlaceCellNoModify --
* *
* Add a CellUse to the subcell tile plane of a CellDef. * Add a CellUse to the subcell tile plane of a CellDef.
* Assumes prior check that the new CellUse is not an exact duplicate * Assumes prior check that the new CellUse is not an exact duplicate
@ -162,11 +163,47 @@ DBPlaceCell (use, def)
SigEnableInterrupts(); 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 -- * DBDeleteCell --
* *
* Remove a CellUse from the subcell tile plane of a CellDef. * 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: * Results:
* None. * None.
@ -197,3 +234,39 @@ DBDeleteCell (use)
SigEnableInterrupts(); 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();
}

View File

@ -723,7 +723,7 @@ dbReComputeBboxFunc(cellDef, boundProc, recurseProc)
*/ */
parent = use->cu_parent; parent = use->cu_parent;
DBDeleteCell(use); DBDeleteCellNoModify(use);
use->cu_parent = parent; use->cu_parent = parent;
} }
@ -751,7 +751,7 @@ dbReComputeBboxFunc(cellDef, boundProc, recurseProc)
if ((parent = use->cu_parent) != (CellDef *) NULL) if ((parent = use->cu_parent) != (CellDef *) NULL)
{ {
parent->cd_flags |= CDBOXESCHANGED; parent->cd_flags |= CDBOXESCHANGED;
DBPlaceCell(use, parent); DBPlaceCellNoModify(use, parent);
if (last != parent) if (last != parent)
{ {
if (last != NULL) (*recurseProc)(last); if (last != NULL) (*recurseProc)(last);

View File

@ -342,6 +342,214 @@ DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func)
DBTreeSrTiles(scx, &locMask, xMask, dbCopyAllPaint, (ClientData) &arg); 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_mask = mask;
arg.caa_targetUse = targetUse; arg.caa_targetUse = targetUse;
arg.caa_func = NULL;
GeoTransRect(&scx->scx_trans, &scx->scx_area, &arg.caa_rect); GeoTransRect(&scx->scx_trans, &scx->scx_area, &arg.caa_rect);
/* Build dummy TreeContext */ /* Build dummy TreeContext */

View File

@ -21,7 +21,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#endif /* not lint */ #endif /* not lint */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> /* for qsort() */
#include <string.h> #include <string.h>
#include <ctype.h>
#include "tcltk/tclmagic.h" #include "tcltk/tclmagic.h"
#include "utils/magic.h" #include "utils/magic.h"
@ -271,6 +273,7 @@ DBCellDelete(cellname, force)
} }
celldef->cd_parents = (CellUse *)NULL; celldef->cd_parents = (CellUse *)NULL;
DBWResetBox(celldef);
result = DBCellDeleteDef(celldef); result = DBCellDeleteDef(celldef);
if (result == FALSE) if (result == FALSE)
@ -280,8 +283,6 @@ DBCellDelete(cellname, force)
return result; 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; int who;
bool dolist; bool dolist;
{ {
int found; int found, numcells;
HashSearch hs; HashSearch hs;
HashEntry *entry; HashEntry *entry;
CellDef *celldef; CellDef *celldef;
CellUse *celluse; CellUse *celluse;
char **celllist;
if (!dolist) if (!dolist)
{ {
@ -657,6 +720,11 @@ DBCellPrint(CellName, who, dolist)
* CDMODIFIED flag set. * CDMODIFIED flag set.
*/ */
numcells = dbCellDefTable.ht_nEntries;
if (numcells == 0) numcells = 1;
celllist = (char **)mallocMagic(numcells * sizeof(char *));
numcells = 0;
HashStartSearch(&hs); HashStartSearch(&hs);
while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL) while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
{ {
@ -666,28 +734,39 @@ DBCellPrint(CellName, who, dolist)
if (((celldef->cd_flags & CDINTERNAL) != CDINTERNAL) && if (((celldef->cd_flags & CDINTERNAL) != CDINTERNAL) &&
((who != MODIFIED) || ((who != MODIFIED) ||
(celldef->cd_flags & CDMODIFIED))) (celldef->cd_flags & CDMODIFIED)))
{
if (celldef->cd_name != NULL) if (celldef->cd_name != NULL)
{ celllist[numcells++] = celldef->cd_name;
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);
}
}
} }
} }
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; break;
case TOPCELLS: 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); HashStartSearch(&hs);
while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL) while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
{ {
@ -712,19 +791,25 @@ DBCellPrint(CellName, who, dolist)
} }
} }
if ( (found == 0) && (celldef->cd_name != NULL) ) if ( (found == 0) && (celldef->cd_name != NULL) )
{ celllist[numcells++] = celldef->cd_name;
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);
}
} }
} }
} }
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; break;
default: default:

View File

@ -29,8 +29,10 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/geometry.h" #include "utils/geometry.h"
#include "tiles/tile.h" #include "tiles/tile.h"
#include "utils/hash.h" #include "utils/hash.h"
#include "utils/stack.h"
#include "database/database.h" #include "database/database.h"
#include "database/databaseInt.h" #include "database/databaseInt.h"
#include "select/select.h"
#include "utils/signals.h" #include "utils/signals.h"
#include "utils/malloc.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. * 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 -- * DBTransformDiagonal --
@ -255,6 +208,7 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
startTile = NULL; startTile = NULL;
for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++) for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
{ {
csa.csa_pNum = startPlane;
if (DBSrPaintArea((Tile *) NULL, if (DBSrPaintArea((Tile *) NULL,
def->cd_planes[startPlane], startArea, mask, def->cd_planes[startPlane], startArea, mask,
dbSrConnectStartFunc, (ClientData) &startTile) != 0) break; dbSrConnectStartFunc, (ClientData) &startTile) != 0) break;
@ -270,7 +224,6 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
csa.csa_clientData = clientData; csa.csa_clientData = clientData;
csa.csa_clear = FALSE; csa.csa_clear = FALSE;
csa.csa_connect = connect; csa.csa_connect = connect;
csa.csa_plane = startPlane;
if (dbSrConnectFunc(startTile, &csa) != 0) result = 1; if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
/* Pass 2. Don't call any client function, just clear the marks. /* 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(); SigDisableInterrupts();
csa.csa_clientFunc = NULL; csa.csa_clientFunc = NULL;
csa.csa_clear = TRUE; csa.csa_clear = TRUE;
csa.csa_plane = startPlane;
(void) dbSrConnectFunc(startTile, &csa); (void) dbSrConnectFunc(startTile, &csa);
SigEnableInterrupts(); SigEnableInterrupts();
@ -346,6 +298,7 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
startTile = NULL; startTile = NULL;
for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++) for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
{ {
csa.csa_pNum = startPlane;
if (DBSrPaintArea((Tile *) NULL, if (DBSrPaintArea((Tile *) NULL,
def->cd_planes[startPlane], startArea, mask, def->cd_planes[startPlane], startArea, mask,
dbSrConnectStartFunc, (ClientData) &startTile) != 0) break; dbSrConnectStartFunc, (ClientData) &startTile) != 0) break;
@ -361,7 +314,6 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
csa.csa_clientData = clientData; csa.csa_clientData = clientData;
csa.csa_clear = FALSE; csa.csa_clear = FALSE;
csa.csa_connect = connect; csa.csa_connect = connect;
csa.csa_plane = startPlane;
if (dbSrConnectFunc(startTile, &csa) != 0) result = 1; if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
return result; return result;
@ -434,7 +386,7 @@ dbSrConnectFunc(tile, csa)
if (csa->csa_clientFunc != NULL) 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; return 1;
} }
@ -577,7 +529,7 @@ donesides:
*/ */
planes = DBConnPlanes[loctype]; planes = DBConnPlanes[loctype];
planes &= ~(PlaneNumToMaskBit(csa->csa_plane)); planes &= ~(PlaneNumToMaskBit(csa->csa_pNum));
if (planes != 0) if (planes != 0)
{ {
struct conSrArg newcsa; struct conSrArg newcsa;
@ -589,7 +541,7 @@ donesides:
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++) for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
{ {
if (!PlaneMaskHasPlane(planes, i)) continue; if (!PlaneMaskHasPlane(planes, i)) continue;
newcsa.csa_plane = i; newcsa.csa_pNum = i;
if (IsSplit(tile)) if (IsSplit(tile))
{ {
if (DBSrPaintNMArea((Tile *) NULL, csa->csa_def->cd_planes[i], if (DBSrPaintNMArea((Tile *) NULL, csa->csa_def->cd_planes[i],
@ -653,7 +605,7 @@ dbcUnconnectFunc(tile, clientData)
* connectivity between them. * connectivity between them.
* *
* Results: * Results:
* Always 0. * Return 0 normally, 1 if list size exceeds integer bounds.
* *
* Side effects: * Side effects:
* Adds a label to the destination definition "def". * 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; int newllen = tpath->tp_next - tpath->tp_first;
newlabtext[0] = '\0'; newlabtext[0] = '\0';
if (newllen > 0) if (tpath->tp_first == NULL)
strncpy(newlabtext, tpath->tp_first, newllen); newlabptr = lab->lab_text;
sprintf(newlabtext + newllen, "%s", lab->lab_text); else
newlabptr = newlabtext; {
if (newllen > 0)
strncpy(newlabtext, tpath->tp_first, newllen);
sprintf(newlabtext + newllen, "%s", lab->lab_text);
newlabptr = newlabtext;
}
} }
else return 0; else return 0;
} }
@ -734,7 +691,7 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
if ((slab->lab_flags & PORT_NUM_MASK) == lidx) if ((slab->lab_flags & PORT_NUM_MASK) == lidx)
{ {
Rect newarea; Rect newarea;
int pNum; int i, pNum;
// Do NOT go searching on labels connected to space! // Do NOT go searching on labels connected to space!
if (slab->lab_type == TT_SPACE) continue; if (slab->lab_type == TT_SPACE) continue;
@ -757,24 +714,29 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
newarea.r_ybot--; newarea.r_ybot--;
newarea.r_ytop++; 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 */ /* 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 */ /* Reached list size limit---need to push the list and */
/* Double the size of the list every time we hit the limit */ /* start a new one. */
conSrArea *newlist; conSrArea *newlist;
int i, lastsize = csa2->csa2_size;
csa2->csa2_size *= 2; newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE *
sizeof(conSrArea));
newlist = (conSrArea *)mallocMagic(csa2->csa2_size StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
* sizeof(conSrArea));
memcpy((void *)newlist, (void *)csa2->csa2_list,
(size_t)lastsize * sizeof(conSrArea));
freeMagic((char *)csa2->csa2_list);
csa2->csa2_list = newlist; csa2->csa2_list = newlist;
csa2->csa2_top = 0;
} }
csa2->csa2_list[csa2->csa2_top].area = newarea; csa2->csa2_list[csa2->csa2_top].area = newarea;
@ -805,7 +767,8 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
* catecorner tiles from being considered as connected. * catecorner tiles from being considered as connected.
* *
* Results: * 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: * Side effects:
* Adds paint to the destination definition. * Adds paint to the destination definition.
@ -829,7 +792,7 @@ dbcConnectFunc(tile, cx)
SearchContext scx2; SearchContext scx2;
TileType loctype = TiGetTypeExact(tile); TileType loctype = TiGetTypeExact(tile);
TileType dinfo = 0; TileType dinfo = 0;
int pNum = cx->tc_plane; int i, pNum = cx->tc_plane;
CellDef *def; CellDef *def;
TiToRect(tile, &tileArea); TiToRect(tile, &tileArea);
@ -942,23 +905,29 @@ dbcConnectFunc(tile, cx)
newarea.r_xtop += 1; 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 */ /* 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 */ /* Reached list size limit---need to push the list and */
/* Double the size of the list every time we hit the limit */ /* start a new one. */
conSrArea *newlist; conSrArea *newlist;
int i, lastsize = csa2->csa2_size;
csa2->csa2_size *= 2; newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
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);
csa2->csa2_list = newlist; csa2->csa2_list = newlist;
csa2->csa2_top = 0;
} }
csa2->csa2_list[csa2->csa2_top].area = newarea; csa2->csa2_list[csa2->csa2_top].area = newarea;
@ -968,7 +937,6 @@ dbcConnectFunc(tile, cx)
return 0; return 0;
} }
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -1019,9 +987,10 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse)
* clipped to this area. Pass * clipped to this area. Pass
* TiPlaneRect to get everything. * TiPlaneRect to get everything.
*/ */
bool doLabels; /* If TRUE, copy connected labels unsigned char doLabels; /* If SEL_DO_LABELS, copy connected labels
* and paint. If FALSE, copy only * and paint. If SEL_NO_LABELS, copy only
* connected paint. * connected paint. If SEL_SIMPLE_LABELS,
* copy only root of labels in subcircuits.
*/ */
CellUse *destUse; /* Result use in which to place CellUse *destUse; /* Result use in which to place
* anything connected to material of * anything connected to material of
@ -1034,7 +1003,6 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse)
unsigned char searchtype; unsigned char searchtype;
csa2.csa2_use = destUse; csa2.csa2_use = destUse;
csa2.csa2_xMask = xMask;
csa2.csa2_bounds = area; csa2.csa2_bounds = area;
csa2.csa2_connect = connect; csa2.csa2_connect = connect;
csa2.csa2_topscx = scx; 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 */ /* malloc calls by maintaining a small list and expanding it only */
/* when necessary. */ /* when necessary. */
csa2.csa2_size = CSA2_LIST_START_SIZE; csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_START_SIZE
* sizeof(conSrArea));
csa2.csa2_top = -1; csa2.csa2_top = -1;
csa2.csa2_lasttop = -1;
csa2.csa2_stack = StackNew(100);
DBTreeSrTiles(scx, mask, xMask, dbcConnectFunc, (ClientData) &csa2); DBTreeSrTiles(scx, mask, xMask, dbcConnectFunc, (ClientData) &csa2);
while (csa2.csa2_top >= 0) 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; newmask = csa2.csa2_list[csa2.csa2_top].connectMask;
scx->scx_area = csa2.csa2_list[csa2.csa2_top].area; scx->scx_area = csa2.csa2_list[csa2.csa2_top].area;
newtype = csa2.csa2_list[csa2.csa2_top].dinfo; 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) if (newtype & TT_DIAGONAL)
DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFunc, DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFunc,
(ClientData) &csa2); (ClientData) &csa2);
else 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 */ /* Check the source def for any labels belonging to this */
/* tile area and plane, and add them to the destination. */ /* 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; searchtype |= TF_LABEL_ATTACH_NOT_SE;
} }
} }
if (doLabels) if (doLabels == SEL_SIMPLE_LABELS) tpath.tp_first = NULL;
DBTreeSrLabels(scx, newmask, xMask, &tpath, searchtype, if (doLabels != SEL_NO_LABELS)
dbcConnectLabelFunc, (ClientData) &csa2); 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); freeMagic((char *)csa2.csa2_list);
StackFree(csa2.csa2_stack);
/* Recompute the bounding box of the destination and record its area /* Recompute the bounding box of the destination and record its area
* for redisplay. * for redisplay.

View File

@ -135,6 +135,132 @@ file_is_not_writeable(name)
return(0); 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; int cellStamp = 0, rectCount = 0, rectReport = 10000;
char line[2048], tech[50], layername[50]; char line[2048], tech[50], layername[50];
PaintResultType *ptable; PaintResultType *ptable;
bool result = TRUE, scaleLimit = FALSE; bool result = TRUE, scaleLimit = FALSE, has_mismatch;
Rect *rp; Rect *rp;
int c; int c;
TileType type, rtype, loctype; TileType type, rtype, loctype;
@ -335,13 +461,122 @@ dbCellReadDef(f, cellDef, name, ignoreTech, dereference)
TxPrintf("Will attempt to read cell anyway.\n"); TxPrintf("Will attempt to read cell anyway.\n");
else else
{ {
TxError("Use command \"tech load\" if you want to switch" /* If no cells are currently in memory, then make an
" technologies, or use\n"); * attempt to find the technology associated with the
TxError("\"cellname delete %s\" and \"load %s -force\" to" * layout and load it.
" force the cell to load as technology %s\n", */
cellDef->cd_name, cellDef->cd_name, DBTechName);
SigEnableInterrupts(); if (!CmdCheckForPaintFunc())
return (FALSE); {
/* 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) if (dbFgets(line, sizeof line, f) == NULL)
@ -609,6 +844,7 @@ done:
* timestamp, then force the cell to be written out with a * timestamp, then force the cell to be written out with a
* correct timestamp. * correct timestamp.
*/ */
has_mismatch = FALSE;
if ((cellDef->cd_timestamp != cellStamp) || (cellStamp == 0)) if ((cellDef->cd_timestamp != cellStamp) || (cellStamp == 0))
{ {
CellUse *cu; CellUse *cu;
@ -617,12 +853,13 @@ done:
if (cu->cu_parent != NULL) if (cu->cu_parent != NULL)
{ {
DBStampMismatch(cellDef, &cellDef->cd_bbox); DBStampMismatch(cellDef, &cellDef->cd_bbox);
has_mismatch = TRUE;
break; break;
} }
} }
} }
/* Update timestamp flags */ /* Update timestamp flags */
DBFlagMismatches(cellDef); if (has_mismatch) DBFlagMismatches(cellDef);
cellDef->cd_timestamp = cellStamp; cellDef->cd_timestamp = cellStamp;
if (cellStamp == 0) if (cellStamp == 0)
@ -634,7 +871,8 @@ done:
} }
UndoEnable(); 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(); SigEnableInterrupts();
return (result); return (result);
@ -3167,6 +3405,105 @@ dbClearCellFunc(cellUse, cdarg)
return 0; 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; struct writeArg *arg = (struct writeArg *) cdarg;
Transform *t; Transform *t;
Rect *b; Rect *b;
bool subbed = FALSE; char cstring[1024], *pathend, *pathstart, *parent;
char cstring[256], *pathend, *pathstart, *parent;
t = &(cellUse->cu_transform); t = &(cellUse->cu_transform);
b = &(cellUse->cu_def->cd_bbox); b = &(cellUse->cu_def->cd_bbox);
@ -3244,92 +3580,13 @@ dbWriteCellFunc(cellUse, cdarg)
} }
else else
{ {
#ifdef MAGIC_WRAPPER sprintf(cstring, "use %s %c%s ", cellUse->cu_def->cd_name,
char *tvar; (cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
cellUse->cu_id);
/* Check for the leading component of the file path being equal to */ DBPathSubstitute(pathstart, cstring + strlen(cstring), cellUse->cu_def);
/* one of several common variable names for the PDK location, and */ strcat(cstring, "\n");
/* 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);
}
}
} }
FPRINTR(arg->wa_file, cstring); FPRINTR(arg->wa_file, cstring);
cellUse->cu_def->cd_flags |= CDVISITED; cellUse->cu_def->cd_flags |= CDVISITED;

View File

@ -2573,7 +2573,7 @@ DBPaintPlaneVert(plane, area, resultTbl, undo)
Tile *newtile, *tp; /* Used for paint */ Tile *newtile, *tp; /* Used for paint */
if (area->r_xtop <= area->r_xbot || area->r_ytop <= area->r_ybot) 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 * The following is a modified version of the area enumeration
@ -2798,6 +2798,7 @@ paintdone:
done: done:
plane->pl_hint = tile; plane->pl_hint = tile;
return 0;
} }
/* /*

View File

@ -83,6 +83,15 @@ DBPropPut(cellDef, name, value)
cellDef->cd_flags |= CDFIXEDBBOX; 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); entry = HashFind(htab, name);
oldvalue = (char *)HashGetValue(entry); oldvalue = (char *)HashGetValue(entry);
if (oldvalue != NULL) freeMagic(oldvalue); if (oldvalue != NULL) freeMagic(oldvalue);

View File

@ -425,7 +425,8 @@ DBTechFinalConnect()
for (n = 0; n < dbNumContacts; n++) for (n = 0; n < dbNumContacts; n++)
{ {
lp = dbContactInfo[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); rMask = DBResidueMask(lp->l_type);
/* Different contact types may share residues. */ /* Different contact types may share residues. */

View File

@ -33,6 +33,10 @@
#include "utils/hash.h" #include "utils/hash.h"
#endif /* _HASH_H */ #endif /* _HASH_H */
#ifndef _STACK_H
#include "utils/stack.h"
#endif /* _STACK_H */
#ifndef _BPLANE_H #ifndef _BPLANE_H
#include "bplane/bplane.h" #include "bplane/bplane.h"
#endif /* _BPLANE_H */ #endif /* _BPLANE_H */
@ -658,6 +662,54 @@ typedef struct treeFilter
/* To do: Make the tpath entries dynamically allocated */ /* To do: Make the tpath entries dynamically allocated */
#define FLATTERMSIZE 4096 /* Used for generating flattened labels */ #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 ------------- */ /* -------------- Undo information passed to DBPaintPlane ------------- */
typedef struct typedef struct
@ -725,6 +777,7 @@ extern void DBFileRecovery();
extern bool DBWriteBackup(); extern bool DBWriteBackup();
extern bool DBReadBackup(); extern bool DBReadBackup();
extern void DBRemoveBackup(); extern void DBRemoveBackup();
extern void DBPathSubstitute();
/* Labels */ /* Labels */
extern Label *DBPutLabel(); extern Label *DBPutLabel();
@ -790,7 +843,9 @@ extern CellUse *DBFindUse();
/* Insertion/deletion of cell uses into the cell tile plane of a parent */ /* Insertion/deletion of cell uses into the cell tile plane of a parent */
extern void DBPlaceCell(); extern void DBPlaceCell();
extern void DBPlaceCellNoModify();
extern void DBDeleteCell(); extern void DBDeleteCell();
extern void DBDeleteCellNoModify();
extern void DBClearCellPlane(); extern void DBClearCellPlane();
/* Insertion/deletion of cell uses into the name space of a parent */ /* Insertion/deletion of cell uses into the name space of a parent */
@ -821,6 +876,7 @@ extern void DBCellCopyLabels();
extern void DBCellCopyAllLabels(); extern void DBCellCopyAllLabels();
extern void DBCellCopyCells(); extern void DBCellCopyCells();
extern void DBCellCopyAllCells(); extern void DBCellCopyAllCells();
extern Plane *DBCellGenerateSubstrate();
/* Contact image handling */ /* Contact image handling */
extern TileType DBPlaneToResidue(); extern TileType DBPlaneToResidue();

View File

@ -42,7 +42,7 @@ extern void CmdAddPath(), CmdAntennaCheck(), CmdArray();
extern void CmdBox(), CmdCellname(), CmdClockwise(); extern void CmdBox(), CmdCellname(), CmdClockwise();
extern void CmdContact(), CmdCopy(), CmdCorner(); extern void CmdContact(), CmdCopy(), CmdCorner();
extern void CmdCrash(), CmdCrosshair(); 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 CmdEdit(), CmdElement(), CmdErase(), CmdExpand(), CmdExtract();
extern void CmdFeedback(), CmdFill(), CmdFindBox(), CmdFindLabel(), CmdFlush(); extern void CmdFeedback(), CmdFill(), CmdFindBox(), CmdFindLabel(), CmdFlush();
extern void CmdGetcell(), CmdGrid(), CmdIdentify(); extern void CmdGetcell(), CmdGrid(), CmdIdentify();
@ -278,6 +278,10 @@ DBWInitCommands()
"drc option design rule checker; type \"drc help\"\n" "drc option design rule checker; type \"drc help\"\n"
" for information on options", " for information on options",
CmdDrc, FALSE); CmdDrc, FALSE);
WindAddCommand(DBWclientID,
"drop layers copy layers from edit cell into\n"
" subcells containing selected paint",
CmdDrop, FALSE);
WindAddCommand(DBWclientID, WindAddCommand(DBWclientID,
"dump cell [child refPointC] [parent refPointP]\n\ "dump cell [child refPointC] [parent refPointP]\n\
copy contents of cell into edit cell, so that\n\ copy contents of cell into edit cell, so that\n\

View File

@ -790,6 +790,31 @@ DBWSetBox(rootDef, rect)
dbwRecordBoxArea(FALSE); 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 -- * ToolMoveBox --

View File

@ -189,6 +189,7 @@ extern void ToolMoveBox(), ToolMoveCorner();
extern int ToolGetCorner(); extern int ToolGetCorner();
extern void DBWloadWindow(), DBWxloadWindow(); extern void DBWloadWindow(), DBWxloadWindow();
extern void DBWSetBox(); extern void DBWSetBox();
extern void DBWResetBox();
extern void DBWUndoOldEdit(); extern void DBWUndoOldEdit();
extern void DBWUndoNewEdit(); extern void DBWUndoNewEdit();

View File

@ -105,7 +105,7 @@ drcArrayFunc(scx, arg)
int xsep, ysep; int xsep, ysep;
int xsize, ysize; int xsize, ysize;
int rval, oldTiles; int rval, oldTiles;
Rect errorArea, yankArea, tmp, tmp2; Rect errorArea, yankArea, tmp, tmp2, saveClip;
DRCCookie *save_cptr; DRCCookie *save_cptr;
CellUse *use = scx->scx_use; CellUse *use = scx->scx_use;
Rect *area; Rect *area;
@ -114,7 +114,7 @@ drcArrayFunc(scx, arg)
ClientData drcArrayClientData; /* Extra parameter to pass to func. */ ClientData drcArrayClientData; /* Extra parameter to pass to func. */
PaintResultType (*savedPaintTable)[NT][NT]; PaintResultType (*savedPaintTable)[NT][NT];
PaintResultType (*savedEraseTable)[NT][NT]; PaintResultType (*savedEraseTable)[NT][NT];
void (*savedPaintPlane)(); int (*savedPaintPlane)();
if ((use->cu_xlo == use->cu_xhi) && (use->cu_ylo == use->cu_yhi)) if ((use->cu_xlo == use->cu_xhi) && (use->cu_ylo == use->cu_yhi))
return 2; return 2;
@ -183,6 +183,8 @@ drcArrayFunc(scx, arg)
(ClientData) &yankArea); (ClientData) &yankArea);
drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea, drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea,
drcArrayErrorFunc, drcArrayClientData); drcArrayErrorFunc, drcArrayClientData);
*arg->dCD_clip = *area;
GeoClip(arg->dCD_clip, &yankArea);
(void) DBArraySr(use, &errorArea, drcArrayOverlapFunc, (void) DBArraySr(use, &errorArea, drcArrayOverlapFunc,
(ClientData) arg); (ClientData) arg);
} }
@ -200,6 +202,8 @@ drcArrayFunc(scx, arg)
(ClientData) &yankArea); (ClientData) &yankArea);
drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea, drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea,
drcArrayErrorFunc, drcArrayClientData); drcArrayErrorFunc, drcArrayClientData);
*arg->dCD_clip = *area;
GeoClip(arg->dCD_clip, &yankArea);
(void) DBArraySr(use, &errorArea, drcArrayOverlapFunc, (void) DBArraySr(use, &errorArea, drcArrayOverlapFunc,
(ClientData) arg); (ClientData) arg);
} }
@ -222,6 +226,8 @@ drcArrayFunc(scx, arg)
(ClientData) &yankArea); (ClientData) &yankArea);
drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea, drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea,
drcArrayErrorFunc, drcArrayClientData); drcArrayErrorFunc, drcArrayClientData);
*arg->dCD_clip = *area;
GeoClip(arg->dCD_clip, &yankArea);
(void) DBArraySr(use, &errorArea, drcArrayOverlapFunc, (void) DBArraySr(use, &errorArea, drcArrayOverlapFunc,
(ClientData) arg); (ClientData) arg);
} }
@ -239,11 +245,16 @@ drcArrayFunc(scx, arg)
(ClientData) &yankArea); (ClientData) &yankArea);
drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea, drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea,
drcArrayErrorFunc, drcArrayClientData); drcArrayErrorFunc, drcArrayClientData);
*arg->dCD_clip = *area;
GeoClip(arg->dCD_clip, &yankArea);
(void) DBArraySr(use, &errorArea, drcArrayOverlapFunc, (void) DBArraySr(use, &errorArea, drcArrayOverlapFunc,
(ClientData) arg); (ClientData) arg);
} }
} }
/* Restore original clip rect */
*arg->dCD_clip = *area;
(void) DBNewPaintTable(savedPaintTable); (void) DBNewPaintTable(savedPaintTable);
(void) DBNewPaintPlane(savedPaintPlane); (void) DBNewPaintPlane(savedPaintPlane);

View File

@ -26,6 +26,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <sys/types.h> #include <sys/types.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> // for memcpy() #include <string.h> // for memcpy()
#include <math.h> // for sqrt() for diagonal check
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "tiles/tile.h" #include "tiles/tile.h"
@ -268,6 +269,47 @@ areaCheck(tile, arg)
return 0; 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)) if (IsSplit(tile))
{ {
int deltax, deltay;
TileType tt, to;
/* Check rules for DRC_ANGLES rule and process */ /* Check rules for DRC_ANGLES rule and process */
TileType tt = TiGetLeftType(tile); tt = TiGetLeftType(tile);
if (tt != TT_SPACE) if (tt != TT_SPACE)
{ {
for (cptr = DRCCurStyle->DRCRulesTbl[TT_SPACE][tt]; 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 */ /* Full check of edge rules along the diagonal. */
if (SplitSide(tile)) goto checkbottom; 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) else if (cptr->drcc_flags & DRC_MAXWIDTH)
{ {
/* bends_illegal option only */ if (cptr->drcc_flags & DRC_MAXWIDTH_BOTH)
if (firsttile) {
drcCheckMaxwidth(tile, arg, cptr); if (firsttile)
drcCheckMaxwidth(tile, arg, cptr, TRUE);
}
else
{
/* bends_illegal option only */
if (firsttile)
drcCheckMaxwidth(tile, arg, cptr, FALSE);
}
continue; continue;
} }
@ -671,8 +814,8 @@ drcTile (tile, arg)
else tpl = tpleft; else tpl = tpleft;
/* Make sure the edge stops at edgeBot */ /* Make sure the edge stops at edgeBot */
if ((TiGetTopType(tpl) != TiGetBottomType(tpleft)) || if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
(TiGetTopType(tpr) != TiGetBottomType(tile))) (TiGetLeftType(tpr) != TiGetLeftType(tile)))
{ {
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpr))) if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpr)))
{ {
@ -698,8 +841,8 @@ drcTile (tile, arg)
else tpl = tpleft; else tpl = tpleft;
/* Make sure the edge stops at edgeTop */ /* Make sure the edge stops at edgeTop */
if ((TiGetBottomType(tpl) != TiGetTopType(tpleft)) || if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
(TiGetBottomType(tpr) != TiGetTopType(tile))) (TiGetLeftType(tpr) != TiGetLeftType(tile)))
{ {
if (TTMaskHasType(&cptr->drcc_corner, if (TTMaskHasType(&cptr->drcc_corner,
TiGetBottomType(tpr))) TiGetBottomType(tpr)))
@ -745,8 +888,8 @@ drcTile (tile, arg)
else tpr = tile; else tpr = tile;
/* Make sure the edge stops at edgeTop */ /* Make sure the edge stops at edgeTop */
if ((TiGetBottomType(tpl) != TiGetTopType(tpleft)) || if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
(TiGetBottomType(tpr) != TiGetTopType(tile))) (TiGetLeftType(tpr) != TiGetLeftType(tile)))
{ {
if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpl))) if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpl)))
{ {
@ -772,8 +915,8 @@ drcTile (tile, arg)
else tpr = tile; else tpr = tile;
/* Make sure the edge stops at edgeBot */ /* Make sure the edge stops at edgeBot */
if ((TiGetTopType(tpl) != TiGetBottomType(tpleft)) || if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
(TiGetTopType(tpr) != TiGetBottomType(tile))) (TiGetLeftType(tpr) != TiGetLeftType(tile)))
{ {
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpl))) 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. * 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)); for (tpx = TR(tile); BOTTOM(tpx) > edgeY; tpx = LB(tpx));
else tpx = tile; else tpx = tile;
if (TTMaskHasType(&cptr->drcc_corner, TiGetLeftType(tpx))) if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpx)))
{ {
errRect.r_xtop += cdist; errRect.r_xtop += cdist;
if (DRCEuclidean) if (DRCEuclidean)
@ -1061,7 +1198,7 @@ checkbottom:
if (LEFT(tile) >= errRect.r_xbot) tpx = BL(tile); if (LEFT(tile) >= errRect.r_xbot) tpx = BL(tile);
else tpx = tile; else tpx = tile;
if (TTMaskHasType(&cptr->drcc_corner, TiGetRightType(tpx))) if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpx)))
{ {
errRect.r_xbot -= cdist; errRect.r_xbot -= cdist;
if (DRCEuclidean) if (DRCEuclidean)
@ -1098,7 +1235,7 @@ checkbottom:
for (tpx = BL(tpbot); TOP(tpx) < edgeY; tpx = RT(tpx)); for (tpx = BL(tpbot); TOP(tpx) < edgeY; tpx = RT(tpx));
else tpx = tpbot; else tpx = tpbot;
if (TTMaskHasType(&cptr->drcc_corner, TiGetRightType(tpx))) if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpx)))
{ {
errRect.r_xbot -= cdist; errRect.r_xbot -= cdist;
if (DRCEuclidean) if (DRCEuclidean)
@ -1114,7 +1251,7 @@ checkbottom:
if (RIGHT(tpbot) <= errRect.r_xtop) tpx = TR(tpbot); if (RIGHT(tpbot) <= errRect.r_xtop) tpx = TR(tpbot);
else tpx = tpbot; else tpx = tpbot;
if (TTMaskHasType(&cptr->drcc_corner, TiGetLeftType(tpx))) if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpx)))
{ {
errRect.r_xtop += cdist; errRect.r_xtop += cdist;
if (DRCEuclidean) if (DRCEuclidean)

View File

@ -257,11 +257,14 @@ forgetit:
*/ */
int int
drcCheckMaxwidth(starttile,arg,cptr) drcCheckMaxwidth(starttile,arg,cptr,both)
Tile *starttile; Tile *starttile;
struct drcClientData *arg; struct drcClientData *arg;
DRCCookie *cptr; DRCCookie *cptr;
bool both;
{ {
int width;
int height;
int edgelimit; int edgelimit;
int retval = 0; int retval = 0;
Rect boundrect; Rect boundrect;
@ -314,8 +317,11 @@ drcCheckMaxwidth(starttile,arg,cptr)
if (TTMaskHasType(oktypes, TiGetLeftType(tp))) PUSHTILE(tp); if (TTMaskHasType(oktypes, TiGetLeftType(tp))) PUSHTILE(tp);
} }
if (boundrect.r_xtop - boundrect.r_xbot > edgelimit && width = boundrect.r_xtop - boundrect.r_xbot;
boundrect.r_ytop - boundrect.r_ybot > edgelimit) height = boundrect.r_ytop - boundrect.r_ybot;
if ( (width > edgelimit && height > edgelimit) ||
( both == TRUE && (width > edgelimit || height > edgelimit)) )
{ {
Rect rect; Rect rect;
TiToRect(starttile,&rect); TiToRect(starttile,&rect);

View File

@ -539,13 +539,23 @@ drcExactOverlapTile(tile, cxp)
type = TiGetType(tile); type = TiGetType(tile);
TTMaskSetOnlyType(&typeMask, type); TTMaskSetOnlyType(&typeMask, type);
for (t = DBNumUserLayers; t < DBNumTypes; t++) if (type < DBNumUserLayers)
{ {
rmask = DBResidueMask(t); for (t = DBNumUserLayers; t < DBNumTypes; t++)
if (TTMaskHasType(rmask, type)) {
TTMaskSetType(&typeMask, 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++) for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
{ {
@ -647,6 +657,7 @@ void
DRCOffGridError(rect) DRCOffGridError(rect)
Rect *rect; /* Area of error */ Rect *rect; /* Area of error */
{ {
if (drcSubFunc == NULL) return;
(*drcSubFunc)(DRCErrorDef, rect, &drcOffGridCookie, drcSubClientData); (*drcSubFunc)(DRCErrorDef, rect, &drcOffGridCookie, drcSubClientData);
} }
@ -696,7 +707,7 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
int oldTiles, count, x, y, errorSaveType; int oldTiles, count, x, y, errorSaveType;
Rect intArea, square, cliparea, subArea; Rect intArea, square, cliparea, subArea;
PaintResultType (*savedPaintTable)[NT][NT]; PaintResultType (*savedPaintTable)[NT][NT];
void (*savedPaintPlane)(); int (*savedPaintPlane)();
struct drcClientData arg; struct drcClientData arg;
SearchContext scx; SearchContext scx;
@ -896,7 +907,7 @@ DRCFlatCheck(use, area)
SearchContext scx; SearchContext scx;
void drcIncCount(); void drcIncCount();
PaintResultType (*savedPaintTable)[NT][NT]; PaintResultType (*savedPaintTable)[NT][NT];
void (*savedPaintPlane)(); int (*savedPaintPlane)();
int drcFlatCount = 0; int drcFlatCount = 0;
UndoDisable(); UndoDisable();

View File

@ -1550,6 +1550,7 @@ drcOffGrid(argc, argv)
* bend_ok - Used mainly for wide metal rules where metal greater than * bend_ok - Used mainly for wide metal rules where metal greater than
* some given width must be slotted. Also, used for things * some given width must be slotted. Also, used for things
* like trench, where the width is some fixed value: * like trench, where the width is some fixed value:
* both - implies bend_illegal and both directions are checked
* *
* XXXXX XXXXXX * XXXXX XXXXXX
* X X XXXXXX * X X XXXXXX
@ -1608,6 +1609,7 @@ drcMaxwidth(argc, argv)
{ {
if (strcmp(bends,"bend_illegal") == 0) bend = 0; if (strcmp(bends,"bend_illegal") == 0) bend = 0;
else if (strcmp(bends,"bend_ok") == 0) bend = DRC_BENDS; else if (strcmp(bends,"bend_ok") == 0) bend = DRC_BENDS;
else if (strcmp(bends,"both") == 0) bend = DRC_MAXWIDTH_BOTH;
else else
{ {
TechError("unknown bend option %s\n",bends); TechError("unknown bend option %s\n",bends);

View File

@ -73,8 +73,9 @@ typedef struct drccookie
#define DRC_AREA 0x020 #define DRC_AREA 0x020
#define DRC_OFFGRID 0x040 #define DRC_OFFGRID 0x040
#define DRC_MAXWIDTH 0x080 #define DRC_MAXWIDTH 0x080
#define DRC_RECTSIZE 0x100 #define DRC_MAXWIDTH_BOTH 0x100
#define DRC_ANGLES 0x200 #define DRC_RECTSIZE 0x200
#define DRC_ANGLES 0x400
#define DRC_NONSTANDARD (DRC_AREA|DRC_MAXWIDTH|DRC_RECTSIZE\ #define DRC_NONSTANDARD (DRC_AREA|DRC_MAXWIDTH|DRC_RECTSIZE\
|DRC_ANGLES|DRC_OFFGRID) |DRC_ANGLES|DRC_OFFGRID)

View File

@ -999,11 +999,12 @@ simdevVisit(dev, hc, scale, trans)
float scale; /* Scale transform for output */ float scale; /* Scale transform for output */
Transform *trans; /* Coordinate transform */ Transform *trans; /* Coordinate transform */
{ {
DevTerm *gate, *source, *drain; DevTerm *gate, *source, *drain, *term;
EFNode *subnode, *snode, *dnode; EFNode *subnode, *snode, *dnode;
int l, w; int l, w;
Rect r; Rect r;
char name[12]; char name[12];
bool is_subckt = FALSE;
HierName *hierName = hc->hc_hierName; HierName *hierName = hc->hc_hierName;
sprintf(name, "output"); sprintf(name, "output");
@ -1057,7 +1058,6 @@ simdevVisit(dev, hc, scale, trans)
case DEV_FET: case DEV_FET:
case DEV_MOSFET: case DEV_MOSFET:
case DEV_ASYMMETRIC: case DEV_ASYMMETRIC:
case DEV_MSUBCKT:
/* The sim file format only understands "n" and "p" for FETs. */ /* The sim file format only understands "n" and "p" for FETs. */
/* The extraction method says nothing about which is which. */ /* The extraction method says nothing about which is which. */
/* The EFDevTypes[] should ideally start with "n" or "p". If */ /* The EFDevTypes[] should ideally start with "n" or "p". If */
@ -1089,6 +1089,19 @@ simdevVisit(dev, hc, scale, trans)
} }
} }
break; 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: default:
fprintf(esSimF, "%c", EFDevTypes[dev->dev_type][0]); fprintf(esSimF, "%c", EFDevTypes[dev->dev_type][0]);
break; break;
@ -1121,8 +1134,31 @@ simdevVisit(dev, hc, scale, trans)
else if (dev->dev_nterm > 2) else if (dev->dev_nterm > 2)
simdevOutNode(hierName, drain->dterm_node->efnode_name->efnn_hier, name, esSimF); 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 */ /* Support gemini's substrate comparison */
if (esFormat == LBL && subnode) else if (esFormat == LBL && subnode)
{ {
putc(' ', esSimF); putc(' ', esSimF);
simdevSubstrate(hierName, subnode->efnode_name->efnn_hier, 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 */ else if (dev->dev_class == DEV_CAPREV) { /* generate a capacitor */
fprintf(esSimF, " %f", (double)(dev->dev_cap)); 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) else if ((dev->dev_class != DEV_DIODE) && (dev->dev_class != DEV_PDIODE)
&& (dev->dev_class != DEV_NDIODE)) { && (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"); fprintf(esSimF, "\n");
return 0; return 0;
@ -1572,9 +1624,8 @@ int simnodeVisit(node, res, cap)
if (esLabF) if (esLabF)
{ {
fprintf(esLabF, "94 ");
EFHNOut(hierName, esLabF); 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, node->efnode_loc.r_xbot, node->efnode_loc.r_ybot,
EFLayerNames[node->efnode_type]); EFLayerNames[node->efnode_type]);
} }

View File

@ -81,6 +81,7 @@ ESGenerateHierarchy(inName, flags)
hc.hc_hierName = NULL; hc.hc_hierName = NULL;
hc.hc_trans = GeoIdentityTransform; hc.hc_trans = GeoIdentityTransform;
hc.hc_x = hc.hc_y = 0; hc.hc_x = hc.hc_y = 0;
EFHierSrDefs(&hc, esMakePorts, NULL); EFHierSrDefs(&hc, esMakePorts, NULL);
EFHierSrDefs(&hc, NULL, NULL); /* Clear processed */ EFHierSrDefs(&hc, NULL, NULL); /* Clear processed */
@ -500,7 +501,7 @@ spcdevHierVisit(hc, dev, scale)
EFNode *subnode, *snode, *dnode, *subnodeFlat = NULL; EFNode *subnode, *snode, *dnode, *subnodeFlat = NULL;
int l, w, i, parmval; int l, w, i, parmval;
Rect r; Rect r;
bool subAP = FALSE, hierS, hierD, extHierSDAttr(), swapped = FALSE; bool subAP = FALSE, hierS, hierD, extHierSDAttr();
float sdM; float sdM;
char devchar; char devchar;
bool has_model = TRUE; bool has_model = TRUE;
@ -522,6 +523,8 @@ spcdevHierVisit(hc, dev, scale)
source = drain = &dev->dev_terms[1]; source = drain = &dev->dev_terms[1];
if (dev->dev_nterm >= 3) if (dev->dev_nterm >= 3)
{ {
drain = &dev->dev_terms[2];
/* If any terminal is marked with attribute "D" or "S" */ /* If any terminal is marked with attribute "D" or "S" */
/* (label "D$" or "S$" at poly-diffusion interface), */ /* (label "D$" or "S$" at poly-diffusion interface), */
/* then force order of source and drain accordingly. */ /* then force order of source and drain accordingly. */
@ -531,11 +534,8 @@ spcdevHierVisit(hc, dev, scale)
(dev->dev_terms[2].dterm_attrs && (dev->dev_terms[2].dterm_attrs &&
!strcmp(dev->dev_terms[2].dterm_attrs, "S"))) !strcmp(dev->dev_terms[2].dterm_attrs, "S")))
{ {
swapDrainSource(dev, &source, &drain); swapDrainSource(dev);
swapped = TRUE;
} }
else
drain = &dev->dev_terms[2];
} }
else if (dev->dev_nterm == 1) // Is a device with one terminal an error? else if (dev->dev_nterm == 1) // Is a device with one terminal an error?
source = drain = &dev->dev_terms[0]; source = drain = &dev->dev_terms[0];
@ -1023,10 +1023,6 @@ spcdevHierVisit(hc, dev, scale)
break; break;
} }
fprintf(esSpiceF, "\n"); fprintf(esSpiceF, "\n");
/* If S/D parameters were swapped, then put them back */
if (swapped) swapDrainSource(dev, NULL, NULL);
return 0; return 0;
} }
@ -1642,8 +1638,11 @@ esMakePorts(hc, cdata)
*tptr = '/'; *tptr = '/';
portname = tptr + 1; portname = tptr + 1;
// Find the net of portname in the subcell and /* Find the net of portname in the subcell and make it a
// make it a port if it is not already. * 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) if (portdef)
{ {
@ -1897,6 +1896,8 @@ esHierVisit(hc, cdata)
freeMagic(p); freeMagic(p);
devMergeList = NULL; devMergeList = NULL;
} }
else if (esDistrJunct)
EFHierVisitDevs(hcf, devDistJunctHierVisit, (ClientData)NULL);
/* Output devices */ /* Output devices */
EFHierVisitDevs(hcf, spcdevHierVisit, (ClientData)NULL); EFHierVisitDevs(hcf, spcdevHierVisit, (ClientData)NULL);

View File

@ -1553,10 +1553,15 @@ subcktVisit(use, hierName, is_top)
} }
} }
/* SPICE subcircuit names must begin with A-Z. This will also be */ /* SPICE subcircuit names must begin with A-Z. */
/* enforced when writing X subcircuit calls. */
subcktname = def->def_name; 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+"); if (tchars > 80) fprintf(esSpiceF, "\n+");
fprintf(esSpiceF, " %s", subcktname); /* subcircuit model name */ 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 */ /* SPICE subcircuit names must begin with A-Z. This will also be */
/* enforced when writing X subcircuit calls. */ /* enforced when writing X subcircuit calls. */
subcktname = def->def_name; 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); fprintf(esSpiceF, ".subckt %s", subcktname);
tchars = 8 + strlen(subcktname); tchars = 8 + strlen(subcktname);
@ -1924,7 +1935,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
hierD = extHierSDAttr(&dev->dev_terms[pn]); 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; esFetInfo[dev->dev_type].resClassSource;
// For parameter a<n> followed by parameter p<n>, // 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'; pn = plist->parm_type[1] - '0';
if (pn >= dev->dev_nterm) pn = dev->dev_nterm - 1; 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; esFetInfo[dev->dev_type].resClassSource;
hierD = extHierSDAttr(&dev->dev_terms[pn]); hierD = extHierSDAttr(&dev->dev_terms[pn]);
@ -2219,47 +2230,39 @@ getCurDevMult()
/* /*
*-----------------------------------------------------------------------------
* swapDrainSource * swapDrainSource
* *
* Swap drain and source ordering and the related stuff * Swap drain and source ordering and the related stuff
* including the drain/source area parameters * 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), * (label "D$" or "S$" at poly-diffusion interface),
* then swap order of source and drain compared to the default ordering. * 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 void
swapDrainSource(dev, source, drain) swapDrainSource(dev)
Dev *dev; Dev *dev;
DevTerm **source, **drain;
{ {
DevParam *plist; DevTerm tmpTerm;
/* 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. */
plist = efGetDeviceParams(EFDevTypes[dev->dev_type]); /* swap original terminals */
while (plist != NULL) memcpy(&tmpTerm, &(dev->dev_terms[1]), sizeof(DevTerm));
{ memcpy(&(dev->dev_terms[1]), &(dev->dev_terms[2]), sizeof(DevTerm));
// Diagnostic memcpy(&(dev->dev_terms[2]), &tmpTerm, sizeof(DevTerm));
// 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;
}
} }
@ -2309,7 +2312,7 @@ spcdevVisit(dev, hc, scale, trans)
DevTerm *gate, *source, *drain; DevTerm *gate, *source, *drain;
EFNode *subnode, *snode, *dnode, *subnodeFlat = NULL; EFNode *subnode, *snode, *dnode, *subnodeFlat = NULL;
int l, w, i, parmval; int l, w, i, parmval;
bool subAP= FALSE, hierS, hierD, extHierSDAttr(), swapped = FALSE ; bool subAP= FALSE, hierS, hierD, extHierSDAttr();
float sdM; float sdM;
char name[12], devchar; char name[12], devchar;
bool has_model = TRUE; bool has_model = TRUE;
@ -2331,8 +2334,11 @@ spcdevVisit(dev, hc, scale, trans)
gate = &dev->dev_terms[0]; gate = &dev->dev_terms[0];
if (dev->dev_nterm >= 2) if (dev->dev_nterm >= 2)
source = drain = &dev->dev_terms[1]; source = drain = &dev->dev_terms[1];
if (dev->dev_nterm >= 3) if (dev->dev_nterm >= 3)
{ {
drain = &dev->dev_terms[2];
/* If any terminal is marked with attribute "D" or "S" */ /* If any terminal is marked with attribute "D" or "S" */
/* (label "D$" or "S$" at poly-diffusion interface), */ /* (label "D$" or "S$" at poly-diffusion interface), */
/* then force order of source and drain accordingly. */ /* then force order of source and drain accordingly. */
@ -2342,11 +2348,8 @@ spcdevVisit(dev, hc, scale, trans)
(dev->dev_terms[2].dterm_attrs && (dev->dev_terms[2].dterm_attrs &&
!strcmp(dev->dev_terms[2].dterm_attrs, "S"))) !strcmp(dev->dev_terms[2].dterm_attrs, "S")))
{ {
swapDrainSource(dev, &source, &drain); swapDrainSource(dev);
swapped = True;
} }
else
drain = &dev->dev_terms[2];
} }
subnode = dev->dev_subsnode; subnode = dev->dev_subsnode;
@ -2852,9 +2855,6 @@ spcdevVisit(dev, hc, scale, trans)
} }
fprintf(esSpiceF, "\n"); fprintf(esSpiceF, "\n");
/* If S/D parameters on a subcircuit were swapped, put them back */
if (swapped) swapDrainSource(dev, NULL, NULL);
return 0; return 0;
} }
@ -4083,7 +4083,7 @@ update_w(resClass, w, n)
{ {
(nc->m_w.widths) = (float *)mallocMagic((unsigned)sizeof(float) (nc->m_w.widths) = (float *)mallocMagic((unsigned)sizeof(float)
* efNumResistClasses); * efNumResistClasses);
for (i = 0; i < EFDevNumTypes; i++) for (i = 0; i < efNumResistClasses; i++)
nc->m_w.widths[i] = 0.0; nc->m_w.widths[i] = 0.0;
} }
nc->m_w.widths[resClass] += (float)w; nc->m_w.widths[resClass] += (float)w;

View File

@ -34,6 +34,7 @@
#include "extflat/EFint.h" #include "extflat/EFint.h"
#include "extract/extract.h" #include "extract/extract.h"
#include "extract/extractInt.h" #include "extract/extractInt.h"
#include "select/select.h"
#include "utils/malloc.h" #include "utils/malloc.h"
/* Forward declarations */ /* Forward declarations */
@ -505,7 +506,7 @@ antennacheckVisit(dev, hc, scale, trans, editUse)
/* To do: Mark tiles so area count can be progressive */ /* To do: Mark tiles so area count can be progressive */
DBTreeCopyConnect(&scx, &DBConnectTbl[t], 0, 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 */ /* Search planes of tie types and accumulate all tiedown areas */
gdas.accum = (dlong)0; gdas.accum = (dlong)0;

View File

@ -32,6 +32,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header$";
#include "utils/malloc.h" #include "utils/malloc.h"
#include "extflat/extflat.h" #include "extflat/extflat.h"
#include "extflat/EFint.h" #include "extflat/EFint.h"
#include "tiles/tile.h"
#include "extract/extract.h" /* for device class list */ #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 = (EFNodeName *) mallocMagic((unsigned)(sizeof (EFNodeName)));
newname->efnn_hier = EFStrToHN((HierName *) NULL, nodeName); newname->efnn_hier = EFStrToHN((HierName *) NULL, nodeName);
newname->efnn_port = -1; /* No port assignment */ newname->efnn_port = -1; /* No port assignment */
newname->efnn_refc = 0; /* Only reference is self */
newname->efnn_next = NULL; newname->efnn_next = NULL;
HashSetValue(he, (char *) newname); HashSetValue(he, (char *) newname);
} }
@ -453,6 +455,8 @@ efBuildEquiv(def, nodeName1, nodeName2)
nn1 = (EFNodeName *) HashGetValue(he1); nn1 = (EFNodeName *) HashGetValue(he1);
nn2 = (EFNodeName *) HashGetValue(he2); nn2 = (EFNodeName *) HashGetValue(he2);
if (nn1 == nn2) return; /* These nodes already merged */
if (nn2 == (EFNodeName *) NULL) if (nn2 == (EFNodeName *) NULL)
{ {
/* Create nodeName1 if it doesn't exist */ /* Create nodeName1 if it doesn't exist */
@ -481,11 +485,35 @@ efBuildEquiv(def, nodeName1, nodeName2)
return; /* Repeated "equiv" statement */ return; /* Repeated "equiv" statement */
if (nn1->efnn_node != nn2->efnn_node) if (nn1->efnn_node != nn2->efnn_node)
{ {
struct efnode *node1 = nn1->efnn_node;
struct efnode *node2 = nn2->efnn_node;
HashSearch hs;
if (efWarn) if (efWarn)
efReadError("Merged nodes %s and %s\n", nodeName1, nodeName2); efReadError("Merged nodes %s and %s\n", nodeName1, nodeName2);
efNodeMerge(&nn1->efnn_node, &nn2->efnn_node); efNodeMerge(&nn1->efnn_node, &nn2->efnn_node);
if (nn1->efnn_port > 0) nn2->efnn_port = nn1->efnn_port; if (nn1->efnn_port > 0) nn2->efnn_port = nn1->efnn_port;
else if (nn2->efnn_port > 0) nn1->efnn_port = nn2->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; return;
} }
@ -1553,6 +1581,7 @@ efNodeAddName(node, he, hn)
newnn->efnn_node = node; newnn->efnn_node = node;
newnn->efnn_hier = hn; newnn->efnn_hier = hn;
newnn->efnn_port = -1; newnn->efnn_port = -1;
newnn->efnn_refc = 0;
HashSetValue(he, (char *) newnn); HashSetValue(he, (char *) newnn);
/* If the node is a port of the top level cell, denoted by flag */ /* 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) for (hn = nn->efnn_hier; hn; hn = hn->hn_parent)
(void) HashFind(&efFreeHashTable, (char *) hn); (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);
} }
} }

View File

@ -204,7 +204,7 @@ EFFlatBuildOneLevel(def, flags)
efFlatRootUse.use_def = efFlatRootDef; efFlatRootUse.use_def = efFlatRootDef;
/* Record all nodes down the hierarchy from here */ /* Record all nodes down the hierarchy from here */
flatnodeflags = FLATNODE_STDCELL; /* No FLATDNODE_DOWARN flag */ flatnodeflags = 0; /* No FLATNODE_DOWARN */
efFlatNodes(&efFlatContext, (ClientData)flatnodeflags); efFlatNodes(&efFlatContext, (ClientData)flatnodeflags);
/* Expand all subcells that contain connectivity information but */ /* 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)) if ((usecount == 0) && (HashGetNumEntries(&efFlatRootUse.use_def->def_devs) == 0))
efFlatRootUse.use_def->def_flags |= DEF_NODEVICES; efFlatRootUse.use_def->def_flags |= DEF_NODEVICES;
/* Record all local nodes */
efAddNodes(&efFlatContext, FALSE);
efAddConns(&efFlatContext, TRUE);
efFlatKills(&efFlatContext); efFlatKills(&efFlatContext);
if (!(flags & EF_NONAMEMERGE)) if (!(flags & EF_NONAMEMERGE))
efFlatGlob(); efFlatGlob();
@ -297,6 +293,9 @@ EFFlatDone()
* Adds node names to the table of flattened node names efNodeHashTable. * Adds node names to the table of flattened node names efNodeHashTable.
* May merge nodes from the list efNodeList as per the connection * May merge nodes from the list efNodeList as per the connection
* list hc->hc_use->use_def->def_conns. * 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; EFNode *node, *newnode;
EFAttr *ap, *newap; EFAttr *ap, *newap;
HierName *hierName; HierName *hierName;
float scale;
int size, asize; int size, asize;
HashEntry *he; HashEntry *he;
bool is_subcircuit = (def->def_flags & DEF_SUBCIRCUIT) ? TRUE : FALSE; bool is_subcircuit = (def->def_flags & DEF_SUBCIRCUIT) ? TRUE : FALSE;
scale = def->def_scale;
size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (EFPerimArea); size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (EFPerimArea);
for (node = (EFNode *) def->def_firstn.efnode_next; for (node = (EFNode *) def->def_firstn.efnode_next;
@ -465,10 +462,6 @@ efAddNodes(hc, stdcell)
newap = (EFAttr *) mallocMagic((unsigned)(asize)); newap = (EFAttr *) mallocMagic((unsigned)(asize));
(void) strcpy(newap->efa_text, ap->efa_text); (void) strcpy(newap->efa_text, ap->efa_text);
GeoTransRect(&hc->hc_trans, &ap->efa_loc, &newap->efa_loc); 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_type = ap->efa_type;
newap->efa_next = newnode->efnode_attrs; newap->efa_next = newnode->efnode_attrs;
@ -491,13 +484,8 @@ efAddNodes(hc, stdcell)
efNumResistClasses * sizeof (EFPerimArea)); efNumResistClasses * sizeof (EFPerimArea));
GeoTransRect(&hc->hc_trans, &node->efnode_loc, &newnode->efnode_loc); GeoTransRect(&hc->hc_trans, &node->efnode_loc, &newnode->efnode_loc);
/* Scale the result by "scale" --- hopefully we end up with an integer */ /* Add each name for this node to the hash table */
/* We don't scale the transform because the scale may be non-integer */ newnode->efnode_name = (EFNodeName *) NULL;
/* 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);
/* Prepend to global node list */ /* Prepend to global node list */
newnode->efnode_next = efNodeList.efnode_next; newnode->efnode_next = efNodeList.efnode_next;
@ -505,9 +493,6 @@ efAddNodes(hc, stdcell)
efNodeList.efnode_next->efnhdr_prev = (EFNodeHdr *) newnode; efNodeList.efnode_next->efnhdr_prev = (EFNodeHdr *) newnode;
efNodeList.efnode_next = (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) for (nn = node->efnode_name; nn; nn = nn->efnn_next)
{ {
/* /*
@ -546,6 +531,7 @@ efAddNodes(hc, stdcell)
newname->efnn_node = newnode; newname->efnn_node = newnode;
newname->efnn_hier = hierName; newname->efnn_hier = hierName;
newname->efnn_port = -1; newname->efnn_port = -1;
newname->efnn_refc = 0;
if (newnode->efnode_name) if (newnode->efnode_name)
{ {
newname->efnn_next = newnode->efnode_name->efnn_next; newname->efnn_next = newnode->efnode_name->efnn_next;
@ -557,6 +543,7 @@ efAddNodes(hc, stdcell)
newnode->efnode_name = newname; newnode->efnode_name = newname;
} }
} }
} }
return 0; return 0;
} }

View File

@ -34,6 +34,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/utils.h" #include "utils/utils.h"
#include "extflat/extflat.h" #include "extflat/extflat.h"
#include "extflat/EFint.h" #include "extflat/EFint.h"
#include "tiles/tile.h"
#include "extract/extract.h" #include "extract/extract.h"
/* Root of the tree being flattened */ /* Root of the tree being flattened */

View File

@ -119,6 +119,7 @@ typedef struct efnn
struct efnn *efnn_next; /* Next name for this node */ struct efnn *efnn_next; /* Next name for this node */
HierName *efnn_hier; /* HierName for this node */ HierName *efnn_hier; /* HierName for this node */
int efnn_port; /* Port number for this node */ int efnn_port; /* Port number for this node */
unsigned char efnn_refc; /* #times referenced in hash */
} EFNodeName; } EFNodeName;
/* /*

View File

@ -727,13 +727,17 @@ extOutputNodes(nodeList, outFile)
fprintf(outFile, "\"\n"); 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) for (ll = reg->nreg_labels; ll; ll = ll->ll_next)
if (ll->ll_label->lab_text == text) if (ll->ll_label->lab_text == text)
{ {
for (ll = ll->ll_next; ll; ll = ll->ll_next) for (ll = ll->ll_next; ll; ll = ll->ll_next)
if (extLabType(ll->ll_label->lab_text, LABTYPE_NAME)) 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); text, ll->ll_label->lab_text);
break; break;
} }
@ -1817,26 +1821,8 @@ extOutputDevices(def, transList, outFile)
extTransFindSubs(reg->treg_tile, t, tmask, def, &node, NULL); extTransFindSubs(reg->treg_tile, t, tmask, def, &node, NULL);
if ((node == NULL) && (TTMaskHasType(tmask, TT_SPACE))) { if ((node == NULL) && (TTMaskHasType(tmask, TT_SPACE))) {
/* Device node is possibly the substrate. But: Note */ /* Device node is the global substrate. */
/* that TT_SPACE in the mask covers all planes, and it */ node = glob_subsnode;
/* is not possible to specify TT_SPACE in a single */
/* plane. So it is necessary to check for any */
/* shielding types that block the substrate. */
if (!TTMaskIsZero(&ExtCurStyle->exts_globSubstrateShieldTypes))
{
extTransFindSubs(reg->treg_tile, t,
&ExtCurStyle->exts_globSubstrateShieldTypes,
def, &node, NULL);
}
if ((glob_subsnode == NULL) || (node != NULL)) {
/* See if there is another matching device record */
/* with a different terminal type, and try again. */
devptr = extDevFindMatch(devptr, t);
break;
}
else if ((node == NULL) && (glob_subsnode != NULL))
node = glob_subsnode;
} }
else if (node == NULL) { else if (node == NULL) {
/* See if there is another matching device record */ /* See if there is another matching device record */

View File

@ -58,7 +58,7 @@ ClientData extUnInit = (ClientData) CLIENTDEFAULT;
int extOutputUsesFunc(); int extOutputUsesFunc();
FILE *extFileOpen(); FILE *extFileOpen();
void extCellFile(); Plane* extCellFile();
void extHeader(); void extHeader();
@ -83,7 +83,7 @@ void extHeader();
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
void Plane *
ExtCell(def, outName, doLength) ExtCell(def, outName, doLength)
CellDef *def; /* Cell being extracted */ CellDef *def; /* Cell being extracted */
char *outName; /* Name of output file; if NULL, derive from def name */ char *outName; /* Name of output file; if NULL, derive from def name */
@ -95,6 +95,7 @@ ExtCell(def, outName, doLength)
{ {
char *filename; char *filename;
FILE *f; FILE *f;
Plane *savePlane;
bool doLocal; bool doLocal;
doLocal = (ExtOptions & EXT_DOLOCAL) ? TRUE : FALSE; doLocal = (ExtOptions & EXT_DOLOCAL) ? TRUE : FALSE;
@ -115,7 +116,7 @@ ExtCell(def, outName, doLength)
} }
extNumFatal = extNumWarnings = 0; extNumFatal = extNumWarnings = 0;
extCellFile(def, f, doLength); savePlane = extCellFile(def, f, doLength);
(void) fclose(f); (void) fclose(f);
if (extNumFatal > 0 || extNumWarnings > 0) if (extNumFatal > 0 || extNumWarnings > 0)
@ -129,6 +130,7 @@ ExtCell(def, outName, doLength)
extNumWarnings, extNumWarnings != 1 ? "s" : ""); extNumWarnings, extNumWarnings != 1 ? "s" : "");
TxPrintf("\n"); TxPrintf("\n");
} }
return savePlane;
} }
/* /*
@ -219,6 +221,137 @@ extFileOpen(def, file, mode, doLocal, prealfile)
return (PaOpen(name, mode, ".ext", ".", ".", 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(&notSubMask, &subMask);
TTMaskAndMask(&notSubMask, &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, &notSubMask,
&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) extCellFile(def, f, doLength)
CellDef *def; /* Def to be extracted */ CellDef *def; /* Def to be extracted */
FILE *f; /* Output to this file */ FILE *f; /* Output to this file */
@ -250,9 +383,13 @@ extCellFile(def, f, doLength)
*/ */
{ {
NodeRegion *reg; NodeRegion *reg;
Plane *saveSub;
UndoDisable(); UndoDisable();
/* Prep any isolated substrate areas */
saveSub = extPrepSubstrate(def);
/* Output the header: timestamp, technology, calls on cell uses */ /* Output the header: timestamp, technology, calls on cell uses */
if (!SigInterruptPending) extHeader(def, f); if (!SigInterruptPending) extHeader(def, f);
@ -274,6 +411,7 @@ extCellFile(def, f, doLength)
extLength(extParentUse, f); extLength(extParentUse, f);
UndoEnable(); UndoEnable();
return saveSub;
} }
/* /*

View File

@ -897,6 +897,9 @@ extSideOverlap(tp, esws)
subcap = (ExtCurStyle->exts_perimCap[ta][outtype] * subcap = (ExtCurStyle->exts_perimCap[ta][outtype] *
MIN(areaAccountedFor, length)); MIN(areaAccountedFor, length));
rbp->nreg_cap -= subcap; 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) if (CAP_DEBUG)
extNregAdjustCap(rbp, -subcap, "obsolete_perimcap"); extNregAdjustCap(rbp, -subcap, "obsolete_perimcap");
} else if (CAP_DEBUG) } else if (CAP_DEBUG)

View File

@ -484,7 +484,10 @@ extHardFreeAll(def, tReg)
/* Free all LabelLists and then the region */ /* Free all LabelLists and then the region */
for (ll = reg->treg_labels; ll; ll = ll->ll_next) 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 *) ll);
}
freeMagic((char *) reg); freeMagic((char *) reg);
} }
} }

View File

@ -60,16 +60,34 @@ int extHierConnectFunc2();
int extHierConnectFunc3(); int extHierConnectFunc3();
Node *extHierNewNode(); Node *extHierNewNode();
/*----------------------------------------------------------------------*/
/* extHierSubShieldFunc -- */
/* */
/* Simple callback function for extHierSubstrate() that halts the */
/* search if any substrate shield type is found in the search area */
/* */
/*----------------------------------------------------------------------*/
/*----------------------------------------------*/ int
/* extHierSubstrate */ extHierSubShieldFunc(tile)
/* */ Tile *tile;
/* Find the substrate node of a child cell and */ {
/* make a connection between parent and child */ return 1;
/* substrates. If either of the substrate */ }
/* nodes is already in the hash table, then the */
/* table will be updated as necessary. */ /*----------------------------------------------------------------------*/
/*----------------------------------------------*/ /* 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 void
extHierSubstrate(ha, use, x, y) extHierSubstrate(ha, use, x, y)
@ -84,6 +102,8 @@ extHierSubstrate(ha, use, x, y)
Node *node1, *node2; Node *node1, *node2;
char *name1, *name2, *childname; char *name1, *name2, *childname;
CellDef *def; CellDef *def;
Rect subArea;
int pNum;
NodeRegion *extFindNodes(); NodeRegion *extFindNodes();
@ -107,6 +127,49 @@ extHierSubstrate(ha, use, x, y)
/* Find the child's substrate node */ /* Find the child's substrate node */
nodeList = extFindNodes(use->cu_def, (Rect *) NULL, TRUE); 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 */ /* Make sure substrate labels are represented */
ExtLabelRegions(use->cu_def, ExtCurStyle->exts_nodeConn, &nodeList, 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 */ /* Look for sticky labels in the child cell that are not */
/* connected to any geometry. */ /* connected to any geometry. */
if (!(ExtOptions & EXT_DOLABELCHECK)) return;
for (lab = sourceDef->cd_labels; lab; lab = lab->lab_next) for (lab = sourceDef->cd_labels; lab; lab = lab->lab_next)
{ {
CellDef *cumDef = cumFlat->et_use->cu_def; 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 */ /* This allows the extractor to catch "sticky" labels that are not */
/* attached to a physical layer in the parent cell. */ /* 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 // NOTE by Tim, 9/10/2014: This generates phantom nodes when the
// labels are created by the "hard" node search; I think this code // labels are created by the "hard" node search; I think this code
// should be restricted to sticky labels only. But not certain. // should be restricted to sticky labels only. But not certain.
@ -330,31 +397,7 @@ extHierConnectFunc1(oneTile, ha)
node1->node_names = node2->node_names; node1->node_names = node2->node_names;
freeMagic((char *) node2); 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); return (0);
} }

View File

@ -45,6 +45,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/signals.h" #include "utils/signals.h"
#include "windows/windows.h" #include "windows/windows.h"
#include "dbwind/dbwind.h" #include "dbwind/dbwind.h"
#include "select/select.h"
#include "utils/styles.h" #include "utils/styles.h"
#include "utils/stack.h" #include "utils/stack.h"
#include "utils/main.h" #include "utils/main.h"
@ -368,7 +369,7 @@ extLengthYank(use, labList)
scx.scx_trans = GeoIdentityTransform; scx.scx_trans = GeoIdentityTransform;
GEO_EXPAND(&lab->lab_rect, 1, &scx.scx_area); GEO_EXPAND(&lab->lab_rect, 1, &scx.scx_area);
DBTreeCopyConnect(&scx, &DBConnectTbl[lab->lab_type], 0, DBTreeCopyConnect(&scx, &DBConnectTbl[lab->lab_type], 0,
DBConnectTbl, &TiPlaneRect, TRUE, extPathUse); DBConnectTbl, &TiPlaneRect, SEL_DO_LABELS, extPathUse);
} }
if (DebugIsSet(extDebugID, extDebLength)) if (DebugIsSet(extDebugID, extDebLength))

View File

@ -616,6 +616,16 @@ closeit:
return (ret); 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; int fatal = 0, warnings = 0;
bool first = TRUE; bool first = TRUE;
Plane *savePlane;
CellDef *def; CellDef *def;
struct saveList *newsl, *sl = (struct saveList *)NULL;
while (def = (CellDef *) StackPop(stack)) while (def = (CellDef *) StackPop(stack))
{ {
@ -654,7 +666,16 @@ extExtractStack(stack, doExtract, rootDef)
{ {
if (doExtract) 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; fatal += extNumFatal;
warnings += extNumWarnings; 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) if (!doExtract)
{ {
TxPrintf("\n"); TxPrintf("\n");

View File

@ -245,7 +245,7 @@ ExtLabelRegions(def, connTo, nodeList, clipArea)
break; break;
} }
} }
if ((found == FALSE) && (nodeList != NULL)) if ((found == FALSE) && (nodeList != NULL) && (ExtOptions & EXT_DOLABELCHECK))
{ {
// Unconnected node label. This may be a "sticky label". // Unconnected node label. This may be a "sticky label".
// If it is not connected to TT_SPACE, then create a new // If it is not connected to TT_SPACE, then create a new

View File

@ -429,14 +429,12 @@ extSubtreeInteraction(ha)
NodeRegion *reg; NodeRegion *reg;
SearchContext scx; SearchContext scx;
/* Copy parent paint into ha->ha_cumFlat (which was initially empty) */
scx.scx_trans = GeoIdentityTransform; scx.scx_trans = GeoIdentityTransform;
scx.scx_area = ha->ha_interArea; scx.scx_area = ha->ha_interArea;
scx.scx_use = ha->ha_parentUse; scx.scx_use = ha->ha_parentUse;
/* Copy parent paint into ha->ha_cumFlat */
DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, ha->ha_cumFlat.et_use); 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. * First element on the subtree list will be parent mask info.
@ -446,9 +444,6 @@ extSubtreeInteraction(ha)
oneDef = oneFlat->et_use->cu_def; oneDef = oneFlat->et_use->cu_def;
DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, oneFlat->et_use); 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); oneFlat->et_nodes = extFindNodes(oneDef, &ha->ha_clipArea, FALSE);
if ((ExtOptions & (EXT_DOCOUPLING|EXT_DOADJUST)) if ((ExtOptions & (EXT_DOCOUPLING|EXT_DOADJUST))
== (EXT_DOCOUPLING|EXT_DOADJUST)) == (EXT_DOCOUPLING|EXT_DOADJUST))
@ -743,6 +738,7 @@ extSubtreeFunc(scx, ha)
hy.hy_area = &ha->ha_subArea; hy.hy_area = &ha->ha_subArea;
hy.hy_target = oneFlat->et_use; hy.hy_target = oneFlat->et_use;
hy.hy_prefix = TRUE; hy.hy_prefix = TRUE;
(void) DBArraySr(use, &ha->ha_subArea, extHierYankFunc, (ClientData) &hy); (void) DBArraySr(use, &ha->ha_subArea, extHierYankFunc, (ClientData) &hy);
/* /*
@ -767,6 +763,8 @@ extSubtreeFunc(scx, ha)
*/ */
if (extFirstPass) if (extFirstPass)
{ {
extFirstPass = FALSE;
// On the first pass, run through et_lookName's label list. // On the first pass, run through et_lookName's label list.
// Copy any sticky labels to cumUse->cu_def, so that the labels // Copy any sticky labels to cumUse->cu_def, so that the labels
// can be found even when there is no geometry underneath in // can be found even when there is no geometry underneath in
@ -796,7 +794,6 @@ extSubtreeFunc(scx, ha)
cumUse->cu_def->cd_labels = newlab; cumUse->cu_def->cd_labels = newlab;
} }
} }
extFirstPass = FALSE;
} }
else else
{ {
@ -861,9 +858,6 @@ extSubtreeFunc(scx, ha)
newscx.scx_area = ha->ha_subArea; newscx.scx_area = ha->ha_subArea;
newscx.scx_trans = GeoIdentityTransform; newscx.scx_trans = GeoIdentityTransform;
DBCellCopyPaint(&newscx, &DBAllButSpaceBits, 0, cumUse); 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); extHierCopyLabels(oneFlat->et_use->cu_def, cumUse->cu_def);
/* Prepend this tree to the list of trees we've processed so far */ /* 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; HierExtractArg *ha = arg->hw_ha;
ExtTree *oneFlat; ExtTree *oneFlat;
arg->hw_proc = extHardProc; arg->hw_proc = extHardProc;
if (et == &ha->ha_cumFlat) if (et == &ha->ha_cumFlat)
{ {

View File

@ -148,6 +148,8 @@ ExtractTest(w, cmd)
if (cmd->tx_argc == 1) if (cmd->tx_argc == 1)
{ {
Plane *savePlane;
selectedCell = CmdGetSelectedCell((Transform *) NULL); selectedCell = CmdGetSelectedCell((Transform *) NULL);
if (selectedCell == NULL) if (selectedCell == NULL)
{ {
@ -156,7 +158,8 @@ ExtractTest(w, cmd)
} }
extDispInit(selectedCell->cu_def, w); 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; return;
} }

View File

@ -67,6 +67,7 @@ extern char *extDevTable[];
#define EXT_DOLENGTH 0x10 /* Extract pathlengths */ #define EXT_DOLENGTH 0x10 /* Extract pathlengths */
#define EXT_DOALL 0x1f /* ALL OF THE ABOVE */ #define EXT_DOALL 0x1f /* ALL OF THE ABOVE */
#define EXT_DOLOCAL 0x20 /* Write to local directory only */ #define EXT_DOLOCAL 0x20 /* Write to local directory only */
#define EXT_DOLABELCHECK 0x40 /* Check for connections by label */
extern int ExtOptions; /* Bitmask of above */ extern int ExtOptions; /* Bitmask of above */
@ -75,7 +76,8 @@ extern void ExtTechInit();
extern void ExtTechFinal(); extern void ExtTechFinal();
extern void ExtSetStyle(); extern void ExtSetStyle();
extern void ExtPrintStyle(); extern void ExtPrintStyle();
extern void ExtCell(); extern void ExtRevertSubstrate();
extern Plane *ExtCell();
extern int ExtGetGateTypesMask(); extern int ExtGetGateTypesMask();
extern int ExtGetDiffTypesMask(); extern int ExtGetDiffTypesMask();

View File

@ -61,7 +61,7 @@ int gaDebNoClean = 0;
/* Used in the "*garoute split" command */ /* Used in the "*garoute split" command */
PlaneMask gaSplitPlaneMask; PlaneMask gaSplitPlaneMask;
void (*gaSplitPaintPlane)(); int (*gaSplitPaintPlane)();
Rect gaSplitArea; Rect gaSplitArea;
int gaSplitType; int gaSplitType;

View File

@ -1546,24 +1546,20 @@ DefReadComponents(f, rootDef, sname, oscale, total)
break; break;
} }
/* Does use name contain brackets? If so, this can */ /* Magic prohibits slashes and commas in use names */
/* interfere with magic's use of arrays. */ /* when using the "identify" command. Removing these */
/* NOTE: This has been commented out. I think */ /* restrictions (at least the slash) is quite complex, */
/* the only confusion is in ext2spice and can be */ /* but really should be taken care of, since no other */
/* avoided by allowing any bracket notation in an */ /* tools consider this an illegal use, that I'm aware */
/* instance name other than that used by the .ext */ /* of. */
/* file for dealing with arrays, which uses the */
/* specific syntax [xlo:xsep:xhi][ylo:ysep:yhi] and */
/* is easy enough to distinguish. */
/* for (dptr = usename; *dptr; dptr++)
dptr = strchr(usename, '['); if ((*dptr == '/') || (*dptr == ','))
if (dptr != NULL) { {
LefError(DEF_WARNING, "Character in instance name "
"converted to underscore.\n");
*dptr = '_'; *dptr = '_';
dptr = strchr(dptr + 1, ']');
if (dptr != NULL) *dptr = '_';
} }
*/
token = LefNextToken(f, TRUE); token = LefNextToken(f, TRUE);

View File

@ -92,6 +92,11 @@ CmdLef(w, cmd)
* other than pin area surrounding labels, * other than pin area surrounding labels,
* with the indicated setback distance. * 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 bool lefTopLayer = FALSE; /* If TRUE, only output the topmost
* layer used by a pin, and make * layer used by a pin, and make
* all layers below it obstructions. * all layers below it obstructions.
@ -234,6 +239,17 @@ CmdLef(w, cmd)
i++; 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)) else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9))
lefTopLayer = TRUE; lefTopLayer = TRUE;
else if (!strncmp(cmd->tx_argv[i], "-nomaster", 9)) else if (!strncmp(cmd->tx_argv[i], "-nomaster", 9))
@ -244,8 +260,8 @@ CmdLef(w, cmd)
} }
else goto wrongNumArgs; else goto wrongNumArgs;
} }
LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, lefTopLayer, LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, lefPinOnly,
lefDoMaster, recurse); lefTopLayer, lefDoMaster, recurse);
} }
break; break;
case LEF_WRITE: case LEF_WRITE:
@ -286,6 +302,23 @@ CmdLef(w, cmd)
else else
TxPrintf("The \"-hide\" option is only for lef write\n"); 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)) else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9))
{ {
if (is_lef) if (is_lef)
@ -339,7 +372,8 @@ CmdLef(w, cmd)
DefWriteCell(selectedUse->cu_def, namep, allSpecial, units); DefWriteCell(selectedUse->cu_def, namep, allSpecial, units);
else else
LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def
== EditRootDef, lefTech, lefHide, lefTopLayer, lefDoMaster); == EditRootDef, lefTech, lefHide, lefPinOnly,
lefTopLayer, lefDoMaster);
break; break;
case LEF_HELP: case LEF_HELP:
wrongNumArgs: wrongNumArgs:

View File

@ -1095,11 +1095,12 @@ LefWritePinHeader(f, lab)
*/ */
void 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 */ CellDef *def; /* Def for which to generate LEF output */
FILE *f; /* Output to this file */ FILE *f; /* Output to this file */
float scale; /* Output distance units conversion factor */ float scale; /* Output distance units conversion factor */
int setback; /* If >= 0, hide all detail except pins inside setback */ 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 toplayer; /* If TRUE, only output topmost layer of pins */
bool domaster; /* If TRUE, write masterslice layers */ bool domaster; /* If TRUE, write masterslice layers */
{ {
@ -1421,8 +1422,19 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster)
Rect carea; Rect carea;
labelLinkedList *newlll; labelLinkedList *newlll;
SelectChunk(&scx, lab->lab_type, 0, &carea, FALSE); if (pinonly == 0)
if (GEO_RECTNULL(&carea)) carea = labr; 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 */ /* Note that a sticky label could be placed over multiple */
/* tile types, which would cause SelectChunk to fail. So */ /* tile types, which would cause SelectChunk to fail. So */
@ -1445,16 +1457,47 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster)
Rect carea; Rect carea;
/* For -hide with setback, select the entire net and then */ /* For -hide with setback, select the entire net and then */
/* remove the part inside the setback area. Note that this */ /* remove the part inside the setback area. */
/* does not check if this causes the label to disappear. */
SelectNet(&scx, lab->lab_type, 0, NULL, FALSE); SelectNet(&scx, lab->lab_type, 0, NULL, FALSE);
GEO_EXPAND(&boundary, -setback, &carea); GEO_EXPAND(&boundary, -setback, &carea);
SelRemoveArea(&carea, &DBAllButSpaceAndDRCBits); 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 else
{
SelectNet(&scx, lab->lab_type, 0, NULL, FALSE); 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 // Search for gate and diff types and accumulate antenna
// areas. For gates, check for all gate types tied to // areas. For gates, check for all gate types tied to
// devices with MOSFET types (including "msubcircuit", etc.). // devices with MOSFET types (including "msubcircuit", etc.).
@ -1964,11 +2007,13 @@ lefGetProperties(stackItem, i, clientData)
*/ */
void void
LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, lefDoMaster, recurse) LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefPinOnly, lefTopLayer,
lefDoMaster, recurse)
CellUse *rootUse; CellUse *rootUse;
bool writeTopCell; bool writeTopCell;
bool lefTech; bool lefTech;
int lefHide; int lefHide;
int lefPinOnly;
bool lefTopLayer; bool lefTopLayer;
bool lefDoMaster; bool lefDoMaster;
bool recurse; bool recurse;
@ -2040,7 +2085,7 @@ LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, lefDoMaster, r
{ {
def->cd_client = (ClientData) 0; def->cd_client = (ClientData) 0;
if (!SigInterruptPending) if (!SigInterruptPending)
lefWriteMacro(def, f, scale, lefHide, lefTopLayer, lefDoMaster); lefWriteMacro(def, f, scale, lefHide, lefPinOnly, lefTopLayer, lefDoMaster);
} }
/* End the LEF file */ /* End the LEF file */
@ -2104,12 +2149,14 @@ lefDefPushFunc(use, recurse)
*/ */
void void
LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefTopLayer, lefDoMaster) LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefPinOnly, lefTopLayer,
lefDoMaster)
CellDef *def; /* Cell being written */ CellDef *def; /* Cell being written */
char *outName; /* Name of output file, or NULL. */ char *outName; /* Name of output file, or NULL. */
bool isRoot; /* Is this the root cell? */ bool isRoot; /* Is this the root cell? */
bool lefTech; /* Output layer information if TRUE */ bool lefTech; /* Output layer information if TRUE */
int lefHide; /* Hide detail other than pins if >= 0 */ 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 lefTopLayer; /* Use only topmost layer of pin if TRUE */
bool lefDoMaster; /* Write masterslice layers if TRUE */ bool lefDoMaster; /* Write masterslice layers if TRUE */
{ {
@ -2145,7 +2192,7 @@ LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefTopLayer, lefDoMaster)
HashKill(&propHashTbl); HashKill(&propHashTbl);
HashKill(&siteHashTbl); HashKill(&siteHashTbl);
} }
lefWriteMacro(def, f, scale, lefHide, lefTopLayer, lefDoMaster); lefWriteMacro(def, f, scale, lefHide, lefPinOnly, lefTopLayer, lefDoMaster);
/* End the LEF file */ /* End the LEF file */
fprintf(f, "END LIBRARY\n\n"); fprintf(f, "END LIBRARY\n\n");

View File

@ -35,6 +35,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/styles.h" #include "utils/styles.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "utils/main.h" #include "utils/main.h"
#include "select/select.h"
#include "netmenu/nmInt.h" #include "netmenu/nmInt.h"
/* The following owns describe the cell currently being highlighted, /* The following owns describe the cell currently being highlighted,
@ -294,7 +295,7 @@ NMShowUnderBox()
&DBAllButSpaceBits); &DBAllButSpaceBits);
DBCellClearDef(nmscShowUse->cu_def); DBCellClearDef(nmscShowUse->cu_def);
DBTreeCopyConnect(&scx, &DBAllButSpaceAndDRCBits, 0, DBTreeCopyConnect(&scx, &DBAllButSpaceAndDRCBits, 0,
DBConnectTbl, &TiPlaneRect, TRUE, nmscShowUse); DBConnectTbl, &TiPlaneRect, SEL_DO_LABELS, nmscShowUse);
DBWAreaChanged(nmscShowDef, &nmscShowDef->cd_bbox, DBW_ALLWINDOWS, DBWAreaChanged(nmscShowDef, &nmscShowDef->cd_bbox, DBW_ALLWINDOWS,
&DBAllButSpaceBits); &DBAllButSpaceBits);
NMShowCell(nmscShowUse, rootDef); NMShowCell(nmscShowUse, rootDef);
@ -418,6 +419,6 @@ nmSRNFunc(rect, name, label, cdarg)
scx.scx_trans = GeoIdentityTransform; scx.scx_trans = GeoIdentityTransform;
DBTreeCopyConnect(&scx, &DBConnectTbl[label->lab_type], 0, DBTreeCopyConnect(&scx, &DBConnectTbl[label->lab_type], 0,
DBConnectTbl, &TiPlaneRect, TRUE, nmscShowUse); DBConnectTbl, &TiPlaneRect, SEL_DO_LABELS, nmscShowUse);
return(0); return(0);
} }

View File

@ -538,7 +538,8 @@ PlotSetParam(name, value)
{ {
int j; 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++) for (j = 0 ; plotTypeNames[j] != NULL; j++)
{ {
TxError("\t%s\n", plotTypeNames[j]); TxError("\t%s\n", plotTypeNames[j]);

View File

@ -91,6 +91,7 @@ PlowRandomTest(def)
static char *dirnames[] = { "up", "down", "right", "left" }; static char *dirnames[] = { "up", "down", "right", "left" };
Rect plowRect; Rect plowRect;
int dir, plowDir; int dir, plowDir;
Plane *savePlane;
#ifdef notdef #ifdef notdef
strcpy(goodName, tempgood); strcpy(goodName, tempgood);
@ -101,7 +102,8 @@ PlowRandomTest(def)
sprintf(tempExt, "%s.ext", tempName); sprintf(tempExt, "%s.ext", tempName);
/* Generate "good" extracted file */ /* Generate "good" extracted file */
ExtCell(def, goodName, FALSE); savePlane = ExtCell(def, goodName, FALSE);
ExtRevertSubstrate(def, savePlane);
(void) sprintf(command, "sedplow %s", goodExt); (void) sprintf(command, "sedplow %s", goodExt);
system(command); system(command);
#endif /* notdef */ #endif /* notdef */
@ -136,7 +138,8 @@ PlowRandomTest(def)
#ifdef notdef #ifdef notdef
/* Extract to the temp file */ /* Extract to the temp file */
ExtCell(def, tempName, FALSE); savePlane = ExtCell(def, tempName, FALSE);
ExtRevertSubstrate(def, savePlane);
(void) sprintf(command, "sedplow %s", tempExt); (void) sprintf(command, "sedplow %s", tempExt);
system(command); system(command);

View File

@ -17,6 +17,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/geofast.h" #include "utils/geofast.h"
#include "tiles/tile.h" #include "tiles/tile.h"
#include "utils/hash.h" #include "utils/hash.h"
#include "utils/stack.h"
#include "database/database.h" #include "database/database.h"
#include "utils/malloc.h" #include "utils/malloc.h"
#include "textio/textio.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 "textio/txcommands.h"
#include "resis/resis.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 dbcUnconnectFunc();
extern int dbcConnectLabelFunc(); extern int dbcConnectLabelFunc();
extern int dbcConnectFuncDCS(); extern int dbcConnectFuncDCS();
@ -67,7 +44,6 @@ TileTypeBitMask ResSubsTypeBitMask;
/* Forward declarations */ /* Forward declarations */
extern void ResCalcPerimOverlap(); extern void ResCalcPerimOverlap();
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -100,7 +76,7 @@ dbcConnectFuncDCS(tile, cx)
TileType dinfo = 0; TileType dinfo = 0;
SearchContext *scx = cx->tc_scx; SearchContext *scx = cx->tc_scx;
SearchContext scx2; SearchContext scx2;
int pNum; int i, pNum;
CellDef *def; CellDef *def;
ExtDevice *devptr; ExtDevice *devptr;
TerminalPath tpath; TerminalPath tpath;
@ -296,29 +272,29 @@ dbcConnectFuncDCS(tile, cx)
newarea.r_ytop += 1; 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 */ /* 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 */ /* Reached list size limit---need to enlarge the list */
/* Double the size of the list every time we hit the limit */ /* Double the size of the list every time we hit the limit */
conSrArea *newlist; conSrArea *newlist;
int i, lastsize = csa2->csa2_size;
csa2->csa2_size *= 2; newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
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);
csa2->csa2_list = newlist; csa2->csa2_list = newlist;
csa2->csa2_top = 0;
} }
csa2->csa2_list[csa2->csa2_top].area = newarea; 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_connect = connect;
csa2.csa2_topscx = scx; csa2.csa2_topscx = scx;
csa2.csa2_size = CSA2_LIST_START_SIZE; csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_START_SIZE
* sizeof(conSrArea));
csa2.csa2_top = -1; csa2.csa2_top = -1;
csa2.csa2_lasttop = -1;
csa2.csa2_stack = StackNew(100);
if (first) if (first)
{ {
@ -474,7 +451,22 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse)
newmask = csa2.csa2_list[csa2.csa2_top].connectMask; newmask = csa2.csa2_list[csa2.csa2_top].connectMask;
scx->scx_area = csa2.csa2_list[csa2.csa2_top].area; scx->scx_area = csa2.csa2_list[csa2.csa2_top].area;
newtype = csa2.csa2_list[csa2.csa2_top].dinfo; 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) if (newtype & TT_DIAGONAL)
DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFuncDCS, DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFuncDCS,
(ClientData) &csa2); (ClientData) &csa2);
@ -482,6 +474,7 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse)
DBTreeSrTiles(scx, newmask, xMask, dbcConnectFuncDCS, (ClientData) &csa2); DBTreeSrTiles(scx, newmask, xMask, dbcConnectFuncDCS, (ClientData) &csa2);
} }
freeMagic((char *)csa2.csa2_list); freeMagic((char *)csa2.csa2_list);
StackFree(csa2.csa2_stack);
for (CurrentT = DevList; CurrentT != NULL; CurrentT=CurrentT->nextDev) for (CurrentT = DevList; CurrentT != NULL; CurrentT=CurrentT->nextDev)
{ {

View File

@ -37,10 +37,10 @@ resNode *ResNodeQueue=NULL; /* Pending nodes */
resNode *ResOriginNode=NULL; /* node where R=0 */ resNode *ResOriginNode=NULL; /* node where R=0 */
resNode *resCurrentNode; resNode *resCurrentNode;
int ResTileCount=0; /* Number of tiles rn_status */ int ResTileCount=0; /* Number of tiles rn_status */
extern Region *ResFirst(); extern Region *ResFirst();
extern Tile *FindStartTile(); extern Tile *FindStartTile();
extern int ResEachTile(); extern int ResEachTile();
extern int ResLaplaceTile(); extern int ResLaplaceTile();
extern ResSimNode *ResInitializeNode(); extern ResSimNode *ResInitializeNode();
extern HashTable ResNodeTable; extern HashTable ResNodeTable;
@ -217,6 +217,18 @@ ResMakePortBreakpoints(def)
plane = def->cd_planes[DBPlane(node->rs_ttype)]; plane = def->cd_planes[DBPlane(node->rs_ttype)];
rect = &(node->rs_bbox); 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); TTMaskSetOnlyType(&mask, node->rs_ttype);
(void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask, (void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask,
ResAddBreakpointFunc, (ClientData)node); ResAddBreakpointFunc, (ClientData)node);
@ -561,19 +573,18 @@ ResProcessTiles(goodies, origin)
* *
* Side effects: Produces a resistance network for the node. * Side effects: Produces a resistance network for the node.
* *
*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
bool bool
ResExtractNet(startlist,goodies,cellname) ResExtractNet(startlist, goodies, cellname)
ResFixPoint *startlist; ResFixPoint *startlist;
ResGlobalParams *goodies; ResGlobalParams *goodies;
char *cellname; char *cellname;
{ {
SearchContext scx; SearchContext scx;
int pNum; int pNum;
ResDevTile *DevTiles,*lasttile; ResDevTile *DevTiles, *lasttile;
TileTypeBitMask FirstTileMask; TileTypeBitMask FirstTileMask;
Point startpoint; Point startpoint;
ResFixPoint *fix; ResFixPoint *fix;
@ -581,10 +592,10 @@ ResExtractNet(startlist,goodies,cellname)
/* Make sure all global network variables are reset */ /* Make sure all global network variables are reset */
ResResList=NULL; ResResList = NULL;
ResNodeList=NULL; ResNodeList = NULL;
ResDevList=NULL; ResDevList = NULL;
ResNodeQueue=NULL; ResNodeQueue = NULL;
ResContactList = NULL; ResContactList = NULL;
ResOriginNode = NULL; ResOriginNode = NULL;
@ -630,17 +641,16 @@ ResExtractNet(startlist,goodies,cellname)
DBCellClearDef(ResUse->cu_def); DBCellClearDef(ResUse->cu_def);
/* Copy Paint */
/* Copy Paint */
DevTiles = NULL; DevTiles = NULL;
lasttile = 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 #ifdef ARIEL
if ((ResOptionsFlags & ResOpt_Power) && if ((ResOptionsFlags & ResOpt_Power) &&
strcmp(fix->fp_name,goodies->rg_name) != 0) continue; strcmp(fix->fp_name, goodies->rg_name) != 0) continue;
#endif #endif
scx.scx_area.r_ll.p_x = fix->fp_loc.p_x-2; 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; scx.scx_area.r_ur.p_y = fix->fp_loc.p_y+2;
startpoint = fix->fp_loc; startpoint = fix->fp_loc;
// Because fix->fp_ttype might come from a label with a sticky type /* Because fix->fp_ttype might come from a label with a sticky type
// that does not correspond exactly to the layer underneath, include * that does not correspond exactly to the layer underneath, include
// all connecting types. * all connecting types.
/* TTMaskSetOnlyType(&FirstTileMask,fix->fp_ttype); */ */
TTMaskSetMask(&FirstTileMask, &DBConnectTbl[fix->fp_ttype]); TTMaskSetMask(&FirstTileMask, &DBConnectTbl[fix->fp_ttype]);
newdevtiles = DBTreeCopyConnectDCS(&scx, &FirstTileMask, 0, newdevtiles = DBTreeCopyConnectDCS(&scx, &FirstTileMask, 0,
@ -662,13 +672,9 @@ ResExtractNet(startlist,goodies,cellname)
if (newdevtiles) if (newdevtiles)
{ {
if (DevTiles) if (DevTiles)
{
lasttile->nextDev = newdevtiles; lasttile->nextDev = newdevtiles;
}
else else
{
DevTiles = newdevtiles; DevTiles = newdevtiles;
}
lasttile = tmp; lasttile = tmp;
} }
} }
@ -682,7 +688,7 @@ ResExtractNet(startlist,goodies,cellname)
&DBAllButSpaceAndDRCBits, &DBAllButSpaceAndDRCBits,
ResConnectWithSD, extUnInit, ResFirst, ResConnectWithSD, extUnInit, ResFirst,
ResEach); ResEach);
ExtResetTiles(ResUse->cu_def,extUnInit); ExtResetTiles(ResUse->cu_def, extUnInit);
/* /*
* dissolve the contacts and find which tiles now cover the point * 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]; Plane *plane = ResUse->cu_def->cd_planes[pNum];
Rect *rect = &ResUse->cu_def->cd_bbox; Rect *rect = &ResUse->cu_def->cd_bbox;
ResFracture(plane,rect); ResFracture(plane, rect);
(void) DBSrPaintClient((Tile *) NULL,plane,rect, (void) DBSrPaintClient((Tile *) NULL,plane,rect,
&DBAllButSpaceAndDRCBits, &DBAllButSpaceAndDRCBits,
(ClientData) CLIENTDEFAULT, ResAddPlumbing, (ClientData) CLIENTDEFAULT, ResAddPlumbing,

View File

@ -48,52 +48,52 @@ extern ResSimNode *ResInitializeNode();
*/ */
void void
ResPrintExtRes(outextfile,resistors,nodename) ResPrintExtRes(outextfile, resistors, nodename)
FILE *outextfile; FILE *outextfile;
resResistor *resistors; resResistor *resistors;
char *nodename; char *nodename;
{ {
int nodenum=0; int nodenum=0;
char newname[MAXNAME]; char newname[MAXNAME];
HashEntry *entry; HashEntry *entry;
ResSimNode *node,*ResInitializeNode(); ResSimNode *node, *ResInitializeNode();
for (; resistors != NULL; resistors=resistors->rr_nextResistor) for (; resistors != NULL; resistors = resistors->rr_nextResistor)
{ {
/* /*
These names shouldn't be null; they should either be set by * These names shouldn't be null; they should either be set by
the device name or by the node printing routine. This * the device name or by the node printing routine. This
code is included in case the resistor network is printed * code is included in case the resistor network is printed
before the nodes. * before the nodes.
*/ */
if (resistors->rr_connection1->rn_name == NULL)
{ if (resistors->rr_connection1->rn_name == NULL)
(void)sprintf(newname,"%s%s%d",nodename,".r",nodenum++); {
entry = HashFind(&ResNodeTable,newname); (void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++);
node = ResInitializeNode(entry); entry = HashFind(&ResNodeTable, newname);
resistors->rr_connection1->rn_name = node->name; node = ResInitializeNode(entry);
node->oldname = nodename; resistors->rr_connection1->rn_name = node->name;
} node->oldname = nodename;
if (resistors->rr_connection2->rn_name == NULL) }
{ if (resistors->rr_connection2->rn_name == NULL)
(void)sprintf(newname,"%s%s%d",nodename,".r",nodenum++); {
entry = HashFind(&ResNodeTable,newname); (void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++);
node = ResInitializeNode(entry); entry = HashFind(&ResNodeTable, newname);
resistors->rr_connection2->rn_name = node->name; node = ResInitializeNode(entry);
node->oldname = nodename; resistors->rr_connection2->rn_name = node->name;
} node->oldname = nodename;
if (ResOptionsFlags & ResOpt_DoExtFile) }
{ if (ResOptionsFlags & ResOpt_DoExtFile)
fprintf(outextfile, "resist \"%s\" \"%s\" %g\n", {
fprintf(outextfile, "resist \"%s\" \"%s\" %g\n",
resistors->rr_connection1->rn_name, resistors->rr_connection1->rn_name,
resistors->rr_connection2->rn_name, resistors->rr_connection2->rn_name,
resistors->rr_value / (float)ExtCurStyle->exts_resistScale); resistors->rr_value / (float)ExtCurStyle->exts_resistScale);
} }
} }
} }
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
@ -166,7 +166,10 @@ ResPrintExtDev(outextfile, devices)
break; 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", fprintf(outextfile, " \"%s\" %d %s \"%s\" %d %s \"%s\" %d %s\n",
devices->gate->name, devices->gate->name,
@ -202,65 +205,64 @@ ResPrintExtNode(outextfile, nodelist, nodename)
FILE *outextfile; FILE *outextfile;
resNode *nodelist; resNode *nodelist;
char *nodename; char *nodename;
{ {
int nodenum=0; int nodenum = 0;
char newname[MAXNAME],tmpname[MAXNAME],*cp; char newname[MAXNAME], tmpname[MAXNAME], *cp;
HashEntry *entry; HashEntry *entry;
ResSimNode *node,*ResInitializeNode(); ResSimNode *node, *ResInitializeNode();
bool DoKillNode = TRUE; bool DoKillNode = TRUE;
resNode *snode = nodelist; resNode *snode = nodelist;
/* If any of the subnode names match the original node name, then */ /* 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. */ /* 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 (nodelist->rn_name != NULL)
if (!strcmp(nodelist->rn_name, nodename)) if (!strcmp(nodelist->rn_name, nodename))
{ {
DoKillNode = FALSE; DoKillNode = FALSE;
break; break;
} }
}
if ((ResOptionsFlags & ResOpt_DoExtFile) && DoKillNode) if ((ResOptionsFlags & ResOpt_DoExtFile) && DoKillNode)
{ {
fprintf(outextfile,"killnode \"%s\"\n",nodename); 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) for (; snode != NULL; snode = snode->rn_more)
{ {
if (snode->rn_name == NULL) if (snode->rn_name == NULL)
{ {
(void)sprintf(tmpname,"%s",nodename); (void)sprintf(tmpname,"%s",nodename);
cp = tmpname + strlen(tmpname) - 1; cp = tmpname + strlen(tmpname) - 1;
if (*cp == '!' || *cp == '#') *cp = '\0'; if (*cp == '!' || *cp == '#') *cp = '\0';
(void)sprintf(newname,"%s%s%d",tmpname,".n",nodenum++); (void)sprintf(newname, "%s%s%d", tmpname, ".n", nodenum++);
entry = HashFind(&ResNodeTable,newname); entry = HashFind(&ResNodeTable, newname);
node = ResInitializeNode(entry); node = ResInitializeNode(entry);
snode->rn_name = node->name; snode->rn_name = node->name;
node->oldname = nodename; node->oldname = nodename;
} }
if (ResOptionsFlags & ResOpt_DoExtFile) if (ResOptionsFlags & ResOpt_DoExtFile)
{ {
/* rnode name R C x y type (R is always 0) */ /* rnode name R C x y type (R is always 0) */
fprintf(outextfile, "rnode \"%s\" 0 %g %d %d %d\n", fprintf(outextfile, "rnode \"%s\" 0 %g %d %d %d\n",
snode->rn_name, snode->rn_name,
(snode->rn_float.rn_area/ (snode->rn_float.rn_area / ExtCurStyle->exts_capScale),
ExtCurStyle->exts_capScale),
snode->rn_loc.p_x, snode->rn_loc.p_x,
snode->rn_loc.p_y, snode->rn_loc.p_y,
/* the following is TEMPORARILY set to 0 */ /* the following is TEMPORARILY set to 0 */
0); 0);
} }
} }
} }
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
@ -276,39 +278,39 @@ ResPrintExtNode(outextfile, nodelist, nodename)
*/ */
void void
ResPrintStats(goodies,name) ResPrintStats(goodies, name)
ResGlobalParams *goodies; ResGlobalParams *goodies;
char *name; char *name;
{ {
static int totalnets=0,totalnodes=0,totalresistors=0; static int totalnets = 0, totalnodes = 0, totalresistors = 0;
int nodes,resistors; int nodes, resistors;
resNode *node; resNode *node;
resResistor *res; resResistor *res;
if (goodies == NULL) if (goodies == NULL)
{ {
TxError("nets:%d nodes:%d resistors:%d\n", TxError("nets:%d nodes:%d resistors:%d\n",
totalnets,totalnodes,totalresistors); totalnets, totalnodes, totalresistors);
totalnets=0; totalnets = 0;
totalnodes=0; totalnodes = 0;
totalresistors=0; totalresistors = 0;
return; return;
} }
nodes=0; nodes = 0;
resistors=0; resistors = 0;
totalnets++; totalnets++;
for (node = ResNodeList; node != NULL; node=node->rn_more) for (node = ResNodeList; node != NULL; node=node->rn_more)
{ {
nodes++; nodes++;
totalnodes++; totalnodes++;
} }
for (res = ResResList; res != NULL; res=res->rr_nextResistor) for (res = ResResList; res != NULL; res=res->rr_nextResistor)
{ {
resistors++; resistors++;
totalresistors++; totalresistors++;
} }
TxError("%s %d %d\n",name,nodes,resistors); TxError("%s %d %d\n", name, nodes, resistors);
} }
/* /*
@ -323,8 +325,8 @@ ResPrintStats(goodies,name)
void void
resWriteNodeName(fp, nodeptr) resWriteNodeName(fp, nodeptr)
FILE *fp; FILE *fp;
resNode *nodeptr; resNode *nodeptr;
{ {
if (nodeptr->rn_name == NULL) if (nodeptr->rn_name == NULL)
fprintf(fp, "N%d", nodeptr->rn_id); fprintf(fp, "N%d", nodeptr->rn_id);

View File

@ -27,12 +27,13 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "textio/textio.h" #include "textio/textio.h"
#include "extract/extract.h" #include "extract/extract.h"
#include "extract/extractInt.h" #include "extract/extractInt.h"
#include "extflat/extflat.h"
#include "windows/windows.h" #include "windows/windows.h"
#include "dbwind/dbwind.h" #include "dbwind/dbwind.h"
#include "utils/utils.h" #include "utils/utils.h"
#include "utils/tech.h" #include "utils/tech.h"
#include "textio/txcommands.h" #include "textio/txcommands.h"
#include "resis/resis.h" #include "resis/resis.h"
/* constants defining where various fields can be found in .sim files. */ /* 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 COUPLEVALUE 3
#define REALNAME 1 #define REALNAME 1
#define ALIASNAME 2 #define ALIASNAME 2
#define NODECIFCOMMAND 0 #define NODES_NODENAME 0
#define NODENODENAME 1 #define NODES_NODEX 1
#define NODENODEX 2 #define NODES_NODEY 2
#define NODENODEY 3 #define NODES_NODETYPE 3
#define NODETYPE 4
#define NODE_BBOX_LL_X 5 #define NODE_BBOX_LL_X 5
#define NODE_BBOX_LL_Y 6 #define NODE_BBOX_LL_Y 6
#define NODE_BBOX_UR_X 7 #define NODE_BBOX_UR_X 7
@ -119,10 +119,10 @@ extern void ResSimProcessDrivePoints();
*/ */
int int
ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc) ResReadSim(simfile, fetproc, capproc, resproc, attrproc, mergeproc, subproc)
char *simfile; char *simfile;
int (*fetproc)(),(*capproc)(),(*resproc)(); int (*fetproc)(), (*capproc)(), (*resproc)();
int (*attrproc)(),(*mergeproc)(); int (*attrproc)(), (*mergeproc)(), (*subproc)();
{ {
char line[MAXLINE][MAXTOKEN]; char line[MAXLINE][MAXTOKEN];
@ -172,6 +172,8 @@ ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc)
line[ATTRIBUTEVALUE], line[ATTRIBUTEVALUE],
simfile, &extfile); simfile, &extfile);
break; break;
case 'x': fettype = DBNumTypes;
break;
case 'D': case 'D':
case 'c': case 'c':
case 'r': break; case 'r': break;
@ -184,6 +186,10 @@ ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc)
TxError("Error in Reading device line of sim file.\n"); TxError("Error in Reading device line of sim file.\n");
result = 1; result = 1;
} }
else if (fettype == DBNumTypes)
{
result = (*subproc)(line);
}
else if (fettype != MINFINITY) else if (fettype != MINFINITY)
{ {
float sheetr; float sheetr;
@ -229,13 +235,6 @@ ResReadNode(nodefile)
char *cp; char *cp;
float lambda; 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); fp = PaOpen(nodefile,"r",".nodes",".", (char *) NULL, (char **) NULL);
if (fp == NULL) if (fp == NULL)
{ {
@ -244,19 +243,19 @@ ResReadNode(nodefile)
} }
while (gettokens(line,fp) != 0) while (gettokens(line,fp) != 0)
{ {
entry = HashFind(&ResNodeTable,line[NODENODENAME]); entry = HashFind(&ResNodeTable,line[NODES_NODENAME]);
node = ResInitializeNode(entry); node = ResInitializeNode(entry);
node->location.p_x = (int)((float)atof(line[NODENODEX]) / lambda); node->location.p_x = atoi(line[NODES_NODEX]);
node->location.p_y = (int)((float)atof(line[NODENODEY]) / lambda); node->location.p_y = atoi(line[NODES_NODEY]);
#ifdef ARIEL #ifdef ARIEL
node->rs_bbox.r_xbot = (int)((float)atof(line[NODE_BBOX_LL_X]) / lambda); node->rs_bbox.r_xbot = atoi(line[NODE_BBOX_LL_X]);
node->rs_bbox.r_ybot = (int)((float)atof(line[NODE_BBOX_LL_Y]) / lambda); node->rs_bbox.r_ybot = atoi(line[NODE_BBOX_LL_Y]);
node->rs_bbox.r_xtop = (int)((float)atof(line[NODE_BBOX_UR_X]) / lambda); node->rs_bbox.r_xtop = atoi(line[NODE_BBOX_UR_X]);
node->rs_bbox.r_ytop = (int)((float)atof(line[NODE_BBOX_UR_Y]) / lambda); node->rs_bbox.r_ytop = atoi(line[NODE_BBOX_UR_Y]);
#endif #endif
if (cp = strchr(line[NODETYPE], ';')) *cp = '\0'; if (cp = strchr(line[NODES_NODETYPE], ';')) *cp = '\0';
node->type = DBTechNameType(line[NODETYPE]); node->type = DBTechNameType(line[NODES_NODETYPE]);
if (node->type == -1) 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 int
ResSimDevice(line,rpersquare,ttype) ResSimDevice(line, rpersquare, ttype)
char line[][MAXTOKEN]; char line[][MAXTOKEN];
float rpersquare; float rpersquare;
TileType ttype; TileType ttype;
@ -428,7 +551,7 @@ ResSimDevice(line,rpersquare,ttype)
*/ */
int int
ResSimNewNode(line,type,device) ResSimNewNode(line, type, device)
char line[]; char line[];
int type; int type;
RDev *device; RDev *device;
@ -443,7 +566,7 @@ ResSimNewNode(line,type,device)
TxError("Missing device connection\n"); TxError("Missing device connection\n");
return(1); return(1);
} }
entry = HashFind(&ResNodeTable,line); entry = HashFind(&ResNodeTable, line);
node = ResInitializeNode(entry); node = ResInitializeNode(entry);
tptr = (devPtr *) mallocMagic((unsigned) (sizeof(devPtr))); tptr = (devPtr *) mallocMagic((unsigned) (sizeof(devPtr)));
tptr->thisDev = device; tptr->thisDev = device;
@ -458,6 +581,8 @@ ResSimNewNode(line,type,device)
break; break;
case DRAIN: device->drain = node; case DRAIN: device->drain = node;
break; break;
case SUBS: device->subs = node;
break;
default: TxError("Bad Terminal Specifier\n"); default: TxError("Bad Terminal Specifier\n");
break; break;
} }

View File

@ -37,9 +37,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
/* Time constants are produced by multiplying attofarads by milliohms, */ /* Time constants are produced by multiplying attofarads by milliohms, */
/* giving zeptoseconds (yes, really. Look it up). This constant */ /* 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 */ /* ResSimNode is a node read in from a sim file */
@ -105,8 +105,8 @@ ExtResisForDef(celldef, resisdata)
HashInit(&ResNodeTable, INITFLATSIZE, HT_STRINGKEYS); HashInit(&ResNodeTable, INITFLATSIZE, HT_STRINGKEYS);
/* read in .sim file */ /* read in .sim file */
result = (ResReadSim(celldef->cd_name, result = (ResReadSim(celldef->cd_name,
ResSimDevice,ResSimCapacitor,ResSimResistor, ResSimDevice, ResSimCapacitor, ResSimResistor,
ResSimAttribute,ResSimMerge) == 0); ResSimAttribute, ResSimMerge, ResSimSubckt) == 0);
if (result) if (result)
/* read in .nodes file */ /* read in .nodes file */
@ -766,12 +766,12 @@ ResCheckPorts(cellDef)
result = 0; result = 0;
if ((node = (ResSimNode *) HashGetValue(entry)) != NULL) 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); 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, node->location.p_x, node->location.p_y,
portloc.p_x, portloc.p_y); portloc.p_x, portloc.p_y);
TxFlushErr(); TxFlush();
node->drivepoint = portloc; node->drivepoint = portloc;
node->status |= FORCE; node->status |= FORCE;
} }
@ -782,9 +782,9 @@ ResCheckPorts(cellDef)
/* and a drivepoint. */ /* and a drivepoint. */
node = ResInitializeNode(entry); 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); 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,
portloc.p_x, portloc.p_y); portloc.p_x, portloc.p_y);
node->location = portloc; node->location = portloc;
@ -1111,37 +1111,33 @@ ResCheckSimNodes(celldef, resisdata)
if (total) if (total)
{ {
TxError("Total Nets: %d\nNets extracted: " TxPrintf("Total Nets: %d\nNets extracted: "
"%d (%f)\nNets output: %d (%f)\n", total, failed1, "%d (%f)\nNets output: %d (%f)\n", total, failed1,
(float)failed1 / (float)total, failed3, (float)failed1 / (float)total, failed3,
(float)failed3 / (float)total); (float)failed3 / (float)total);
} }
else else
{ {
TxError("Total Nodes: %d\n",total); TxPrintf("Total Nodes: %d\n",total);
} }
/* close output files */ /* close output files */
if (ResExtFile != NULL) if (ResExtFile != NULL)
{
(void) fclose(ResExtFile); (void) fclose(ResExtFile);
}
if (ResLumpFile != NULL) if (ResLumpFile != NULL)
{
(void) fclose(ResLumpFile); (void) fclose(ResLumpFile);
}
if (ResFHFile != NULL) if (ResFHFile != NULL)
{
(void) fclose(ResFHFile); (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. * 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. * 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. */ /* don't patch up networks. This cuts down on memory use. */
if ((ResOptionsFlags & (ResOpt_DoRsmFile | ResOpt_DoExtFile)) == 0) if ((ResOptionsFlags & (ResOpt_DoRsmFile | ResOpt_DoExtFile)) == 0)
{
return; return;
}
if (simDev->layout == NULL) if (simDev->layout == NULL)
{ {
layoutDev->rd_status |= RES_DEV_SAVE; layoutDev->rd_status |= RES_DEV_SAVE;
simDev->layout = layoutDev; simDev->layout = layoutDev;
} }
simDev->status |= TRUE; 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; notdecremented = TRUE;
if (simDev->gate == simNode) if (simDev->gate == simNode)
{ {
if ((gate=layoutDev->rd_fet_gate) != NULL) 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 */ /* name, the new one won't be used, so we decrement resNodeNum */
if (gate->rn_name != NULL) if (gate->rn_name != NULL)
{ {
@ -1197,45 +1192,41 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
notdecremented = FALSE; notdecremented = FALSE;
} }
ResFixDevName(newname,GATE,simDev,gate); ResFixDevName(newname, GATE, simDev, gate);
gate->rn_name = simDev->gate->name; gate->rn_name = simDev->gate->name;
(void)sprintf(newname,"%s%s%d",nodename,".t",resNodeNum++); sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++);
} }
else else
{
TxError("Missing gate connection\n"); TxError("Missing gate connection\n");
}
} }
if (simDev->source == simNode) if (simDev->source == simNode)
{ {
if (simDev->drain == simNode) if (simDev->drain == simNode)
{ {
if ((source=layoutDev->rd_fet_source) && if (((source = layoutDev->rd_fet_source) != NULL) &&
(drain=layoutDev->rd_fet_drain)) ((drain = layoutDev->rd_fet_drain) != NULL))
{ {
if (source->rn_name != NULL && notdecremented) if (source->rn_name != NULL && notdecremented)
{ {
resNodeNum--; resNodeNum--;
notdecremented = FALSE; notdecremented = FALSE;
} }
ResFixDevName(newname,SOURCE,simDev,source); ResFixDevName(newname, SOURCE, simDev, source);
source->rn_name = simDev->source->name; 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--; if (drain->rn_name != NULL) resNodeNum--;
ResFixDevName(newname,DRAIN,simDev,drain); ResFixDevName(newname, DRAIN, simDev, drain);
drain->rn_name = simDev->drain->name; drain->rn_name = simDev->drain->name;
/* one to each */ /* one to each */
} }
else else
{
TxError("Missing SD connection\n"); TxError("Missing SD connection\n");
}
} }
else 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) if (source != drain)
{ {
@ -1256,7 +1247,7 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
} }
layoutDev->rd_fet_drain = (resNode *)NULL; layoutDev->rd_fet_drain = (resNode *)NULL;
if (source->rn_name != NULL) resNodeNum--; if (source->rn_name != NULL) resNodeNum--;
ResFixDevName(newname,SOURCE,simDev,source); ResFixDevName(newname, SOURCE, simDev, source);
source->rn_name = simDev->source->name; source->rn_name = simDev->source->name;
} }
else else
@ -1266,22 +1257,20 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
resNodeNum--; resNodeNum--;
notdecremented = FALSE; notdecremented = FALSE;
} }
ResFixDevName(newname,SOURCE,simDev,source); ResFixDevName(newname, SOURCE, simDev, source);
source->rn_name = simDev->source->name; source->rn_name = simDev->source->name;
} }
} }
else else
{
TxError("missing SD connection\n"); TxError("missing SD connection\n");
}
} }
} }
else if (simDev->drain == simNode) 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) if (drain != source)
{ {
@ -1321,14 +1310,10 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
} }
} }
else else
{
TxError("missing SD connection\n"); TxError("missing SD connection\n");
}
} }
else else
{
resNodeNum--; resNodeNum--;
}
} }
@ -1346,7 +1331,7 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
*/ */
void void
ResFixDevName(line,type,device,layoutnode) ResFixDevName(line, type, device, layoutnode)
char line[]; char line[];
int type; int type;
RDev *device; RDev *device;
@ -1359,13 +1344,13 @@ ResFixDevName(line,type,device,layoutnode)
if (layoutnode->rn_name != NULL) if (layoutnode->rn_name != NULL)
{ {
entry = HashFind(&ResNodeTable,layoutnode->rn_name); entry = HashFind(&ResNodeTable, layoutnode->rn_name);
node = ResInitializeNode(entry); node = ResInitializeNode(entry);
} }
else else
{ {
entry = HashFind(&ResNodeTable,line); entry = HashFind(&ResNodeTable, line);
node = ResInitializeNode(entry); node = ResInitializeNode(entry);
} }
tptr = (devPtr *) mallocMagic((unsigned) (sizeof(devPtr))); 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. * drain or source by gate node number, then by drain (source) number.
* This places devices with identical connections next to one * This places devices with identical connections next to one
* another. * another.
@ -1448,8 +1433,8 @@ ResSortByGate(DevpointerList)
last = NULL; last = NULL;
while (working != NULL && (current = working->nextDev) != NULL) while (working != NULL && (current = working->nextDev) != NULL)
{ {
RDev *w = working->thisDev; RDev *w = working->thisDev;
RDev *c = current->thisDev; RDev *c = current->thisDev;
if (w->gate > c->gate) if (w->gate > c->gate)
{ {
@ -1503,17 +1488,12 @@ ResSortByGate(DevpointerList)
else else
{ {
if (working->nextDev != NULL) if (working->nextDev != NULL)
{
TxError("Bad Device pointer in sort\n"); TxError("Bad Device pointer in sort\n");
}
else else
{
working->nextDev = gatelist; working->nextDev = gatelist;
}
} }
} }
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
@ -1536,13 +1516,11 @@ ResWriteLumpFile(node)
{ {
if (gparams.rg_nodecap != 0) if (gparams.rg_nodecap != 0)
{ {
lumpedres = (int)((gparams.rg_Tdi/gparams.rg_nodecap lumpedres = (int)((gparams.rg_Tdi / gparams.rg_nodecap
-(float)(gparams.rg_bigdevres))/OHMSTOMILLIOHMS); - (float)(gparams.rg_bigdevres)) / OHMSTOMILLIOHMS);
} }
else else
{
lumpedres = 0; lumpedres = 0;
}
} }
else else
{ {
@ -1636,35 +1614,35 @@ ResWriteExtFile(celldef, node, tol, rctol, nidx, eidx)
RCdev = gparams.rg_bigdevres * gparams.rg_nodecap; RCdev = gparams.rg_bigdevres * gparams.rg_nodecap;
if (tol == 0.0 ||(node->status & FORCE) || if (tol == 0.0 || (node->status & FORCE) ||
(ResOptionsFlags & ResOpt_ExtractAll)|| (ResOptionsFlags & ResOpt_ExtractAll) ||
(ResOptionsFlags & ResOpt_Simplify)==0|| (ResOptionsFlags & ResOpt_Simplify) == 0 ||
(rctol+1)*RCdev < rctol*gparams.rg_Tdi) (rctol + 1) * RCdev < rctol * gparams.rg_Tdi)
{ {
ASSERT(gparams.rg_Tdi != -1,"ResWriteExtFile"); ASSERT(gparams.rg_Tdi != -1, "ResWriteExtFile");
(void)sprintf(newname,"%s",node->name); (void)sprintf(newname,"%s", node->name);
cp = newname+strlen(newname)-1; cp = newname + strlen(newname)-1;
if (*cp == '!' || *cp == '#') *cp = '\0'; 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) (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", TxPrintf("Adding %s; Tnew = %.2fns, Told = %.2fns\n",
node->name,gparams.rg_Tdi/Z_TO_N, RCdev/Z_TO_N); node->name, gparams.rg_Tdi / Z_TO_P, RCdev / Z_TO_P);
} }
} }
for (ptr = node->firstDev; ptr != NULL; ptr=ptr->nextDev) for (ptr = node->firstDev; ptr != NULL; ptr=ptr->nextDev)
{ {
if (layoutDev = ResGetDevice(&ptr->thisDev->location)) if (layoutDev = ResGetDevice(&ptr->thisDev->location))
{ {
ResFixUpConnections(ptr->thisDev,layoutDev,node,newname); ResFixUpConnections(ptr->thisDev, layoutDev, node, newname);
} }
} }
if (ResOptionsFlags & ResOpt_DoExtFile) if (ResOptionsFlags & ResOpt_DoExtFile)
{ {
ResPrintExtNode(ResExtFile,ResNodeList,node->name); ResPrintExtNode(ResExtFile, ResNodeList, node->name);
ResPrintExtRes(ResExtFile,ResResList,newname); ResPrintExtRes(ResExtFile, ResResList, newname);
} }
if (ResOptionsFlags & ResOpt_FastHenry) if (ResOptionsFlags & ResOpt_FastHenry)
{ {

View File

@ -293,6 +293,7 @@ typedef struct rdev
struct ressimnode *gate; /* Terminals of transistor. */ struct ressimnode *gate; /* Terminals of transistor. */
struct ressimnode *source; struct ressimnode *source;
struct ressimnode *drain; struct ressimnode *drain;
struct ressimnode *subs; /* Used with subcircuit type only */
Point location; /* Location of lower left point of */ Point location; /* Location of lower left point of */
/* device. */ /* device. */
float resistance; /* "Resistance" of device. */ float resistance; /* "Resistance" of device. */
@ -519,6 +520,7 @@ typedef struct capval
#define GATE 1 #define GATE 1
#define SOURCE 2 #define SOURCE 2
#define DRAIN 3 #define DRAIN 3
#define SUBS 4
#define DRIVEONLY 0x00001000 #define DRIVEONLY 0x00001000
#define ORIGIN 0x00000008 #define ORIGIN 0x00000008
@ -610,6 +612,7 @@ extern int ResSimCapacitor();
extern int ResSimResistor(); extern int ResSimResistor();
extern int ResSimAttribute(); extern int ResSimAttribute();
extern int ResSimMerge(); extern int ResSimMerge();
extern int ResSimSubckt();
extern int dbSrConnectStartFunc(); extern int dbSrConnectStartFunc();
extern int ResEach(),ResAddPlumbing(),ResRemovePlumbing(); extern int ResEach(),ResAddPlumbing(),ResRemovePlumbing();
extern float ResCalculateChildCapacitance(); extern float ResCalculateChildCapacitance();

View File

@ -52,26 +52,6 @@ int rtrDelta; /* Change in layer width */
* is used to clear the markings again. * 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 * The search path is maintained on the C runtime stack
* with rtrTileStack sructures. Each entry on the stack * with rtrTileStack sructures. Each entry on the stack

View File

@ -253,6 +253,144 @@ selClearFunc(scx)
else return 2; 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(); UndoDisable();
DBCellClearDef(Select2Def); DBCellClearDef(Select2Def);
DBTreeCopyConnect(scx, &connections[type], xMask, connections, DBTreeCopyConnect(scx, &connections[type], xMask, connections,
&TiPlaneRect, TRUE, Select2Use); &TiPlaneRect, SelectDoLabels, Select2Use);
UndoEnable(); UndoEnable();
/* Now transfer what we found into the main selection cell. Pick /* Now transfer what we found into the main selection cell. Pick
@ -850,7 +988,7 @@ SelectNet(scx, type, xMask, pArea, less)
UndoDisable(); UndoDisable();
DBCellClearDef(Select2Def); DBCellClearDef(Select2Def);
DBTreeCopyConnect(scx, &mask, xMask, DBConnectTbl, DBTreeCopyConnect(scx, &mask, xMask, DBConnectTbl,
&TiPlaneRect, TRUE, Select2Use); &TiPlaneRect, SelectDoLabels, Select2Use);
UndoEnable(); UndoEnable();
/* Network undo method added by Nishit and Tim, July 8-10, 2004 */ /* Network undo method added by Nishit and Tim, July 8-10, 2004 */
@ -1074,7 +1212,7 @@ SelectAndCopy2(newSourceDef)
SearchContext scx; SearchContext scx;
Rect editArea, labelArea, expanded; Rect editArea, labelArea, expanded;
int plane; int plane;
void (*savedPaintPlane)(); int (*savedPaintPlane)();
extern int selACPaintFunc(); /* Forward reference. */ extern int selACPaintFunc(); /* Forward reference. */
extern int selACCellFunc(); extern int selACCellFunc();

View File

@ -22,6 +22,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#endif /* not lint */ #endif /* not lint */
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/geometry.h" #include "utils/geometry.h"
@ -47,6 +48,7 @@ static int selStretchX, selStretchY; /* Stretch distances. Only one should
* ever be non-zero. * ever be non-zero.
*/ */
static TileType selStretchType; /* Type of material being stretched. */ static TileType selStretchType; /* Type of material being stretched. */
unsigned char SelectDoLabels = SEL_DO_LABELS; /* Whether or not to select subcell labels */
typedef struct planeAndArea typedef struct planeAndArea
{ {
@ -716,6 +718,43 @@ SelectShort(char *lab1, char *lab2)
destlab = selLabel; 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 */ /* Must be able to find both labels */
if (srclab == NULL || destlab == NULL) return NULL; if (srclab == NULL || destlab == NULL) return NULL;

View File

@ -372,7 +372,6 @@ SelectRemoveCellUse(use, trans)
{ {
SearchContext scx; SearchContext scx;
CellUse selectedUse;
SelRemoveCellArgs args; SelRemoveCellArgs args;
/* The search context is the area covered by the cell's bounding box in /* The search context is the area covered by the cell's bounding box in

View File

@ -35,6 +35,7 @@ extern void SelectRegion();
extern void SelectInit(); extern void SelectInit();
extern void SelectClear(); extern void SelectClear();
extern void SelectCell(); extern void SelectCell();
extern void SelectIntersect();
extern void SelRemoveArea(); extern void SelRemoveArea();
extern int SelRemoveSel2(); extern int SelRemoveSel2();
extern int SelectRemoveCellUse(); extern int SelectRemoveCellUse();
@ -56,6 +57,15 @@ extern void SelectStretch();
extern void SelectArray(); extern void SelectArray();
extern void SelectDump(); 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. */ /* The following is the root cell that contains the current selection. */
extern CellDef *SelectRootDef; extern CellDef *SelectRootDef;

View File

@ -31,6 +31,7 @@
#include "utils/geofast.h" #include "utils/geofast.h"
#include "tiles/tile.h" #include "tiles/tile.h"
#include "utils/hash.h" #include "utils/hash.h"
#include "utils/stack.h"
#include "database/database.h" #include "database/database.h"
#include "database/databaseInt.h" #include "database/databaseInt.h"
#include "textio/textio.h" #include "textio/textio.h"
@ -45,54 +46,6 @@
#include "utils/styles.h" #include "utils/styles.h"
#include "graphics/graphics.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 */ /* Forward declarations */
extern char *DBPrintUseId(); extern char *DBPrintUseId();
@ -303,27 +256,29 @@ SimConnectFunc(tile, cx)
return 1; 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 */ /* 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 */ /* Reached list size limit---need to enlarge the list */
/* Double the size of the list every time we hit the limit */ /* Double the size of the list every time we hit the limit */
conSrArea *newlist; conSrArea *newlist;
int i, lastsize = csa2->csa2_size;
csa2->csa2_size *= 2; newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
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);
csa2->csa2_list = newlist; csa2->csa2_list = newlist;
csa2->csa2_top = 0;
} }
csa2->csa2_list[csa2->csa2_top].area = newarea; 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_bounds = area;
csa2.csa2_connect = connect; csa2.csa2_connect = connect;
csa2.csa2_size = CSA2_LIST_START_SIZE; csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_START_SIZE
* sizeof(conSrArea));
csa2.csa2_top = -1; csa2.csa2_top = -1;
csa2.csa2_lasttop = -1;
csa2.csa2_stack = StackNew(100);
tpath.tp_first = tpath.tp_next = pathName; tpath.tp_first = tpath.tp_next = pathName;
tpath.tp_last = pathName + MAXPATHNAME; 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; newmask = csa2.csa2_list[csa2.csa2_top].connectMask;
scx->scx_area = csa2.csa2_list[csa2.csa2_top].area; scx->scx_area = csa2.csa2_list[csa2.csa2_top].area;
newtype = csa2.csa2_list[csa2.csa2_top].dinfo; 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) if (newtype & TT_DIAGONAL)
SimTreeSrNMTiles(scx, newtype, newmask, xMask, &tpath, SimTreeSrNMTiles(scx, newtype, newmask, xMask, &tpath,
@ -435,6 +405,7 @@ SimTreeCopyConnect(scx, mask, xMask, connect, area, destUse, Node_Name)
(ClientData) &csa2); (ClientData) &csa2);
} }
freeMagic((char *)csa2.csa2_list); freeMagic((char *)csa2.csa2_list);
StackFree(csa2.csa2_stack);
/* Recompute the bounding box of the destination and record /* Recompute the bounding box of the destination and record
* its area for redisplay. * its area for redisplay.
@ -636,7 +607,7 @@ SimSrConnect(def, startArea, mask, connect, bounds, func, clientData)
csa.csa_clientData = clientData; csa.csa_clientData = clientData;
csa.csa_clear = FALSE; csa.csa_clear = FALSE;
csa.csa_connect = connect; csa.csa_connect = connect;
csa.csa_plane = def->cd_planes[startPlane]; csa.csa_pNum = startPlane;
if (dbSrConnectFunc(startTile, &csa) != 0) result = 1; if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
return result; return result;

View File

@ -53,7 +53,8 @@ proc readspice {netfile} {
# Read data from file. Remove comment lines and concatenate # Read data from file. Remove comment lines and concatenate
# continuation lines. # continuation lines.
puts stderr "Annotating port orders from $netfile" puts stdout "Annotating port orders from $netfile"
flush stdout
set fdata {} set fdata {}
set lastline "" set lastline ""
while {[gets $fnet line] >= 0} { while {[gets $fnet line] >= 0} {
@ -109,14 +110,20 @@ proc readspice {netfile} {
# Make sure pins aren't duplicated by first moving all pin # Make sure pins aren't duplicated by first moving all pin
# indexes above the number of pins to check. # indexes above the number of pins to check.
puts stdout "Annotating cell $cell"
flush stdout
set npins [expr {[llength $ftokens] - 1}] set npins [expr {[llength $ftokens] - 1}]
set highport [port last] set highport [port last]
set outport $highport set outport $highport
if {$outport < $npins} {set outport $npins} if {$outport < $npins} {set outport $npins}
set p [port first] set p [port first]
while {$p != -1 && $p <= $highport} { while {$p != -1 && $p <= $highport} {
if {$p == ""} {
puts stderr "Error: $cell port numbering failed."
break
}
set p1 [port $p next] set p1 [port $p next]
set testpin [port $p name] set testpin [port $p name -quiet]
if {$testpin != ""} { if {$testpin != ""} {
port $p index $outport port $p index $outport
incr outport incr outport
@ -150,15 +157,15 @@ proc readspice {netfile} {
# a port. # a port.
set testpin $pin set testpin $pin
set pinidx [port $testpin index] set pinidx [port $testpin index -quiet]
if {$pinidx == ""} { if {$pinidx == ""} {
set testpin [string map {\[ < \] >]} $pin] set testpin [string map {\[ < \] >]} $pin]
set pinidx [port $testpin index] set pinidx [port $testpin index -quiet]
} }
if {$pinidx == ""} { if {$pinidx == ""} {
set testpin [string map {< \[ > \]} $pin] set testpin [string map {< \[ > \]} $pin]
set pinidx [port $testpin index] set pinidx [port $testpin index -quiet]
} }
# Handle issues with case insensitivity by getting # Handle issues with case insensitivity by getting
@ -167,9 +174,9 @@ proc readspice {netfile} {
if {$pinidx == ""} { if {$pinidx == ""} {
set highport [port last] set highport [port last]
for {set p 0} {$p <= $highport} {incr p} { 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]} { if {[string tolower $testpin] == [string tolower $pin]} {
set pinidx [port $testpin index] set pinidx [port $testpin index -quiet]
break break
} }
} }

View File

@ -8,6 +8,8 @@
# Revision 1 # Revision 1
# October 29, 2020 # October 29, 2020
# Revision 2 (names are hashed from properties) # 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 # Sets up the environment for a toolkit. The toolkit must
# supply a namespace that is the "library name". For each # 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" 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 # gencell
# #
@ -184,6 +487,11 @@ proc magic::gencell {gencell_name {instname {}} args} {
set gencell_type $gencell_name 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 == {}} { if {$instname == {}} {
# Case: Interactive, new device with parameters in args (if any) # Case: Interactive, new device with parameters in args (if any)
if {$spicemode == 1} { 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. # then keep the old instance name.
if {[string first $old_gname $instname] != 0} { if {[string first $old_gname $instname] != 0} {
set newinstname $instname 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 identify $newinstname

View File

@ -58,11 +58,31 @@ proc magic::makecrashbackup {} {
global Opts global Opts
*bypass crash save *bypass crash save
if {$Opts(backupinterval) > 0} { if {![catch set Opts(backupinterval)]} {
after $Opts(backupinterval) magic::makecrashbackup 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}} { proc magic::crashbackups {{option start}} {
global Opts global Opts
@ -71,12 +91,25 @@ proc magic::crashbackups {{option start}} {
if {[catch set Opts(backupinterval)]} { if {[catch set Opts(backupinterval)]} {
set Opts(backupinterval) 600000 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 - stop -
cancel { cancel {
after cancel magic::makecrashbackup after cancel magic::makecrashbackup
} }
disable {
after cancel magic::makecrashbackup
unset Opts(backupinterval)
}
} }
} }
@ -123,12 +156,17 @@ proc magic::popstack {} {
} else { } else {
set ltag [tag load] set ltag [tag load]
tag load {} tag load {}
suspendall
load [lindex $editstack end] load [lindex $editstack end]
set snaptype [snap]
snap internal
view [lindex $editstack end-1] view [lindex $editstack end-1]
tag load $ltag snap $snaptype
set editstack [lrange $editstack 0 end-2]
catch {magic::cellmanager} catch {magic::cellmanager}
catch {magic::captions} catch {magic::captions}
resumeall
tag load $ltag
set editstack [lrange $editstack 0 end-2]
} }
return return
} }

View File

@ -554,7 +554,6 @@ set Opts(crosshair) 0
set Opts(hidelocked) 0 set Opts(hidelocked) 0
set Opts(hidespecial) 0 set Opts(hidespecial) 0
set Opts(toolbar) 0 set Opts(toolbar) 0
set Opts(scale) 1.0
set Opts(toolscale) 1.0 set Opts(toolscale) 1.0
set Opts(drc) 1 set Opts(drc) 1
set Opts(autobuttontext) 1 set Opts(autobuttontext) 1
@ -1135,6 +1134,16 @@ proc magic::openwrapper {{cell ""} {framename ""}} {
toplevel $framename toplevel $framename
tkwait visibility $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 # Resize the window
if {[catch {wm geometry ${framename} $Winopts(${framename},geometry)}]} { if {[catch {wm geometry ${framename} $Winopts(${framename},geometry)}]} {
catch {wm geometry ${framename} $Opts(geometry)} catch {wm geometry ${framename} $Opts(geometry)}

View File

@ -770,6 +770,12 @@ mainInitAfterArgs()
return 0; return 0;
} }
void tcl_exit_hook(ClientData clientData)
{
TxResetTerminal();
exit(0);
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* mainInitFinal: * mainInitFinal:
@ -794,6 +800,9 @@ mainInitFinal()
char *rname; char *rname;
int result; int result;
/* Reset terminal if exit is called inside a TCL script */
Tcl_SetExitProc(tcl_exit_hook);
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
/* Read in system pre-startup file, if it exists. */ /* Read in system pre-startup file, if it exists. */
@ -1187,6 +1196,8 @@ mainInitFinal()
UndoFlush(); UndoFlush();
TxClearPoint(); TxClearPoint();
Tcl_SetExitProc(NULL);
return 0; return 0;
} }

View File

@ -26,8 +26,17 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <signal.h> #include <signal.h>
#include <unistd.h> /* for getpid() */ #include <unistd.h> /* for getpid() */
#include <sys/time.h> #include <sys/time.h>
#include <fcntl.h>
#include "tcltk/tclmagic.h"
#include "utils/main.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 #ifndef SIGEMT
#define SIGEMT 7 /* EMT instruction (SIGUNUSED) */ #define SIGEMT 7 /* EMT instruction (SIGUNUSED) */
@ -57,17 +66,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#endif #endif
#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 #ifndef FASYNC
# define FASYNC 00100 /* kludge for SUN2s */ # define FASYNC 00100 /* kludge for SUN2s */
#endif #endif