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 CalmaFlattenLimit = 10;
int NameConvertErrors = 0;
extern HashTable calmaDefInitHash;
/* forward declarations */
int calmaElementSref();
bool calmaParseElement();
void calmaUniqueCell();
/* Structure used when flattening the GDS hierarchy on read-in */
@ -306,8 +308,8 @@ calmaParseStructure(filename)
if (!calmaReadStringRecord(CALMA_STRNAME, &strname)) goto syntaxerror;
TxPrintf("Reading \"%s\".\n", strname);
if (CalmaReadOnly)
filepos = ftello(calmaInputFile);
/* Used for read-only and annotated LEF views */
filepos = ftello(calmaInputFile);
/* Set up the cell definition */
he = HashFind(&calmaDefInitHash, strname);
@ -348,51 +350,76 @@ calmaParseStructure(filename)
freeMagic(newname);
}
}
if (CalmaUnique) calmaUniqueCell(strname); /* Ensure uniqueness */
cifReadCellDef = calmaFindCell(strname, &was_called, &predefined);
HashSetValue(he, cifReadCellDef);
if (predefined == TRUE)
{
calmaNextCell();
return TRUE;
bool isAbstract;
/* If the cell was predefined, the "noduplicates" option was
* invoked, and the existing cell is an abstract view, then
* annotate the cell with the GDS file pointers to the cell
* data, and the GDS filename.
*/
DBPropGet(cifReadCellDef, "LEFview", &isAbstract);
if (!isAbstract)
{
calmaNextCell();
return TRUE;
}
calmaSkipTo(CALMA_ENDSTR);
}
DBCellClearDef(cifReadCellDef);
DBCellSetAvail(cifReadCellDef);
HashSetValue(he, cifReadCellDef);
cifCurReadPlanes = cifSubcellPlanes;
cifReadCellDef->cd_flags &= ~CDDEREFERENCE;
/* For read-only cells, set flag in def */
if (CalmaReadOnly)
cifReadCellDef->cd_flags |= CDVENDORGDS;
/* Skip CALMA_STRCLASS or CALMA_STRTYPE */
calmaSkipSet(structs);
/* Initialize the hash table for layer errors */
HashInit(&calmaLayerHash, 32, sizeof (CalmaLayerType) / sizeof (unsigned));
was_initialized = TRUE;
/* Body of structure: a sequence of elements */
osrefs = nsrefs = 0;
npaths = 0;
calmaNonManhattan = 0;
while (calmaParseElement(filename, &nsrefs, &npaths))
else
{
if (SigInterruptPending)
goto done;
if (nsrefs > osrefs && (nsrefs % 100) == 0)
TxPrintf(" %d uses\n", nsrefs);
osrefs = nsrefs;
DBCellClearDef(cifReadCellDef);
DBCellSetAvail(cifReadCellDef);
cifCurReadPlanes = cifSubcellPlanes;
cifReadCellDef->cd_flags &= ~CDDEREFERENCE;
/* For read-only cells, set flag in def */
if (CalmaReadOnly)
cifReadCellDef->cd_flags |= CDVENDORGDS;
/* Skip CALMA_STRCLASS or CALMA_STRTYPE */
calmaSkipSet(structs);
/* Initialize the hash table for layer errors */
HashInit(&calmaLayerHash, 32, sizeof (CalmaLayerType) / sizeof (unsigned));
was_initialized = TRUE;
/* Body of structure: a sequence of elements */
osrefs = nsrefs = 0;
npaths = 0;
calmaNonManhattan = 0;
while (calmaParseElement(filename, &nsrefs, &npaths))
{
if (SigInterruptPending)
goto done;
if (nsrefs > osrefs && (nsrefs % 100) == 0)
TxPrintf(" %d uses\n", nsrefs);
osrefs = nsrefs;
calmaNonManhattan = 0;
}
}
if (CalmaReadOnly)
if (CalmaReadOnly || predefined)
{
char cstring[1024];
/* Writing the file position into a string is slow, but */
/* it prevents requiring special handling when printing */
/* out the properties. */
char *fpcopy = (char *)mallocMagic(20);
char *fncopy = StrDup(NULL, filename);
char *fncopy;
/* Substitute variable for PDK path or ~ for home directory */
/* the same way that cell references are handled in .mag files. */
DBPathSubstitute(filename, cstring, cifReadCellDef);
fncopy = StrDup(NULL, cstring);
sprintf(fpcopy, "%"DLONG_PREFIX"d", (dlong) filepos);
DBPropPut(cifReadCellDef, "GDS_START", (ClientData)fpcopy);
@ -403,9 +430,11 @@ calmaParseStructure(filename)
DBPropPut(cifReadCellDef, "GDS_FILE", (ClientData)fncopy);
/* Do not lock the cell, or else we can't save the */
/* magic cell with its GDS pointers to disk. . . */
/* cifReadCellDef->cd_flags |= CDNOEDIT; */
if (predefined)
{
if (strname != NULL) freeMagic(strname);
return TRUE;
}
}
/* Check if the cell name matches the pattern list of cells to flatten */
@ -591,6 +620,25 @@ calmaParseElement(filename, pnsrefs, pnpaths)
return (calmaSkipTo(CALMA_ENDEL));
}
/*
* ----------------------------------------------------------------------------
*
* Callback procedure for enumerating any paint in a cell. Used to find if
* a cell needs to be retained after being flattened into the parent cell.
*
* Returns 1 always. Only called if a non-space tile was encountered.
*
* ----------------------------------------------------------------------------
*/
int
calmaEnumFunc(tile, plane)
Tile *tile;
int *plane;
{
return 1;
}
/*
* ----------------------------------------------------------------------------
*
@ -836,8 +884,24 @@ calmaElementSref(filename)
READI2(propAttrType);
if (propAttrType == CALMA_PROP_USENAME)
{
char *s;
if (!calmaReadStringRecord(CALMA_PROPVALUE, &useid))
return -1;
/* Magic prohibits comma and slash from use names */
for (s = useid; *s; s++)
if (*s == '/' || *s == ',')
{
if (NameConvertErrors < 100)
TxPrintf("\"%c\" character cannot be used in instance name; "
"converting to underscore\n", *s);
else if (NameConvertErrors == 100)
TxPrintf("More than 100 character changes; not reporting"
" further errors.\n");
*s = '_';
NameConvertErrors++;
}
}
else if (propAttrType == CALMA_PROP_ARRAY_LIMITS)
{
@ -981,9 +1045,38 @@ calmaElementSref(filename)
}
}
/* If cell has children in addition to paint to be flattened, */
/* then also generate an instance of the cell. */
/* When not reading with VENDORGDS, if a cell has contents */
/* other than the paint to be flattened, then also generate an */
/* instance of the cell. Otherwise (with VENDORGDS), always */
/* generate cell instances. Note that only paint and cells */
/* are counted, not labels (see below). */
else if (!(def->cd_flags & CDVENDORGDS))
{
int plane;
for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
if (DBSrPaintArea((Tile *)NULL, def->cd_planes[plane], &TiPlaneRect,
&DBAllButSpaceAndDRCBits, calmaEnumFunc, (ClientData)NULL))
break;
if ((plane < DBNumPlanes) || DBCellEnum(def, gdsHasUses, (ClientData)NULL))
{
use = DBCellNewUse(def, (useid) ? useid : (char *) NULL);
if (isArray)
DBMakeArray(use, &GeoIdentityTransform, xlo, ylo, xhi, yhi, xsep, ysep);
DBSetTrans(use, &trans);
DBPlaceCell(use, cifReadCellDef);
madeinst = TRUE;
}
else
{
/* (To do: Copy labels from flattened cells, with hierarchical */
/* names. Whether to do this or not should be an option.) */
/* TxPrintf("Removing instances of flattened cell %s in %s\n",
def->cd_name, cifReadCellDef->cd_name); */
madeinst = TRUE;
}
}
else
{
use = DBCellNewUse(def, (useid) ? useid : (char *) NULL);
@ -1045,6 +1138,65 @@ gdsCopyPaintFunc(tile, gdsCopyRec)
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* calmaUniqueCell --
*
* Attempt to find a cell in the GDS subcell name hash table.
* If one exists, rename its definition so that it will not
* be overwritten when the cell is redefined.
*
* Results:
* None.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
void
calmaUniqueCell(sname)
char *sname;
{
HashEntry *h;
CellDef *def, *testdef;
char *newname;
int snum = 0;
h = HashLookOnly(&CifCellTable, sname);
/* Existing entry with zero value indicates that the existing */
/* cell came from the same GDS file, so don't change anything. */
if ((h != NULL) && HashGetValue(h) == 0) return;
def = DBCellLookDef(sname);
if (def == (CellDef *)NULL)
return;
/* Cell may have been called but not yet defined---this is okay. */
else if ((def->cd_flags & CDAVAILABLE) == 0)
return;
testdef = def;
newname = (char *)mallocMagic(10 + strlen(sname));
while (testdef != NULL)
{
/* Keep appending suffix indexes until we find one not used */
sprintf(newname, "%s_%d", sname, ++snum);
testdef = DBCellLookDef(newname);
}
DBCellRenameDef(def, newname);
h = HashFind(&CifCellTable, (char *)sname);
HashSetValue(h, 0);
CalmaReadError("Warning: cell definition \"%s\" reused.\n", sname);
freeMagic(newname);
}
/*
* ----------------------------------------------------------------------------
*

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
* the GDS file is skipped.
*/
bool CalmaUnique = FALSE; /* If TRUE, then if a cell exists in
* memory with the same name as a cell
* in the GDS file, then the cell in
* memory is renamed to a unique
* identifier with a _N suffix.
*/
extern void calmaUnexpected();
extern int calmaWriteInitFunc();

View File

@ -613,7 +613,7 @@ calmaFullDump(def, fi, outf, filename)
FILE *outf;
char *filename;
{
int version, rval, i;
int version, rval;
char *libname = NULL, uniqlibname[4];
char *sptr, *viewopts;
bool isAbstract;
@ -657,24 +657,29 @@ calmaFullDump(def, fi, outf, filename)
viewopts = (char *)DBPropGet(def, "LEFview", &isAbstract);
if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
{
/* Generate a SHORT name for this cell (else it is easy to run into the
* GDS 32-character cellname limit). Save it in the hash record. The
* chance of generating the same prefix for a library that has items
* with conflicting names is vanishingly small, but to be pedantic, store
* the prefix in a hash table and check to make sure that uniqueness is
* ensured.
* ensured. NOTE: The first character of a SPICE name cannot be a
* number. Therefore the first character is alphabetical, and the second
* is alphanumeric. There are only 936 possible combinations, but this
* is only meant to distinguish cells in large IP blocks of unknown
* origin, of which only a limited number would be expected. Beware
* the implications for LVS, as the prefixed names from layout would
* need to be compared to un-prefixed names from another netlist.
*/
while (TRUE)
{
HashEntry *he2;
for (i = 0; i < 2; i++) {
rval = random() % 62;
rval = (rval < 26) ? ('A' + rval) : ((rval < 52) ? ('a' + rval - 26) :
('0' + rval - 52));
uniqlibname[i] = (char)(rval & 127);
}
rval = random() % 26;
rval = 'A' + rval;
uniqlibname[0] = (char)(rval & 127);
rval = random() % 36;
rval = (rval < 26) ? ('A' + rval) : ('0' + rval - 26);
uniqlibname[1] = (char)(rval & 127);
uniqlibname[2] = '_';
uniqlibname[3] = '\0';
he2 = HashLookOnly(&calmaPrefixHash, uniqlibname);
@ -809,6 +814,13 @@ calmaProcessDef(def, outf, do_library)
if (isReadOnly && hasContent && CalmaAddendum) return (0);
/* Give a strongly-worded statement about writing abstract views */
if (isAbstract && !isReadOnly)
TxError("Warning: Writing abstract view of \"%s\" to GDS. This is"
" probably not what you want to do.\n",
def->cd_name);
/*
* Output the definitions for any of our descendants that have
* not already been output. Numbers are assigned to the subcells

View File

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

View File

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

View File

@ -110,6 +110,7 @@ bool cmdDumpParseArgs();
#define CALMA_POLYS 19
#define CALMA_PATHS 20
#define CALMA_UNDEFINED 21
#define CALMA_UNIQUE 22
#define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */
@ -145,8 +146,8 @@ CmdCalma(w, cmd)
"library [yes|no] do not output the top level, only subcells",
"lower [yes|no] allow both upper and lower case in labels",
"merge [yes|no] merge tiles into polygons in the output",
"noduplicates [yes|no] do not read cells that exist before reading GDS",
"nodatestamp [yes|no] write a zero value creation date stamp",
"noduplicates [yes|no] do not read cells that exist before reading GDS",
"read file read Calma GDS-II format from \"file\"\n"
" into edit cell",
"readonly [yes|no] set cell as read-only and generate output from GDS file",
@ -160,6 +161,7 @@ CmdCalma(w, cmd)
" put wire paths into individual subcells",
"undefined [allow|disallow]\n"
" [dis]allow writing of GDS with calls to undefined cells",
"unique [yes|no] rename any cells with names duplicated in the GDS",
NULL
};
@ -599,6 +601,26 @@ CmdCalma(w, cmd)
CalmaNoDuplicates = (option < 4) ? FALSE : TRUE;
return;
case CALMA_UNIQUE:
if (cmd->tx_argc == 2)
{
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaUnique));
#else
TxPrintf("Cell defs that exist before reading GDS will be renamed.\n",
(CalmaUnique) ? "not " : "");
#endif
return;
}
else if (cmd->tx_argc != 3)
goto wrongNumArgs;
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
if (option < 0)
goto wrongNumArgs;
CalmaUnique = (option < 4) ? FALSE : TRUE;
return;
case CALMA_NO_STAMP:
if (cmd->tx_argc == 2)
{
@ -857,6 +879,9 @@ CmdCellname(w, cmd)
IDX_ORIENTATION, IDX_RENAME, IDX_READWRITE,
IDX_MODIFIED } optionType;
static char *cmdCellnameYesNo[] = {
"no", "false", "off", "0", "yes", "true", "on", "1", 0 };
if (strstr(cmd->tx_argv[0], "in"))
is_cellname = FALSE;
else
@ -1072,7 +1097,10 @@ CmdCellname(w, cmd)
}
else if (locargc == 4)
{
if (tolower(*cmd->tx_argv[3 + ((dolist) ? 1 : 0)]) == 't')
int subopt = Lookup(cmd->tx_argv[3 + ((dolist) ? 1 : 0)],
cmdCellnameYesNo);
if (subopt < 0) goto badusage;
else if (subopt >= 4)
{
/* Check if file is already read-write */
if (!(cellDef->cd_flags & CDNOEDIT))
@ -1084,13 +1112,11 @@ CmdCellname(w, cmd)
if (cellDef->cd_fd == -1)
dbReadOpen(cellDef, NULL, TRUE, NULL);
if (cellDef->cd_fd != -1)
cellDef->cd_flags &= ~CDNOEDIT;
else
TxError("Advisory lock held on cell %s\n", cellDef->cd_name);
#else
cellDef->cd_flags &= ~CDNOEDIT;
if (cellDef->cd_fd == -1)
TxError("Overriding advisory lock held on cell %s\n",
cellDef->cd_name);
#endif
cellDef->cd_flags &= ~CDNOEDIT;
WindAreaChanged(w, &w->w_screenArea);
CmdSetWindCaption(EditCellUse, EditRootDef);
}
@ -3921,6 +3947,216 @@ CmdDrc(w, cmd)
return;
}
/*
* ----------------------------------------------------------------------------
*
* cmdDropPaintCell ---
*
* Callback function used by cmdDropFunc. Called for each tile found in
* the edit cell hierarchy that matches paint that was in the selection.
* Paints layers from lMask (clientData) into the subcell containing the
* tile, within the area of the tile.
*
* Returns:
* Always returns zero to keep the search going.
*
* ----------------------------------------------------------------------------
*/
int cmdDropPaintCell(tile, cxp)
Tile *tile;
TreeContext *cxp;
{
CellDef *cellDef = cxp->tc_scx->scx_use->cu_def;
TileTypeBitMask *lMask = (TileTypeBitMask *)cxp->tc_filter->tf_arg;
int pNum;
TileType type;
Rect area;
if (SplitSide(tile))
type = SplitRightType(tile);
else
type = SplitLeftType(tile);
pNum = DBPlane(type);
TiToRect(tile, &area);
/* Clip to search area */
GEOCLIP(&area, &cxp->tc_scx->scx_area);
DBPaintMask(cellDef, &area, lMask);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* cmdDropFunc ---
*
* Callback function used by CmdDrop. Called for each tile found in the
* selection.
*
* Returns:
* Always returns zero to keep the search going.
*
* ----------------------------------------------------------------------------
*/
int
cmdDropFunc(Tile *tile, ClientData clientData)
{
TileTypeBitMask tMask, *lMask = (TileTypeBitMask *)clientData;
SearchContext scx;
TileType type;
TiToRect(tile, &scx.scx_area);
scx.scx_use = EditCellUse;
scx.scx_trans = GeoIdentityTransform;
if (SplitSide(tile))
type = SplitRightType(tile);
else
type = SplitLeftType(tile);
TTMaskSetOnlyType(&tMask, type);
DBTreeSrTiles(&scx, &tMask, 0, cmdDropPaintCell, (ClientData)lMask);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* cmdDropPaintFunc --
*
* Callback function to SelEnumPaint() from CmdDrop(). Sets a bit in
* the type mask passed as clientData for the type of the tile found
* in the selection.
*
* ----------------------------------------------------------------------------
*/
int
cmdDropPaintFunc(rect, type, mask)
Rect *rect; /* Not used. */
TileType type; /* Type of this piece of paint. */
TileTypeBitMask *mask; /* Place to OR in type's bit. */
{
if (type & TT_DIAGONAL)
type = (type & TT_SIDE) ? (type & TT_RIGHTMASK) >> 14 :
(type & TT_LEFTMASK);
TTMaskSetType(mask, type);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* CmdDrop --
*
* Implement the ":drop" command.
*
* Usage:
* drop <layers>
*
* where <layers> is a list of paint layers. The command requires an
* existing selection, with the expectation that the selection contains
* paint material that exists in subcells of the current edit cell. The
* "drop" command will copy the types in <layers> into every subcell in
* the hierarchy of the current edit cell that contains selected material.
*
* The purpose of this command is to deal with issues arising from layers
* in a vendor GDS file that must be in the same cell as a device layer
* in order for the device to be extracted properly, but instead is placed
* in a cell further up in the hierarchy. A typical example is the deep
* nwell layer, which isolates the transistor bulk terminal from the
* substrate. Without the deep nwell layer in the same cell as the
* transistor, the transistor will be extracted with the bulk terminal
* connected to the substrate.
*
* Note that the act of copying material down into a subcell means that
* material is then present in all instances of the subcell. There is
* no implementation as yet to handle the case where some instances of the
* same subcell require <layers> and some don't, which would necessitate
* splitting the subcell into (at least) two different subcells, one
* containing <layers> and one not. This needs to be implemented. A
* possible implementation would be: 1st pass: Find all subcells that
* will be modified. Make a list of the instances that will be modified.
* After the first pass, check if the list of instances contains all
* instances of the cell def. If so, then just modify the cell def. If
* not, then make a copy the cell def and split off the instances that
* get the modification to point to that cell def, then modify that cell
* def. 2nd pass: Run the "drop" command as before.
*
* Results:
* None.
*
* Side effects:
* Subcells are modified by adding paint.
*
* ----------------------------------------------------------------------------
*/
void
CmdDrop(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
TileType i;
TileTypeBitMask lMask, tMask;
CellUse *checkUse;
int pNum;
Rect editBox;
if (cmd->tx_argc != 2)
{
TxError("Usage: %s layers\n", cmd->tx_argv[0]);
return;
}
if (!ToolGetEditBox(&editBox)) return;
if (!CmdParseLayers(cmd->tx_argv[1], &lMask))
return;
checkUse = NULL;
if (EditRootDef == SelectRootDef)
checkUse = EditCellUse;
if (checkUse == NULL)
{
if (w == (MagWindow *)NULL)
windCheckOnlyWindow(&w, DBWclientID);
if (w) checkUse = (CellUse *)w->w_surfaceID;
}
if ((checkUse == NULL) || (checkUse->cu_def != SelectRootDef))
{
TxError("The selection does not match the edit cell.\n");
return;
}
TTMaskZero(&tMask);
SelEnumPaint(&DBAllButSpaceAndDRCBits, FALSE, (bool *)NULL,
cmdDropPaintFunc, (ClientData)&tMask);
if (TTMaskIsZero(&tMask)) return; /* Nothing selected */
for (i = TT_SELECTBASE; i < DBNumUserLayers; i++)
{
if (TTMaskHasType(&tMask, i))
{
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (TTMaskHasType(&DBPlaneTypes[pNum], i))
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum],
&SelectUse->cu_bbox, &tMask,
cmdDropFunc, (ClientData)&lMask);
}
}
DRCCheckThis(EditCellUse->cu_def, TT_CHECKPAINT, &editBox);
DBWAreaChanged(EditCellUse->cu_def, &editBox, DBW_ALLWINDOWS, &tMask);
DBReComputeBbox(EditCellUse->cu_def);
}
/*
* ----------------------------------------------------------------------------
*

View File

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

View File

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

View File

@ -50,6 +50,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
void CmdPaintEraseButton();
/* See the SetLabel command */
extern Label *DefaultLabel;
/*
* ----------------------------------------------------------------------------
@ -169,8 +172,8 @@ CmdLabel(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
TileType type;
int pos, font = -1, size = 0, rotate = 0, offx = 0, offy = 0;
TileType type = (TileType)(-1);
int pos = -1, font = -1, size = 0, rotate = 0, offx = 0, offy = 0;
bool sticky = FALSE;
int option;
char *p;
@ -185,6 +188,22 @@ CmdLabel(w, cmd)
p = cmd->tx_argv[1];
/*
* If the "setlabel" command has been used to set defaults, pick up
* the default values from DefaultLabel.
*/
if (DefaultLabel != NULL)
{
pos = DefaultLabel->lab_just;
font = DefaultLabel->lab_font;
size = DefaultLabel->lab_size;
rotate = DefaultLabel->lab_rotate;
offx = DefaultLabel->lab_offset.p_x;
offy = DefaultLabel->lab_offset.p_y;
sticky = (DefaultLabel->lab_flags & LABEL_STICKY) ? 1 : 0;
type = DefaultLabel->lab_type;
}
/*
* Find and check validity of position.
*/
@ -220,13 +239,14 @@ CmdLabel(w, cmd)
else
pos = GeoTransPos(&RootToEditTransform, pos);
}
else pos = -1;
if (font >= 0)
{
char *yp = NULL;
size = DBLambda[1];
if (DefaultLabel == NULL)
size = DBLambda[1];
if (cmd->tx_argc > 3)
if (StrIsNumeric(cmd->tx_argv[3]))
size = cmdScaleCoord(w, cmd->tx_argv[3], TRUE, TRUE, 8);
@ -304,7 +324,7 @@ CmdLabel(w, cmd)
TxError("Unknown layer: %s\n", cmd->tx_argv[cmd->tx_argc - 1]);
return;
}
} else type = -1;
}
CmdLabelProc(p, font, size, rotate, offx, offy, pos, sticky, type);
}
@ -1292,7 +1312,7 @@ complabel(const void *one, const void *two)
* or
* port makeall|renumber [connect_direction(s)]
* or
* port [name|num] class|use|shape|index [value]
* port [name|num] class|use|shape|index|name [value] [-quiet]
*
* num is the index of the port, usually beginning with 1. This indicates
* the order in which ports should be written to a subcircuit record
@ -1310,6 +1330,9 @@ complabel(const void *one, const void *two)
* "value" is a value string representing one of the valid port classes
* or uses.
*
* The "-quiet" option causes magic to fail quietly and return (in Tcl)
* an empty string if the value requested does not exist.
*
* Results:
* None.
*
@ -1346,7 +1369,7 @@ CmdPort(w, cmd)
int i, refidx, idx, pos, type, option, argc;
unsigned int dirmask;
bool found;
bool nonEdit = FALSE;
bool nonEdit = FALSE, doQuiet = FALSE;
Label *lab, *sl;
Rect editBox, tmpArea;
CellDef *editDef = EditCellUse->cu_def;
@ -1441,6 +1464,16 @@ CmdPort(w, cmd)
argstart = 1;
argc = cmd->tx_argc;
if (argc > 1)
{
if (!strcmp(cmd->tx_argv[argc - 1], "-quiet"))
{
doQuiet = TRUE;
argc--;
}
}
if (argc > 6 || argc == 1)
goto portWrongNumArgs;
else
@ -1483,10 +1516,13 @@ CmdPort(w, cmd)
}
if (lab == NULL)
{
if (StrIsInt(cmd->tx_argv[1]))
TxError("No label found with index %s.\n", cmd->tx_argv[1]);
else
TxError("No port found with name %s.\n", cmd->tx_argv[1]);
if (!doQuiet)
{
if (StrIsInt(cmd->tx_argv[1]))
TxError("No label found with index %s.\n", cmd->tx_argv[1]);
else
TxError("No port found with name %s.\n", cmd->tx_argv[1]);
}
return;
}
argstart = 2;
@ -1554,7 +1590,7 @@ CmdPort(w, cmd)
/* label "lab" must already be a port */
if (!(lab->lab_flags & PORT_DIR_MASK))
{
if (option != PORT_REMOVE)
if ((option != PORT_REMOVE) && (!doQuiet))
TxError("The selected label is not a port.\n");
return;
}
@ -1946,8 +1982,11 @@ parseindex:
if ((option != PORT_MAKEALL) && (lab->lab_flags & PORT_DIR_MASK))
{
/* For this syntax, the label must not already be a port */
TxError("The selected label is already a port.\n");
TxError("Do \"port help\" to get a list of options.\n");
if (!doQuiet)
{
TxError("The selected label is already a port.\n");
TxError("Do \"port help\" to get a list of options.\n");
}
return;
}

View File

@ -54,6 +54,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
extern void DisplayWindow();
/* Used by CmdSetLabel() */
Label *DefaultLabel;
/*
* ----------------------------------------------------------------------------
*
@ -525,6 +528,26 @@ CmdSee(w, cmd)
return;
}
#define SEL_AREA 0
#define SEL_VISIBLE 1
#define SEL_CELL 2
#define SEL_LABELS 3
#define SEL_INTERSECT 4
#define SEL_CLEAR 5
#define SEL_FLAT 6
#define SEL_HELP 7
#define SEL_KEEP 8
#define SEL_MOVE 9
#define SEL_PICK 10
#define SEL_SAVE 11
#define SEL_FEEDBACK 12
#define SEL_BBOX 13
#define SEL_BOX 14
#define SEL_CHUNK 15
#define SEL_REGION 16
#define SEL_NET 17
#define SEL_SHORT 18
#define SEL_DEFAULT 19
/*
* ----------------------------------------------------------------------------
@ -547,86 +570,10 @@ CmdSee(w, cmd)
/* ARGSUSED */
void
cmdSelectArea(layers, less)
char *layers; /* Which layers are to be selected. */
bool less;
{
SearchContext scx;
TileTypeBitMask mask;
int windowMask, xMask;
DBWclientRec *crec;
MagWindow *window;
bzero(&scx, sizeof(SearchContext));
window = ToolGetBoxWindow(&scx.scx_area, &windowMask);
if (window == NULL)
{
TxPrintf("The box isn't in a window.\n");
return;
}
/* Since the box may actually be in multiple windows, we have to
* be a bit careful. If the box is only in one window, then there's
* no problem. If it's in more than window, the cursor must
* disambiguate the windows.
*/
xMask = ((DBWclientRec *) window->w_clientData)->dbw_bitmask;
if ((windowMask & ~xMask) != 0)
{
window = CmdGetRootPoint((Point *) NULL, (Rect *) NULL);
xMask = ((DBWclientRec *) window->w_clientData)->dbw_bitmask;
if ((windowMask & xMask) == 0)
{
TxPrintf("The box is in more than one window; use the cursor\n");
TxPrintf("to select the one you want to select from.\n");
return;
}
}
if (CmdParseLayers(layers, &mask))
{
if (TTMaskEqual(&mask, &DBSpaceBits))
(void) CmdParseLayers("*,label", &mask);
TTMaskClearType(&mask, TT_SPACE);
}
else return;
if (less)
{
(void) SelRemoveArea(&scx.scx_area, &mask);
return;
}
scx.scx_use = (CellUse *) window->w_surfaceID;
scx.scx_trans = GeoIdentityTransform;
crec = (DBWclientRec *) window->w_clientData;
SelectArea(&scx, &mask, crec->dbw_bitmask);
}
/*
* ----------------------------------------------------------------------------
*
* cmdSelectVisible --
*
* This is a utility procedure used by CmdSelect to do area
* selection of visible paint.
*
* Results:
* None.
*
* Side effects:
* The selection is augmented to contain all the information on
* layers that is visible under the box, including paint, labels,
* and expanded subcells.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
void
cmdSelectVisible(layers, less)
cmdSelectArea(layers, less, option)
char *layers; /* Which layers are to be selected. */
bool less;
int option; /* Option from defined list above */
{
SearchContext scx;
TileTypeBitMask mask;
@ -677,6 +624,7 @@ cmdSelectVisible(layers, less)
scx.scx_use = (CellUse *) window->w_surfaceID;
scx.scx_trans = GeoIdentityTransform;
crec = (DBWclientRec *) window->w_clientData;
if (option == SEL_VISIBLE)
{
int i;
for (i = 0; i < DBNumUserLayers; i++)
@ -688,6 +636,85 @@ cmdSelectVisible(layers, less)
SelectArea(&scx, &mask, crec->dbw_bitmask);
}
/*
* ----------------------------------------------------------------------------
*
* cmdIntersectArea --
*
* This is a utility procedure used by CmdSelect to do area
* selection itersect.
*
* Results:
* None.
*
* Side effects:
* The selection is pared down to contain only the part of the
* original selection that intersects with the type "layer".
*
* ----------------------------------------------------------------------------
*/
void
cmdIntersectArea(layer)
char *layer; /* The layer to intersect with */
{
TileType ttype;
SearchContext scx;
int windowMask, xMask;
DBWclientRec *crec;
MagWindow *window;
char *lptr;
bool negate = FALSE;
bzero(&scx, sizeof(SearchContext));
window = ToolGetBoxWindow(&scx.scx_area, &windowMask);
if (window == NULL)
{
TxPrintf("The box isn't in a window.\n");
return;
}
/* Since the box may actually be in multiple windows, we have to
* be a bit careful. If the box is only in one window, then there's
* no problem. If it's in more than window, the cursor must
* disambiguate the windows.
*/
xMask = ((DBWclientRec *) window->w_clientData)->dbw_bitmask;
if ((windowMask & ~xMask) != 0)
{
window = CmdGetRootPoint((Point *) NULL, (Rect *) NULL);
xMask = ((DBWclientRec *) window->w_clientData)->dbw_bitmask;
if ((windowMask & xMask) == 0)
{
TxPrintf("The box is in more than one window; use the cursor\n");
TxPrintf("to select the one you want to select from.\n");
return;
}
}
scx.scx_use = (CellUse *) window->w_surfaceID;
scx.scx_trans = GeoIdentityTransform;
crec = (DBWclientRec *) window->w_clientData;
/* Special behavior: "!" or "~" in front of layer name intersects */
/* with NOT(layer). */
lptr = layer;
if ((*lptr == '~') || (*lptr == '!'))
{
negate = TRUE;
lptr++;
}
ttype = DBTechNameType(lptr);
if (ttype < 0) {
TxError("Cannot parse layer type \"%s\".\n", layer);
return;
}
SelectIntersect(&scx, ttype, crec->dbw_bitmask, negate);
}
/*
* ----------------------------------------------------------------------------
*
@ -725,30 +752,13 @@ CmdSelect(w, cmd)
* second table, due to a help message for ":select" with no arguments.
*/
#define SEL_AREA 0
#define SEL_VISIBLE 1
#define SEL_CELL 2
#define SEL_CLEAR 3
#define SEL_FLAT 4
#define SEL_HELP 5
#define SEL_KEEP 6
#define SEL_MOVE 7
#define SEL_PICK 8
#define SEL_SAVE 9
#define SEL_FEEDBACK 10
#define SEL_BBOX 11
#define SEL_BOX 12
#define SEL_CHUNK 13
#define SEL_REGION 14
#define SEL_NET 15
#define SEL_SHORT 16
#define SEL_DEFAULT 17
static char *cmdSelectOption[] =
{
"area",
"visible",
"cell",
"labels",
"intersection",
"clear",
"flat",
"help",
@ -774,6 +784,8 @@ CmdSelect(w, cmd)
"[more | less] area [layers] [de]select all info under box in layers",
"[more | less] visible [layers] [de]select all visible info under box in layers",
"[more | less | top] cell [name] [de]select cell under cursor, or \"name\"",
"[do | no] labels [do not] select subcell labels",
"[more | less] intersection [layers] [de]select intersection of layers",
"clear clear selection",
"flat flatten the contents of the selection",
"help print this message",
@ -819,7 +831,7 @@ CmdSelect(w, cmd)
* also used to step through multiple uses.
*/
static bool lessCycle = FALSE, lessCellCycle = FALSE;
char path[200], *printPath, **msg, **optionArgs, *feedtext;
char path[200], *printPath, **msg, **optionArgs, *feedtext, *pstr;
TerminalPath tpath;
CellUse *use;
CellDef *rootBoxDef;
@ -832,6 +844,7 @@ CmdSelect(w, cmd)
bool layerspec;
bool degenerate;
bool more = FALSE, less = FALSE, samePlace = TRUE;
unsigned char labelpolicy = SEL_DO_LABELS;
#ifdef MAGIC_WRAPPER
char *tclstr;
Tcl_Obj *lobj;
@ -851,7 +864,7 @@ CmdSelect(w, cmd)
/* See if "more" was given. If so, just strip off the "more" from
* the argument list and set the "more" flag. Similarly for options
* "less", "nocycle", "top", and "cell".
* "less", "do", "no", "nocycle", "top", and "cell".
*/
if (cmd->tx_argc >= 2)
@ -876,6 +889,7 @@ CmdSelect(w, cmd)
else if (!strncmp(cmd->tx_argv[1], "nocycle", arg1len))
{
samePlace = FALSE;
labelpolicy = SEL_NO_LABELS;
more = FALSE;
less = FALSE;
type = TT_SELECTBASE - 1; /* avoid cycling between types */
@ -890,6 +904,24 @@ CmdSelect(w, cmd)
optionArgs = &cmd->tx_argv[2];
cmd->tx_argc--;
}
else if (!strncmp(cmd->tx_argv[1], "do", arg1len))
{
labelpolicy = SEL_DO_LABELS;
optionArgs = &cmd->tx_argv[2];
cmd->tx_argc--;
}
else if (!strncmp(cmd->tx_argv[1], "no", arg1len))
{
labelpolicy = SEL_NO_LABELS;
optionArgs = &cmd->tx_argv[2];
cmd->tx_argc--;
}
else if (!strncmp(cmd->tx_argv[1], "simple", arg1len))
{
labelpolicy = SEL_SIMPLE_LABELS;
optionArgs = &cmd->tx_argv[2];
cmd->tx_argc--;
}
else if (!strncmp(cmd->tx_argv[1], "top", arg1len))
{
@ -954,7 +986,7 @@ CmdSelect(w, cmd)
}
if (!(more || less)) SelectClear();
if (cmd->tx_argc == 3)
cmdSelectArea(optionArgs[1], less);
cmdSelectArea(optionArgs[1], less, option);
else cmdSelectArea("*,label,subcell", less);
return;
@ -968,8 +1000,18 @@ CmdSelect(w, cmd)
if (cmd->tx_argc > 3) goto usageError;
if (!(more || less)) SelectClear();
if (cmd->tx_argc == 3)
cmdSelectVisible(optionArgs[1], less);
else cmdSelectVisible("*,label,subcell", less);
cmdSelectArea(optionArgs[1], less, option);
else cmdSelectArea("*,label,subcell", less, option);
return;
/*--------------------------------------------------------------------
* Select area that is the intersection of all the specified layers
*--------------------------------------------------------------------
*/
case SEL_INTERSECT:
if (cmd->tx_argc > 3) goto usageError;
cmdIntersectArea(optionArgs[1]);
return;
/*--------------------------------------------------------------------
@ -982,6 +1024,14 @@ CmdSelect(w, cmd)
SelectClear();
return;
case SEL_LABELS:
SelectDoLabels = labelpolicy;
if (SelectDoLabels)
TxPrintf("Selection includes subcell labels\n");
else
TxPrintf("Selection ignores subcell labels\n");
return;
/*--------------------------------------------------------------------
* Print out help information.
*--------------------------------------------------------------------
@ -1526,6 +1576,13 @@ Okay:
DBWSetBox(scx.scx_use->cu_def, &r);
#ifdef MAGIC_WRAPPER
/* Remove any backslash escapes so that Tcl_escape() doesn't
* double-escape them.
*/
for (pstr = printPath; *pstr != '\0';)
if ((*pstr == '\\') && ((*(pstr + 1) == '[') || (*(pstr + 1) == ']')))
memmove(pstr, pstr + 1, 1 + strlen(pstr + 1));
else pstr++;
tclstr = Tcl_escape(printPath);
Tcl_SetResult(magicinterp, tclstr, TCL_DYNAMIC);
#else
@ -1854,8 +1911,7 @@ cmdLabelFontFunc(label, cellUse, transform, font)
* Query or change properties of a (selected) label in the edit cell
*
* Usage:
* setlabel option [name]
*
* setlabel [-default] option [name]
*
* Option may be one of:
* text
@ -1875,6 +1931,11 @@ cmdLabelFontFunc(label, cellUse, transform, font)
* "setlabel font <name>" can be used without any select to load fonts
* from a startup script.
*
* Use with "-default" causes the DefaultLabel structure to be created
* (if not existing already) and set with the given value. Subsequent
* use of the "label" command will start with the given defaults, then
* apply whatever non-default values are specified in the command.
*
* ----------------------------------------------------------------------------
*/
@ -1895,10 +1956,12 @@ CmdSetLabel(w, cmd)
TxCommand *cmd;
{
int pos = -1, font = -1, size = 0, rotate = 0, flags = 0;
int locargc, argstart = 1;
char **msg;
Point offset;
TileType ttype;
int option;
bool doDefault = FALSE;
#ifdef MAGIC_WRAPPER
Tcl_Obj *lobj;
#endif
@ -1921,10 +1984,34 @@ CmdSetLabel(w, cmd)
NULL
};
if (cmd->tx_argc < 2 || cmd->tx_argc > 4)
locargc = cmd->tx_argc;
if (locargc > 2)
{
if (!strncmp(cmd->tx_argv[1], "-def", 4))
{
if (DefaultLabel == NULL)
{
DefaultLabel = (Label *)mallocMagic(sizeof(Label));
/* Set default defaults (lab_text is ignored) */
DefaultLabel->lab_just = -1;
DefaultLabel->lab_size = 0;
DefaultLabel->lab_font = -1;
DefaultLabel->lab_rotate = 0;
DefaultLabel->lab_flags = 0;
DefaultLabel->lab_offset.p_x = 0;
DefaultLabel->lab_offset.p_y = 0;
DefaultLabel->lab_type = (TileType)(-1);
}
doDefault = TRUE;
locargc--;
argstart++;
}
}
if (locargc < 2 || locargc > 4)
option = SETLABEL_HELP;
else
option = Lookup(cmd->tx_argv[1], cmdLabelSetOption);
option = Lookup(cmd->tx_argv[argstart], cmdLabelSetOption);
switch (option)
{
@ -1943,20 +2030,27 @@ CmdSetLabel(w, cmd)
break;
case SETLABEL_TEXT:
if (EditCellUse)
if (doDefault)
{
TxError("Cannot set a default label text.\n");
}
else if (EditCellUse)
{
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelTextFunc, (cmd->tx_argc == 3) ?
(ClientData)cmd->tx_argv[2] : (ClientData)NULL);
cmdLabelTextFunc, (locargc == 3) ?
(ClientData)cmd->tx_argv[argstart + 1] : (ClientData)NULL);
}
break;
case SETLABEL_FONT:
if (cmd->tx_argc >= 2 && cmd->tx_argc <= 4)
if (locargc >= 2 && locargc <= 4)
{
if ((cmd->tx_argc == 3) && StrIsInt(cmd->tx_argv[2]))
/* This option is used to see the font name corresponding
* to a font number.
*/
if ((locargc == 3) && StrIsInt(cmd->tx_argv[argstart + 1]))
{
int font = atoi(cmd->tx_argv[2]);
int font = atoi(cmd->tx_argv[argstart + 1]);
if (font < -1 || font >= DBNumFonts)
{
if (DBNumFonts == 0)
@ -1970,67 +2064,118 @@ CmdSetLabel(w, cmd)
else
TxPrintf("%s\n", DBFontList[font]->mf_name);
}
else if ((cmd->tx_argc == 3 || cmd->tx_argc == 4) &&
!StrIsInt(cmd->tx_argv[2]))
else if ((locargc == 3 || locargc == 4) &&
!StrIsInt(cmd->tx_argv[argstart + 1]))
{
font = DBNameToFont(cmd->tx_argv[2]);
font = DBNameToFont(cmd->tx_argv[argstart + 1]);
if (font < -1)
{
float scale = 1.0;
if ((cmd->tx_argc == 4) && StrIsNumeric(cmd->tx_argv[3]))
scale = (float)atof(cmd->tx_argv[3]);
if (DBLoadFont(cmd->tx_argv[2], scale) != 0)
TxError("Error loading font \"%s\"\n", cmd->tx_argv[2]);
font = DBNameToFont(cmd->tx_argv[2]);
if ((locargc == 4) && StrIsNumeric(cmd->tx_argv[argstart + 2]))
scale = (float)atof(cmd->tx_argv[argstart + 2]);
if (DBLoadFont(cmd->tx_argv[argstart + 1], scale) != 0)
TxError("Error loading font \"%s\"\n", cmd->tx_argv[argstart + 1]);
font = DBNameToFont(cmd->tx_argv[argstart + 1]);
if (font < -1) break;
}
}
if (EditCellUse)
if (doDefault)
{
if (locargc == 2)
{
font = DefaultLabel->lab_font;
if (font == -1)
#ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp, "default", TCL_VOLATILE);
#else
TxPrintf("default\n");
#endif
else
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp,
Tcl_NewStringObj(DBFontList[font]->mf_name, -1));
#else
TxPrintf("%s\n", DBFontList[font]->mf_name);
#endif
}
else
DefaultLabel->lab_font = font;
}
else if (EditCellUse)
{
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelFontFunc, (cmd->tx_argc == 3) ?
cmdLabelFontFunc, (locargc == 3) ?
(ClientData)&font : (ClientData)NULL);
}
}
break;
case SETLABEL_JUSTIFY:
if (cmd->tx_argc == 3)
if (locargc == 3)
{
pos = GeoNameToPos(cmd->tx_argv[2], FALSE, TRUE);
pos = GeoNameToPos(cmd->tx_argv[argstart + 1], FALSE, TRUE);
if (pos < 0) break;
}
if (EditCellUse)
if (doDefault)
{
if (locargc == 2)
{
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp,
Tcl_NewStringObj(GeoPosToName(DefaultLabel->lab_just),
-1));
#else
TxPrintf("%s\n", GeoPosToName(DefaultLabel->lab_just));
#endif
}
else
DefaultLabel->lab_just = pos;
}
else if (EditCellUse)
{
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelJustFunc, (cmd->tx_argc == 3) ?
cmdLabelJustFunc, (locargc == 3) ?
(ClientData)&pos : (ClientData)NULL);
}
break;
case SETLABEL_SIZE:
if (cmd->tx_argc == 3)
if (locargc == 3)
{
if (StrIsNumeric(cmd->tx_argv[2]))
size = cmdScaleCoord(w, cmd->tx_argv[2], TRUE, TRUE, 8);
if (StrIsNumeric(cmd->tx_argv[argstart + 1]))
size = cmdScaleCoord(w, cmd->tx_argv[argstart + 1], TRUE, TRUE, 8);
if (size <= 0) break;
}
if (EditCellUse)
if (doDefault)
{
if (locargc == 2)
{
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp,
Tcl_NewIntObj(DefaultLabel->lab_size));
#else
TxPrintf("%d\n", DefaultLabel->lab_size);
#endif
}
else
DefaultLabel->lab_size = size;
}
else if (EditCellUse)
{
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelSizeFunc, (cmd->tx_argc == 3) ?
cmdLabelSizeFunc, (locargc == 3) ?
(ClientData)&size : (ClientData)NULL);
}
break;
case SETLABEL_OFFSET:
if (cmd->tx_argc == 3)
if (locargc == 3)
{
char *yp;
if ((yp = strchr(cmd->tx_argv[2], ' ')) != NULL)
if ((yp = strchr(cmd->tx_argv[argstart + 1], ' ')) != NULL)
{
offset.p_x = cmdScaleCoord(w, cmd->tx_argv[2], TRUE, TRUE, 8);
offset.p_x = cmdScaleCoord(w, cmd->tx_argv[argstart + 1], TRUE, TRUE, 8);
offset.p_y = cmdScaleCoord(w, yp, TRUE, FALSE, 8);
}
else
@ -2039,67 +2184,138 @@ CmdSetLabel(w, cmd)
return;
}
}
else if (cmd->tx_argc == 4)
else if (locargc == 4)
{
offset.p_x = cmdScaleCoord(w, cmd->tx_argv[2], TRUE, TRUE, 8);
offset.p_y = cmdScaleCoord(w, cmd->tx_argv[3], TRUE, FALSE, 8);
offset.p_x = cmdScaleCoord(w, cmd->tx_argv[argstart + 1], TRUE, TRUE, 8);
offset.p_y = cmdScaleCoord(w, cmd->tx_argv[argstart + 2], TRUE, FALSE, 8);
}
if (EditCellUse)
if (doDefault)
{
if (locargc == 2)
{
#ifdef MAGIC_WRAPPER
Tcl_Obj *lobj;
Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(DefaultLabel->lab_offset.p_x));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(DefaultLabel->lab_offset.p_y));
Tcl_SetObjResult(magicinterp, lobj);
#else
TxPrintf("%d %d\n", DefaultLabel->lab_offset.p_x,
DefaultLabel->lab_offset.p_y);
#endif
}
else
DefaultLabel->lab_offset = offset;
}
else if (EditCellUse)
{
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelOffsetFunc, (cmd->tx_argc != 2) ?
cmdLabelOffsetFunc, (locargc != 2) ?
(ClientData)&offset : (ClientData)NULL);
}
break;
case SETLABEL_ROTATE:
if (cmd->tx_argc == 3)
if (locargc == 3)
{
if (StrIsInt(cmd->tx_argv[2]))
rotate = atoi(cmd->tx_argv[2]);
if (StrIsInt(cmd->tx_argv[argstart + 1]))
rotate = atoi(cmd->tx_argv[argstart + 1]);
}
if (EditCellUse)
if (doDefault)
{
if (locargc == 2)
{
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp,
Tcl_NewIntObj(DefaultLabel->lab_rotate));
#else
TxPrintf("%d\n", DefaultLabel->lab_rotate);
#endif
}
else
DefaultLabel->lab_rotate = rotate;
}
else if (EditCellUse)
{
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelRotateFunc, (cmd->tx_argc == 3) ?
cmdLabelRotateFunc, (locargc == 3) ?
(ClientData)&rotate : (ClientData)NULL);
}
break;
case SETLABEL_STICKY:
if (cmd->tx_argc == 3)
if (locargc == 3)
{
option = Lookup(cmd->tx_argv[2], cmdLabelYesNo);
option = Lookup(cmd->tx_argv[argstart + 1], cmdLabelYesNo);
if (option < 0)
{
TxError("Unknown sticky option \"%s\"\n", cmd->tx_argv[2]);
TxError("Unknown sticky option \"%s\"\n", cmd->tx_argv[argstart + 1]);
break;
}
flags = (option <= 3) ? 0 : LABEL_STICKY;
}
if (EditCellUse)
if (doDefault)
{
if (locargc == 2)
{
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp,
Tcl_NewBooleanObj((DefaultLabel->lab_flags &
LABEL_STICKY) ? TRUE : FALSE));
#else
TxPrintf("%d\n", (DefaultLabel->lab_flags & LABEL_STICKY) ? 1 : 0);
#endif
}
else
DefaultLabel->lab_flags = flags;
}
else if (EditCellUse)
{
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelStickyFunc, (cmd->tx_argc == 3) ?
cmdLabelStickyFunc, (locargc == 3) ?
(ClientData)&flags : (ClientData)NULL);
}
break;
case SETLABEL_LAYER:
if (cmd->tx_argc == 3)
if (locargc == 3)
{
if (!strcasecmp(cmd->tx_argv[2], "default"))
if (!strcasecmp(cmd->tx_argv[argstart + 1], "default"))
ttype = -1;
else
{
ttype = DBTechNoisyNameType(cmd->tx_argv[2]);
ttype = DBTechNoisyNameType(cmd->tx_argv[argstart + 1]);
if (ttype < 0) break;
}
}
if (EditCellUse)
if (doDefault)
{
if (locargc == 2)
{
if (DefaultLabel->lab_type == (TileType)(-1))
#ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp, "default", TCL_VOLATILE);
#else
TxPrintf("default\n");
#endif
else
#ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp,
DBTypeLongNameTbl[DefaultLabel->lab_type],
TCL_VOLATILE);
#else
TxPrintf("%s\n", DBTypeLongNameTbl[DefaultLabel->lab_type]);
#endif
}
else
DefaultLabel->lab_type = ttype;
}
else if (EditCellUse)
{
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelLayerFunc, (cmd->tx_argc == 3) ?
cmdLabelLayerFunc, (locargc == 3) ?
(ClientData)&ttype : (ClientData)NULL);
}
break;
@ -2113,7 +2329,7 @@ CmdSetLabel(w, cmd)
break;
default:
TxError("Unknown setlabel option \"%s\"\n", cmd->tx_argv[1]);
TxError("Unknown setlabel option \"%s\"\n", cmd->tx_argv[argstart]);
break;
}
}

View File

@ -825,7 +825,6 @@ int cmdWhatPrintCell(tile, cxp)
}
if (curlid == NULL)
{
TxPrintf(" %s ", CurrCellName);
curlid = (struct linked_id *)mallocMagic(sizeof(struct linked_id));
curlid->lid_name = CurrCellName;
curlid->lid_next = *lid;
@ -844,6 +843,41 @@ typedef struct labelstore
static int moreLabelEntries, labelEntryCount;
static LabelStore *labelBlockTop, *labelEntry;
/*
* ----------------------------------------------------------------------------
*
* cmdFindWhatTileFunc ---
*
* Callback function for CmdWhat(). Given a tile found in the current
* selection, searches the database to find what cell or cells that type
* belongs to.
*
* ----------------------------------------------------------------------------
*/
int
cmdFindWhatTileFunc(Tile *tile, ClientData clientData)
{
struct linked_id **lid = (struct linked_id **)clientData;
SearchContext scx;
TileTypeBitMask tmask;
TileType type;
TiToRect(tile, &scx.scx_area);
scx.scx_use = EditCellUse;
scx.scx_trans = GeoIdentityTransform;
if (SplitSide(tile))
type = SplitRightType(tile);
else
type = SplitLeftType(tile);
TTMaskSetOnlyType(&tmask, type);
DBTreeSrTiles(&scx, &tmask, 0, cmdWhatPrintCell, (ClientData)lid);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
@ -852,7 +886,7 @@ static LabelStore *labelBlockTop, *labelEntry;
* Print out information about what's selected.
*
* Usage:
* what [-list]
* what [-list[all]]
*
* Results:
* None.
@ -861,7 +895,8 @@ static LabelStore *labelBlockTop, *labelEntry;
* Information gets printed to identify the kinds of paint, plus
* labels and subcells, that are selected.
* In the TCL version, the "-list" option puts the result in a
* nested TCL list.
* nested TCL list. The "-listall" variant gives more information
* about what cell(s) each type exists in, in the type list.
*
* ----------------------------------------------------------------------------
*/
@ -873,14 +908,12 @@ CmdWhat(w, cmd)
{
int i, locargc;
bool foundAny;
bool doList = FALSE;
bool doList = FALSE, doListAll = FALSE;
TileTypeBitMask layers, maskBits, *rMask;
SearchContext scx;
CellUse *CheckUse;
struct linked_id *lid;
#ifdef MAGIC_WRAPPER
Tcl_Obj *lobj, *paintobj, *labelobj, *cellobj;
Tcl_Obj *lobj, *paintobj, *paintcellobj, *celllistobj, *labelobj, *cellobj;
extern int cmdWhatCellListFunc();
#endif
@ -890,14 +923,20 @@ CmdWhat(w, cmd)
locargc = cmd->tx_argc;
#ifdef MAGIC_WRAPPER
if ((locargc == 2) && !strncmp(cmd->tx_argv[locargc - 1], "-list", 5))
if (locargc == 2)
{
doList = TRUE;
locargc--;
lobj = Tcl_NewListObj(0, NULL);
paintobj = Tcl_NewListObj(0, NULL);
labelobj = Tcl_NewListObj(0, NULL);
cellobj = Tcl_NewListObj(0, NULL);
if (!strncmp(cmd->tx_argv[locargc - 1], "-list", 5))
{
if (!strncmp(cmd->tx_argv[locargc - 1], "-listall", 8))
doListAll = TRUE;
else
doList = TRUE;
locargc--;
lobj = Tcl_NewListObj(0, NULL);
paintobj = Tcl_NewListObj(0, NULL);
labelobj = Tcl_NewListObj(0, NULL);
cellobj = Tcl_NewListObj(0, NULL);
}
}
if (locargc > 1)
{
@ -959,29 +998,69 @@ CmdWhat(w, cmd)
}
if ((CheckUse != NULL) && (CheckUse->cu_def == SelectRootDef))
{
scx.scx_use = CheckUse;
scx.scx_area = SelectUse->cu_bbox; // BSI
scx.scx_trans = GeoIdentityTransform; // BSI
CellUse *saveUse = EditCellUse;
struct linked_id *lid, *lidp;
int pNum;
TxPrintf("Selected mask layers:\n");
EditCellUse = CheckUse;
if (!doListAll) TxPrintf("Selected mask layers:\n");
for (i = TT_SELECTBASE; i < DBNumUserLayers; i++)
{
if (TTMaskHasType(&layers, i))
{
lid = NULL;
TxPrintf(" %-8s (", DBTypeLongName(i));
TTMaskSetOnlyType(&maskBits, i);
if (DBIsContact(i)) DBMaskAddStacking(&maskBits);
DBTreeSrTiles(&scx, &maskBits, 0, cmdWhatPrintCell,
(ClientData)&lid);
TxPrintf(")\n");
while (lid != NULL)
if (doListAll) paintcellobj = Tcl_NewListObj(0, NULL);
/* Search selection for tiles of this type, then */
/* call cmdFindWhatTileFunc() to search the cell */
/* def in the area of that tile to determine what */
/* cell or subcell that tile belongs to. */
lid = NULL;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (TTMaskHasType(&DBPlaneTypes[pNum], i))
{
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum],
&SelectUse->cu_bbox, &maskBits,
cmdFindWhatTileFunc, (ClientData)&lid);
}
if (!doListAll)
{
freeMagic(lid);
lid = lid->lid_next;
TxPrintf(" %-8s (", DBTypeLongName(i));
for (lidp = lid; lidp; lidp = lidp->lid_next)
TxPrintf(" %s ", lidp->lid_name);
TxPrintf(")\n");
}
else
{
Tcl_ListObjAppendElement(magicinterp, paintcellobj,
Tcl_NewStringObj(DBTypeLongName(i), -1));
celllistobj = Tcl_NewListObj(0, NULL);
for (lidp = lid; lidp; lidp = lidp->lid_next)
Tcl_ListObjAppendElement(magicinterp, celllistobj,
Tcl_NewStringObj(lidp->lid_name, -1));
Tcl_ListObjAppendElement(magicinterp, paintcellobj,
celllistobj);
}
while (lid != NULL)
{
freeMagic(lid);
lid = lid->lid_next;
}
if (doListAll)
Tcl_ListObjAppendElement(magicinterp, paintobj,
paintcellobj);
}
}
EditCellUse = saveUse;
}
else
{
@ -1008,7 +1087,7 @@ CmdWhat(w, cmd)
qsort(labelBlockTop, labelEntryCount, sizeof(LabelStore), orderLabelFunc);
#ifdef MAGIC_WRAPPER
if (doList)
if (doList || doListAll)
{
Tcl_Obj *newtriple;
for (labelEntry = labelBlockTop; labelEntryCount-- > 0; labelEntry++)
@ -1052,7 +1131,7 @@ CmdWhat(w, cmd)
foundAny = FALSE;
#ifdef MAGIC_WRAPPER
if (doList)
if (doList || doListAll)
SelEnumCells(FALSE, (bool *) NULL, (SearchContext *) NULL,
cmdWhatCellListFunc, (ClientData) cellobj);
else
@ -1061,7 +1140,7 @@ CmdWhat(w, cmd)
cmdWhatCellFunc, (ClientData) &foundAny);
#ifdef MAGIC_WRAPPER
if (doList)
if (doList || doListAll)
{
Tcl_ListObjAppendElement(magicinterp, lobj, paintobj);
Tcl_ListObjAppendElement(magicinterp, lobj, labelobj);
@ -1926,7 +2005,7 @@ CmdXor(w, cmd)
PaintResultType DBXORResultTbl[NP][NT][NT];
PaintResultType (*curPaintSave)[NT][NT];
void (*curPlaneSave)();
int (*curPlaneSave)();
int p, t, h;

View File

@ -118,6 +118,7 @@ DBCellFindDup(use, parent)
* ----------------------------------------------------------------------------
*
* DBPlaceCell --
* DBPlaceCellNoModify --
*
* Add a CellUse to the subcell tile plane of a CellDef.
* Assumes prior check that the new CellUse is not an exact duplicate
@ -162,11 +163,47 @@ DBPlaceCell (use, def)
SigEnableInterrupts();
}
/* Like DBPlaceCell(), but don't change the flags of the parent cell. */
/* This is needed by the bounding box recalculation routine, which may */
/* cause the cell to be deleted and replaced for the purpose of */
/* capturing the bounding box information in the BPlane structure, but */
/* this does not mean that anything in the parent cell has changed. */
void
DBPlaceCellNoModify (use, def)
CellUse * use; /* new celluse to add to subcell tile plane */
CellDef * def; /* parent cell's definition */
{
Rect rect; /* argument to DBSrCellPlaneArea(), placeCellFunc() */
BPlane *bplane; /* argument to DBSrCellPlaneArea(), placeCellFunc() */
struct searchArg arg; /* argument to placeCellFunc() */
ASSERT(use != (CellUse *) NULL, "DBPlaceCell");
ASSERT(def, "DBPlaceCell");
/* To do: Check non-duplicate placement, check non-duplicate ID */
use->cu_parent = def;
/* Be careful not to permit interrupts during this, or the
* database could be left in a trashed state.
*/
SigDisableInterrupts();
BPAdd(def->cd_cellPlane, use);
if (UndoIsEnabled())
DBUndoCellUse(use, UNDO_CELL_PLACE);
SigEnableInterrupts();
}
/*
* ----------------------------------------------------------------------------
* DBDeleteCell --
*
* Remove a CellUse from the subcell tile plane of a CellDef.
* If "nomodify" is TRUE, then don't set the parent cell's CDMODIFIED flag.
* This is needed when recomputing the bounding box, which should not by
* itself change the modified state.
*
* Results:
* None.
@ -197,3 +234,39 @@ DBDeleteCell (use)
SigEnableInterrupts();
}
/*
* ----------------------------------------------------------------------------
* DBDeleteCellNoModify --
*
* Remove a CellUse from the subcell tile plane of a CellDef, as above,
* but don't set the parent cell's CDMODIFIED flag. This is needed when
* recomputing the bounding box, which should not by itself change the
* modified state.
*
* Results:
* None.
*
* Side effects:
* Modifies the subcell tile plane of the CellDef, sets the
* parent pointer of the deleted CellUse to NULL.
* ----------------------------------------------------------------------------
*/
void
DBDeleteCellNoModify (use)
CellUse * use;
{
ASSERT(use != (CellUse *) NULL, "DBDeleteCell");
/* It's important that this code run with interrupts disabled,
* or else we could leave the subcell tile plane in a weird
* state.
*/
SigDisableInterrupts();
dbInstanceUnplace(use);
if (UndoIsEnabled())
DBUndoCellUse(use, UNDO_CELL_DELETE);
use->cu_parent = (CellDef *) NULL;
SigEnableInterrupts();
}

View File

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

View File

@ -342,6 +342,214 @@ DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func)
DBTreeSrTiles(scx, &locMask, xMask, dbCopyAllPaint, (ClientData) &arg);
}
/* Client data structure used by DBCellGenerateSubstrate() */
struct dbCopySubData {
Plane *csd_plane;
TileType csd_subtype;
int csd_pNum;
bool csd_modified;
};
/*
*-----------------------------------------------------------------------------
*
* DBCellGenerateSubstrate --
*
* This function is used by the extraction code in ExtSubtree.c.
* Paint substrate into the target use. Similar to DBCellCopyAllPaint(),
* but it finds space tiles on the substrate plane and converts them to
* a substrate type in the target, clipped to the cell boundary. This
* allows the extraction to find and record all substrate regions, both
* common (global substrate) and local (isolated substrate), without
* requiring a physical substrate type to be drawn into all cells.
*
* Unlike normal paint copying, this can only be done by painting the
* substrate type over the entire cell area and then erasing all areas
* belonging to not-substrate types in the source.
*
* Returns:
* Nothing.
*
* Side Effects:
* Paints into the targetUse's CellDef. This only happens if two
* conditions are met:
* (1) The techfile has defined "substrate"
* (2) The techfile defines a type corresponding to the substrate
*
* ----------------------------------------------------------------------------
*/
Plane *
DBCellGenerateSubstrate(scx, subType, notSubMask, subShieldMask, targetDef)
SearchContext *scx;
TileType subType; /* Substrate paint type */
TileTypeBitMask *notSubMask; /* Mask of types that are not substrate */
TileTypeBitMask *subShieldMask; /* Mask of types that shield substrate */
CellDef *targetDef;
{
struct dbCopySubData csd;
Plane *tempPlane;
int plane;
Rect rect;
int dbPaintSubFunc();
int dbEraseNonSub();
int dbCopySubFunc();
GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &rect);
/* Clip to bounding box of the top level cell */
GEOCLIP(&rect, &scx->scx_use->cu_def->cd_bbox);
plane = DBPlane(subType);
tempPlane = DBNewPlane((ClientData) TT_SPACE);
DBClearPaintPlane(tempPlane);
csd.csd_subtype = subType;
csd.csd_plane = tempPlane;
csd.csd_pNum = plane;
csd.csd_modified = FALSE;
/* First paint the substrate type in the temporary plane over the */
/* area of all substrate shield types. */
/* Note: xMask is always zero, as this is only called from extract routines */
DBTreeSrTiles(scx, subShieldMask, 0, dbPaintSubFunc, (ClientData)&csd);
if (csd.csd_modified == FALSE) return NULL;
/* Now erase all areas that are non-substrate types in the source */
DBTreeSrTiles(scx, notSubMask, 0, dbEraseNonSub, (ClientData)&csd);
/* Finally, copy the destination plane contents onto tempPlane */
DBSrPaintArea((Tile *)NULL, targetDef->cd_planes[plane], &TiPlaneRect,
&DBAllButSpaceBits, dbCopySubFunc, (ClientData)&csd);
return tempPlane;
}
/*
* Callback function for DBCellGenerateSubstrate()
* Finds tiles in the source def that belong to the list of types that
* shield the substrate (e.g., deep nwell), and paint the substrate type
* into the target plane over the same area.
*/
int
dbPaintSubFunc(tile, cxp)
Tile *tile; /* Pointer to source tile with shield type */
TreeContext *cxp; /* Context from DBTreeSrTiles */
{
SearchContext *scx;
Rect sourceRect, targetRect;
int pNum;
TileType type, loctype, subType;
Plane *plane;
struct dbCopySubData *csd; /* Client data */
scx = cxp->tc_scx;
csd = (struct dbCopySubData *)cxp->tc_filter->tf_arg;
plane = csd->csd_plane;
pNum = csd->csd_pNum;
subType = csd->csd_subtype;
type = TiGetTypeExact(tile);
if (IsSplit(tile))
{
loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
if (loctype == TT_SPACE) return 0;
}
/* Construct the rect for the tile */
TITORECT(tile, &sourceRect);
/* Transform to target coordinates */
GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect);
csd->csd_modified = TRUE;
return DBNMPaintPlane(plane, type, &targetRect, DBStdPaintTbl(subType, pNum),
(PaintUndoInfo *)NULL);
}
/*
* Callback function for DBCellGenerateSubstrate()
* Finds tiles on the substrate plane in the source def that are not the
* substrate type, and erases those areas from the target. This reduces
* the geometry in the target plane to areas that form isolated substrate
* regions. Regions belonging to the common global substrate are ignored.
*/
int
dbEraseNonSub(tile, cxp)
Tile *tile; /* Pointer to tile to erase from target */
TreeContext *cxp; /* Context from DBTreeSrTiles */
{
SearchContext *scx;
Rect sourceRect, targetRect;
Plane *plane; /* Plane of target data */
TileType type, loctype, subType;
struct dbCopySubData *csd;
int pNum;
csd = (struct dbCopySubData *)cxp->tc_filter->tf_arg;
plane = csd->csd_plane;
subType = csd->csd_subtype;
pNum = csd->csd_pNum;
scx = cxp->tc_scx;
type = TiGetTypeExact(tile);
if (IsSplit(tile))
{
loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
if (loctype == TT_SPACE) return 0;
}
/* Construct the rect for the tile */
TITORECT(tile, &sourceRect);
/* Transform to target coordinates */
GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect);
/* Erase the substrate type from the area of this tile in the target plane. */
return DBNMPaintPlane(plane, type, &targetRect, DBStdEraseTbl(subType, pNum),
(PaintUndoInfo *)NULL);
}
/*
* Callback function for DBCellGenerateSubstrate()
* Simple paint function to copy all paint from the substrate plane of the
* source def into the target plane containing the isolated substrate
* regions.
*/
int
dbCopySubFunc(tile, csd)
Tile *tile; /* Pointer to tile to erase from target */
struct dbCopySubData *csd; /* Client data */
{
Rect rect;
int pNum;
TileType type, loctype;
Plane *plane;
plane = csd->csd_plane;
pNum = csd->csd_pNum;
type = TiGetTypeExact(tile);
if (IsSplit(tile))
{
loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
if (loctype == TT_SPACE) return 0;
}
else
loctype = type;
/* Construct the rect for the tile */
TITORECT(tile, &rect);
return DBNMPaintPlane(plane, type, &rect, DBStdPaintTbl(loctype, pNum),
(PaintUndoInfo *)NULL);
}
/*
*-----------------------------------------------------------------------------
*
@ -480,6 +688,7 @@ DBCellCopyPaint(scx, mask, xMask, targetUse)
arg.caa_mask = mask;
arg.caa_targetUse = targetUse;
arg.caa_func = NULL;
GeoTransRect(&scx->scx_trans, &scx->scx_area, &arg.caa_rect);
/* Build dummy TreeContext */

View File

@ -21,7 +21,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#endif /* not lint */
#include <stdio.h>
#include <stdlib.h> /* for qsort() */
#include <string.h>
#include <ctype.h>
#include "tcltk/tclmagic.h"
#include "utils/magic.h"
@ -271,6 +273,7 @@ DBCellDelete(cellname, force)
}
celldef->cd_parents = (CellUse *)NULL;
DBWResetBox(celldef);
result = DBCellDeleteDef(celldef);
if (result == FALSE)
@ -280,8 +283,6 @@ DBCellDelete(cellname, force)
return result;
}
/*
* ----------------------------------------------------------------------------
*
@ -598,6 +599,67 @@ DBTopPrint(mw, dolist)
}
}
/*
* ----------------------------------------------------------------------------
* Simple natural sort routine
* https://stackoverflow.com/questions/34518/natural-sorting-algorithm
* By Norman Ramsey, edited for style.
* ----------------------------------------------------------------------------
*/
int strcmpbynum(const char *s1, const char *s2)
{
/* Like strcmp() but compare sequences of digits numerically */
for (;;)
{
if (*s2 == '\0')
return *s1 != '\0';
else if (*s1 == '\0')
return 1;
else if (!(isdigit(*s1) && isdigit(*s2)))
{
if (*s1 != *s2)
return (int)*s1 - (int)*s2;
else
{
++s1;
++s2;
}
}
else
{
char *lim1, *lim2;
unsigned long n1 = strtoul(s1, &lim1, 10);
unsigned long n2 = strtoul(s2, &lim2, 10);
if (n1 > n2)
return 1;
else if (n1 < n2)
return -1;
s1 = lim1;
s2 = lim2;
}
}
}
/*
* ----------------------------------------------------------------------------
* Sort routine for qsort() to be used by DBCellPrint(). Sorts in alphabetical
* order using the natural sort routine above. List is reverse sorted since
* the code below prints from the end to the beginning of the list.
* ----------------------------------------------------------------------------
*/
int
qcompare(const void *one, const void *two)
{
int cval;
char *s1 = *((char **)one);
char *s2 = *((char **)two);
cval = strcmpbynum(s1, s2);
return -cval;
}
/*
* ----------------------------------------------------------------------------
*
@ -625,11 +687,12 @@ DBCellPrint(CellName, who, dolist)
int who;
bool dolist;
{
int found;
int found, numcells;
HashSearch hs;
HashEntry *entry;
CellDef *celldef;
CellUse *celluse;
char **celllist;
if (!dolist)
{
@ -657,6 +720,11 @@ DBCellPrint(CellName, who, dolist)
* CDMODIFIED flag set.
*/
numcells = dbCellDefTable.ht_nEntries;
if (numcells == 0) numcells = 1;
celllist = (char **)mallocMagic(numcells * sizeof(char *));
numcells = 0;
HashStartSearch(&hs);
while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
{
@ -666,28 +734,39 @@ DBCellPrint(CellName, who, dolist)
if (((celldef->cd_flags & CDINTERNAL) != CDINTERNAL) &&
((who != MODIFIED) ||
(celldef->cd_flags & CDMODIFIED)))
{
if (celldef->cd_name != NULL)
{
if (dolist)
#ifdef MAGIC_WRAPPER
Tcl_AppendElement(magicinterp, celldef->cd_name);
#else
TxPrintf("%s ", celldef->cd_name);
#endif
else
TxPrintf(" %s\n", celldef->cd_name);
}
}
celllist[numcells++] = celldef->cd_name;
}
}
qsort(celllist, numcells, sizeof(char *), qcompare);
while (--numcells >= 0)
{
if (dolist)
#ifdef MAGIC_WRAPPER
Tcl_AppendElement(magicinterp, celllist[numcells]);
#else
TxPrintf("%s ", celllist[numcells]);
#endif
else
TxPrintf(" %s\n", celllist[numcells]);
}
freeMagic(celllist);
break;
case TOPCELLS:
/*
* Print the name of all the 'top' cells.
* Print the name of all the 'top' cells. Sort alphabetically.
*/
numcells = dbCellDefTable.ht_nEntries;
if (numcells == 0) numcells = 1;
celllist = (char **)mallocMagic(numcells * sizeof(char *));
numcells = 0;
HashStartSearch(&hs);
while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
{
@ -712,19 +791,25 @@ DBCellPrint(CellName, who, dolist)
}
}
if ( (found == 0) && (celldef->cd_name != NULL) )
{
if (dolist)
#ifdef MAGIC_WRAPPER
Tcl_AppendElement(magicinterp, celldef->cd_name);
#else
TxPrintf("%s ", celldef->cd_name);
#endif
else
TxPrintf(" %s\n", celldef->cd_name);
}
celllist[numcells++] = celldef->cd_name;
}
}
}
qsort(celllist, numcells, sizeof(char *), qcompare);
while (--numcells >= 0)
{
if (dolist)
#ifdef MAGIC_WRAPPER
Tcl_AppendElement(magicinterp, celllist[numcells]);
#else
TxPrintf("%s ", celllist[numcells]);
#endif
else
TxPrintf(" %s\n", celllist[numcells]);
}
freeMagic(celllist);
break;
default:

View File

@ -29,8 +29,10 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "utils/stack.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "select/select.h"
#include "utils/signals.h"
#include "utils/malloc.h"
@ -43,55 +45,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
* is used to clear the markings again.
*/
/* The following structure is used to hold several pieces
* of information that must be passed through multiple
* levels of search function (used by dbSrConnectFunc).
*/
struct conSrArg
{
CellDef *csa_def; /* Definition being searched. */
int csa_plane; /* Index of current plane being searched. */
TileTypeBitMask *csa_connect; /* Table indicating what connects
* to what.
*/
int (*csa_clientFunc)(); /* Client function to call. */
ClientData csa_clientData; /* Argument for clientFunc. */
bool csa_clear; /* FALSE means pass 1, TRUE
* means pass 2.
*/
Rect csa_bounds; /* Area that limits search. */
};
/* The following structure is used to hold several pieces
* of information that must be passed through multiple
* levels of search function (used by dbcConnectFunc).
*/
typedef struct
{
Rect area; /* Area to process */
TileTypeBitMask *connectMask; /* Connection mask for search */
TileType dinfo; /* Info about triangular search areas */
} conSrArea;
struct conSrArg2
{
CellUse *csa2_use; /* Destination use */
TileTypeBitMask *csa2_connect; /* Table indicating what connects
* to what.
*/
SearchContext *csa2_topscx; /* Original top-level search context */
int csa2_xMask; /* Cell window mask for search */
Rect *csa2_bounds; /* Area that limits the search */
conSrArea *csa2_list; /* List of areas to process */
int csa2_top; /* Index of next area to process */
int csa2_size; /* Max. number bins in area list */
};
#define CSA2_LIST_START_SIZE 256
/*
*-----------------------------------------------------------------
* DBTransformDiagonal --
@ -255,6 +208,7 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
startTile = NULL;
for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
{
csa.csa_pNum = startPlane;
if (DBSrPaintArea((Tile *) NULL,
def->cd_planes[startPlane], startArea, mask,
dbSrConnectStartFunc, (ClientData) &startTile) != 0) break;
@ -270,7 +224,6 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
csa.csa_clientData = clientData;
csa.csa_clear = FALSE;
csa.csa_connect = connect;
csa.csa_plane = startPlane;
if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
/* Pass 2. Don't call any client function, just clear the marks.
@ -280,7 +233,6 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
SigDisableInterrupts();
csa.csa_clientFunc = NULL;
csa.csa_clear = TRUE;
csa.csa_plane = startPlane;
(void) dbSrConnectFunc(startTile, &csa);
SigEnableInterrupts();
@ -346,6 +298,7 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
startTile = NULL;
for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
{
csa.csa_pNum = startPlane;
if (DBSrPaintArea((Tile *) NULL,
def->cd_planes[startPlane], startArea, mask,
dbSrConnectStartFunc, (ClientData) &startTile) != 0) break;
@ -361,7 +314,6 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
csa.csa_clientData = clientData;
csa.csa_clear = FALSE;
csa.csa_connect = connect;
csa.csa_plane = startPlane;
if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
return result;
@ -434,7 +386,7 @@ dbSrConnectFunc(tile, csa)
if (csa->csa_clientFunc != NULL)
{
if ((*csa->csa_clientFunc)(tile, csa->csa_plane, csa->csa_clientData) != 0)
if ((*csa->csa_clientFunc)(tile, csa->csa_pNum, csa->csa_clientData) != 0)
return 1;
}
@ -577,7 +529,7 @@ donesides:
*/
planes = DBConnPlanes[loctype];
planes &= ~(PlaneNumToMaskBit(csa->csa_plane));
planes &= ~(PlaneNumToMaskBit(csa->csa_pNum));
if (planes != 0)
{
struct conSrArg newcsa;
@ -589,7 +541,7 @@ donesides:
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
{
if (!PlaneMaskHasPlane(planes, i)) continue;
newcsa.csa_plane = i;
newcsa.csa_pNum = i;
if (IsSplit(tile))
{
if (DBSrPaintNMArea((Tile *) NULL, csa->csa_def->cd_planes[i],
@ -653,7 +605,7 @@ dbcUnconnectFunc(tile, clientData)
* connectivity between them.
*
* Results:
* Always 0.
* Return 0 normally, 1 if list size exceeds integer bounds.
*
* Side effects:
* Adds a label to the destination definition "def".
@ -691,10 +643,15 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
{
int newllen = tpath->tp_next - tpath->tp_first;
newlabtext[0] = '\0';
if (newllen > 0)
strncpy(newlabtext, tpath->tp_first, newllen);
sprintf(newlabtext + newllen, "%s", lab->lab_text);
newlabptr = newlabtext;
if (tpath->tp_first == NULL)
newlabptr = lab->lab_text;
else
{
if (newllen > 0)
strncpy(newlabtext, tpath->tp_first, newllen);
sprintf(newlabtext + newllen, "%s", lab->lab_text);
newlabptr = newlabtext;
}
}
else return 0;
}
@ -734,7 +691,7 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
if ((slab->lab_flags & PORT_NUM_MASK) == lidx)
{
Rect newarea;
int pNum;
int i, pNum;
// Do NOT go searching on labels connected to space!
if (slab->lab_type == TT_SPACE) continue;
@ -757,24 +714,29 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
newarea.r_ybot--;
newarea.r_ytop++;
/* Check if any of the last 5 entries has the same type and */
/* area. If so, don't duplicate the existing entry. */
for (i = csa2->csa2_lasttop; (i >= 0) &&
(i > csa2->csa2_lasttop - 5); i--)
if (connectMask == csa2->csa2_list[i].connectMask)
if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea))
return 0;
/* Register the area and connection mask as needing to be processed */
if (++csa2->csa2_top == csa2->csa2_size)
if (++csa2->csa2_top == CSA2_LIST_SIZE)
{
/* Reached list size limit---need to enlarge the list */
/* Double the size of the list every time we hit the limit */
/* Reached list size limit---need to push the list and */
/* start a new one. */
conSrArea *newlist;
int i, lastsize = csa2->csa2_size;
csa2->csa2_size *= 2;
newlist = (conSrArea *)mallocMagic(csa2->csa2_size
* sizeof(conSrArea));
memcpy((void *)newlist, (void *)csa2->csa2_list,
(size_t)lastsize * sizeof(conSrArea));
freeMagic((char *)csa2->csa2_list);
newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE *
sizeof(conSrArea));
StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
csa2->csa2_list = newlist;
csa2->csa2_top = 0;
}
csa2->csa2_list[csa2->csa2_top].area = newarea;
@ -805,7 +767,8 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
* catecorner tiles from being considered as connected.
*
* Results:
* Always returns 0 to keep the search from aborting.
* Returns 0 normally to keep the search from aborting; returns 1
* if allocation of list failed due to exceeding integer bounds.
*
* Side effects:
* Adds paint to the destination definition.
@ -829,7 +792,7 @@ dbcConnectFunc(tile, cx)
SearchContext scx2;
TileType loctype = TiGetTypeExact(tile);
TileType dinfo = 0;
int pNum = cx->tc_plane;
int i, pNum = cx->tc_plane;
CellDef *def;
TiToRect(tile, &tileArea);
@ -942,23 +905,29 @@ dbcConnectFunc(tile, cx)
newarea.r_xtop += 1;
}
/* Check if any of the last 5 entries has the same type and */
/* area. If so, don't duplicate the existing entry. */
/* (NOTE: Connect masks are all from the same table, so */
/* they can be compared by address, no need for TTMaskEqual)*/
for (i = csa2->csa2_lasttop; (i >= 0) && (i > csa2->csa2_lasttop - 5); i--)
if (connectMask == csa2->csa2_list[i].connectMask)
if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea))
return 0;
/* Register the area and connection mask as needing to be processed */
if (++csa2->csa2_top == csa2->csa2_size)
if (++csa2->csa2_top == CSA2_LIST_SIZE)
{
/* Reached list size limit---need to enlarge the list */
/* Double the size of the list every time we hit the limit */
/* Reached list size limit---need to push the list and */
/* start a new one. */
conSrArea *newlist;
int i, lastsize = csa2->csa2_size;
csa2->csa2_size *= 2;
newlist = (conSrArea *)mallocMagic((size_t)(csa2->csa2_size) * sizeof(conSrArea));
memcpy((void *)newlist, (void *)csa2->csa2_list,
(size_t)lastsize * sizeof(conSrArea));
freeMagic((char *)csa2->csa2_list);
newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
csa2->csa2_list = newlist;
csa2->csa2_top = 0;
}
csa2->csa2_list[csa2->csa2_top].area = newarea;
@ -968,7 +937,6 @@ dbcConnectFunc(tile, cx)
return 0;
}
/*
* ----------------------------------------------------------------------------
*
@ -1019,9 +987,10 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse)
* clipped to this area. Pass
* TiPlaneRect to get everything.
*/
bool doLabels; /* If TRUE, copy connected labels
* and paint. If FALSE, copy only
* connected paint.
unsigned char doLabels; /* If SEL_DO_LABELS, copy connected labels
* and paint. If SEL_NO_LABELS, copy only
* connected paint. If SEL_SIMPLE_LABELS,
* copy only root of labels in subcircuits.
*/
CellUse *destUse; /* Result use in which to place
* anything connected to material of
@ -1034,7 +1003,6 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse)
unsigned char searchtype;
csa2.csa2_use = destUse;
csa2.csa2_xMask = xMask;
csa2.csa2_bounds = area;
csa2.csa2_connect = connect;
csa2.csa2_topscx = scx;
@ -1043,10 +1011,11 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse)
/* malloc calls by maintaining a small list and expanding it only */
/* when necessary. */
csa2.csa2_size = CSA2_LIST_START_SIZE;
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_START_SIZE
* sizeof(conSrArea));
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
csa2.csa2_top = -1;
csa2.csa2_lasttop = -1;
csa2.csa2_stack = StackNew(100);
DBTreeSrTiles(scx, mask, xMask, dbcConnectFunc, (ClientData) &csa2);
while (csa2.csa2_top >= 0)
@ -1061,13 +1030,28 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse)
newmask = csa2.csa2_list[csa2.csa2_top].connectMask;
scx->scx_area = csa2.csa2_list[csa2.csa2_top].area;
newtype = csa2.csa2_list[csa2.csa2_top].dinfo;
csa2.csa2_top--;
if (csa2.csa2_top == 0)
{
if (StackLook(csa2.csa2_stack) != (ClientData)NULL)
{
freeMagic(csa2.csa2_list);
csa2.csa2_list = (conSrArea *)StackPop(csa2.csa2_stack);
csa2.csa2_top = CSA2_LIST_SIZE - 1;
}
else
csa2.csa2_top--;
}
else
csa2.csa2_top--;
csa2.csa2_lasttop = csa2.csa2_top;
if (newtype & TT_DIAGONAL)
DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFunc,
(ClientData) &csa2);
else
DBTreeSrTiles(scx, newmask, xMask, dbcConnectFunc, (ClientData) &csa2);
DBTreeSrTiles(scx, newmask, xMask, dbcConnectFunc,
(ClientData) &csa2);
/* Check the source def for any labels belonging to this */
/* tile area and plane, and add them to the destination. */
@ -1098,11 +1082,17 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse)
searchtype |= TF_LABEL_ATTACH_NOT_SE;
}
}
if (doLabels)
DBTreeSrLabels(scx, newmask, xMask, &tpath, searchtype,
dbcConnectLabelFunc, (ClientData) &csa2);
if (doLabels == SEL_SIMPLE_LABELS) tpath.tp_first = NULL;
if (doLabels != SEL_NO_LABELS)
if (DBTreeSrLabels(scx, newmask, xMask, &tpath, searchtype,
dbcConnectLabelFunc, (ClientData) &csa2) != 0)
{
TxError("Connection search hit memory limit and stopped.\n");
break;
}
}
freeMagic((char *)csa2.csa2_list);
StackFree(csa2.csa2_stack);
/* Recompute the bounding box of the destination and record its area
* for redisplay.

View File

@ -135,6 +135,132 @@ file_is_not_writeable(name)
return(0);
}
/*
* ----------------------------------------------------------------------------
*
* DBSearchForTech --
*
* Helper function for automatically discovering a technology used in a
* .mag file when reading. This function will recursively search all
* directories rooted at "pathroot" looking for a file "techname" which
* must include the ".tech" extension. If found, the path name is returned.
*
* Results:
* Pointer to a string containing the path name. This is allocated so as
* not to be lost, and must be freed by the caller.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
char *
DBSearchForTech(techname, pathroot, level)
char *techname;
char *pathroot;
int level;
{
char *newpath, *found;
struct dirent *tdent;
DIR *tdir;
/* Avoid potential infinite looping. Any tech file should not be very */
/* far down the path. 10 levels is already excessive. */
if (level > 10) return NULL;
tdir = opendir(pathroot);
if (tdir) {
/* Read the directory contents of tdir */
while ((tdent = readdir(tdir)) != NULL)
{
if (tdent->d_type != DT_DIR)
{
if (!strcmp(tdent->d_name, techname))
return pathroot;
}
else if (strcmp(tdent->d_name, ".") && strcmp(tdent->d_name, ".."))
{
newpath = mallocMagic(strlen(pathroot) + strlen(tdent->d_name) + 3);
sprintf(newpath, "%s/%s", pathroot, tdent->d_name);
found = DBSearchForTech(techname, newpath, level + 1);
if (found != newpath) freeMagic(newpath);
if (found) return found;
}
}
closedir(tdir);
}
else
return NULL;
}
/*
* ----------------------------------------------------------------------------
*
* DBAddStandardCellPaths --
*
* Search for .mag files in any directory below "pathptr", for any
* directory found containing .mag files, add that path to the search
* path for cells.
*
* Results:
* Number of paths added to CellLibPath.
*
* Side effects:
* May add paths to the CellLibPath.
*
* ----------------------------------------------------------------------------
*/
int
DBAddStandardCellPaths(pathptr, level)
char *pathptr;
int level;
{
int paths = 0;
struct dirent *tdent;
char *newpath;
DIR *tdir;
bool magfound = FALSE;
/* Avoid potential infinite looping. Any tech file should not be very */
/* far down the path. 10 levels is already excessive. */
if (level > 10) return 0;
tdir = opendir(pathptr);
if (tdir) {
while ((tdent = readdir(tdir)) != NULL)
{
if ((tdent->d_type == DT_DIR) &&
(strcmp(tdent->d_name, ".") && strcmp(tdent->d_name, "..")))
{
/* Scan the directory contents of tdir for more subdirectories */
newpath = mallocMagic(strlen(pathptr) + strlen(tdent->d_name) + 3);
sprintf(newpath, "%s/%s", pathptr, tdent->d_name);
paths += DBAddStandardCellPaths(newpath, level + 1);
freeMagic(newpath);
}
else if (tdent->d_type != DT_DIR)
{
/* Scan the directory contents of tdir for .mag files */
if (!strcmp(tdent->d_name + strlen(tdent->d_name) - 4, ".mag"))
{
if (magfound == FALSE)
{
PaAppend(&CellLibPath, pathptr);
paths++;
magfound = TRUE;
}
}
}
}
closedir(tdir);
}
return paths;
}
/*
* ----------------------------------------------------------------------------
*
@ -285,7 +411,7 @@ dbCellReadDef(f, cellDef, name, ignoreTech, dereference)
int cellStamp = 0, rectCount = 0, rectReport = 10000;
char line[2048], tech[50], layername[50];
PaintResultType *ptable;
bool result = TRUE, scaleLimit = FALSE;
bool result = TRUE, scaleLimit = FALSE, has_mismatch;
Rect *rp;
int c;
TileType type, rtype, loctype;
@ -335,13 +461,122 @@ dbCellReadDef(f, cellDef, name, ignoreTech, dereference)
TxPrintf("Will attempt to read cell anyway.\n");
else
{
TxError("Use command \"tech load\" if you want to switch"
" technologies, or use\n");
TxError("\"cellname delete %s\" and \"load %s -force\" to"
" force the cell to load as technology %s\n",
cellDef->cd_name, cellDef->cd_name, DBTechName);
SigEnableInterrupts();
return (FALSE);
/* If no cells are currently in memory, then make an
* attempt to find the technology associated with the
* layout and load it.
*/
if (!CmdCheckForPaintFunc())
{
/* Places to check for a technology: In the PDK_ROOT
* (PDKROOT) directory, PDK_PATH (PDKPATH) from environment
* variables, and CAD_ROOT from Tcl variables; the open_pdks
* default install path /usr/share/pdk/, and magic's install
* path. For CAD_ROOT the variable is expected to point to
* a path containing the techfile. For PDK_PATH and PDK_ROOT,
* search the directory tree for any subdirectory called
* magic/ and look for a compatible techfile there.
*/
char *found = NULL;
char *string, *techfullname;
techfullname = mallocMagic(strlen(tech) + 6);
sprintf(techfullname, "%s.tech", tech);
string = getenv("PDK_PATH");
if (string)
found = DBSearchForTech(techfullname, string, 0);
if (!found)
{
string = getenv("PDKPATH");
if (string)
found = DBSearchForTech(techfullname, string, 0);
}
if (!found)
{
string = getenv("PDK_ROOT");
if (string)
found = DBSearchForTech(techfullname, string, 0);
}
if (!found)
{
string = getenv("PDKROOT");
if (string)
found = DBSearchForTech(techfullname, string, 0);
}
if (!found)
{
found = DBSearchForTech(techfullname, "/usr/share/pdk", 0);
}
#ifdef MAGIC_WRAPPER
/* Additional checks for PDK_PATH, etc., as Tcl variables. */
/* This is unlikely, as they would have to be set in a */
/* startup file, and a startup file is likely to just load */
/* the technology itself. */
if (!found)
{
string = (char *)Tcl_GetVar(magicinterp, "PDK_ROOT",
TCL_GLOBAL_ONLY);
if (string)
found = DBSearchForTech(techfullname, string, 0);
}
if (!found)
{
string = (char *)Tcl_GetVar(magicinterp, "PDKROOT",
TCL_GLOBAL_ONLY);
if (string)
found = DBSearchForTech(techfullname, string, 0);
}
if (!found)
{
string = (char *)Tcl_GetVar(magicinterp, "PDK_PATH",
TCL_GLOBAL_ONLY);
if (string)
found = DBSearchForTech(techfullname, string, 0);
}
if (!found)
{
string = (char *)Tcl_GetVar(magicinterp, "PDKPATH",
TCL_GLOBAL_ONLY);
if (string)
found = DBSearchForTech(techfullname, string, 0);
}
#endif
freeMagic(techfullname);
if (found)
{
char *sptr;
PaAppend(&SysLibPath, found);
TxError("Loading technology %s\n", tech);
if (!TechLoad(tech, 0))
TxError("Error in loading technology file\n");
else if ((sptr = strstr(found, "libs.tech")) != NULL)
{
int paths = 0;
/* Additional automatic handling of open_pdks- */
/* style PDKs. Append the libs.ref libraries */
/* to the cell search path. */
strcpy(sptr + 5, "ref");
paths = DBAddStandardCellPaths(found, 0);
if (paths > 0)
TxPrintf("Cell path is now \"%s\"\n", CellLibPath);
}
freeMagic(found);
}
}
if (strcmp(DBTechName, tech))
{
TxError("Use command \"tech load\" if you want to switch"
" technologies, or use\n");
TxError("\"cellname delete %s\" and \"load %s -force\" to"
" force the cell to load as technology %s\n",
cellDef->cd_name, cellDef->cd_name, DBTechName);
SigEnableInterrupts();
return (FALSE);
}
}
}
if (dbFgets(line, sizeof line, f) == NULL)
@ -609,6 +844,7 @@ done:
* timestamp, then force the cell to be written out with a
* correct timestamp.
*/
has_mismatch = FALSE;
if ((cellDef->cd_timestamp != cellStamp) || (cellStamp == 0))
{
CellUse *cu;
@ -617,12 +853,13 @@ done:
if (cu->cu_parent != NULL)
{
DBStampMismatch(cellDef, &cellDef->cd_bbox);
has_mismatch = TRUE;
break;
}
}
}
/* Update timestamp flags */
DBFlagMismatches(cellDef);
if (has_mismatch) DBFlagMismatches(cellDef);
cellDef->cd_timestamp = cellStamp;
if (cellStamp == 0)
@ -634,7 +871,8 @@ done:
}
UndoEnable();
DRCCheckThis(cellDef, TT_CHECKPAINT, (Rect *) NULL);
/* Disabled 3/16/2021. Let <<checkpaint>> in file force a DRC check */
/* DRCCheckThis(cellDef, TT_CHECKPAINT, (Rect *) NULL); */
SigEnableInterrupts();
return (result);
@ -3167,6 +3405,105 @@ dbClearCellFunc(cellUse, cdarg)
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* DBPathSubstitute --
*
* Replace the leading part of a file path string according to the following
* criteria:
*
* 1) If the filename starts with a string equal to the contents of
* Tcl variables PDK_PATH, PDKPATH, PDK_ROOT, or PDKROOT, then
* replace the string with the variable name. The "PATH" names are
* more specific than "ROOT" and so are checked first.
* 2) If the filename starts with a string equal to the contents of
* environment variable HOME, then replace the string with "~".
*
* Results:
* None.
*
* Side Effects:
* Writes into the string "cstring".
*
* ----------------------------------------------------------------------------
*/
void
DBPathSubstitute(pathstart, cstring, cellDef)
char *pathstart;
char *cstring;
CellDef *cellDef;
{
bool subbed = FALSE;
#ifdef MAGIC_WRAPPER
char *tvar;
/* Check for the leading component of the file path being equal to */
/* one of several common variable names for the PDK location, and */
/* if there is a match, then substitute the variable name for the */
/* matching leading path component. */
if (subbed == FALSE)
{
tvar = (char *)Tcl_GetVar(magicinterp, "PDK_PATH", TCL_GLOBAL_ONLY);
if (tvar)
if (!strncmp(pathstart, tvar, strlen(tvar)))
{
sprintf(cstring, "$PDK_PATH%s", pathstart + strlen(tvar));
subbed = TRUE;
}
}
if (subbed == FALSE)
{
tvar = (char *)Tcl_GetVar(magicinterp, "PDKPATH", TCL_GLOBAL_ONLY);
if (tvar)
if (!strncmp(pathstart, tvar, strlen(tvar)))
{
sprintf(cstring, "$PDKPATH%s", pathstart + strlen(tvar));
subbed = TRUE;
}
}
if (subbed == FALSE)
{
tvar = (char *)Tcl_GetVar(magicinterp, "PDK_ROOT", TCL_GLOBAL_ONLY);
if (tvar)
if (!strncmp(pathstart, tvar, strlen(tvar)))
{
sprintf(cstring, "$PDK_ROOT%s", pathstart + strlen(tvar));
subbed = TRUE;
}
}
if (subbed == FALSE)
{
tvar = (char *)Tcl_GetVar(magicinterp, "PDKROOT", TCL_GLOBAL_ONLY);
if (tvar)
if (!strncmp(pathstart, tvar, strlen(tvar)))
{
sprintf(cstring, "$PDKROOT%s", pathstart + strlen(tvar));
subbed = TRUE;
}
}
#endif
if (subbed == FALSE)
{
/* If path starts with home path, then replace with "~" */
/* to make IP semi-portable between home directories */
/* with the same file structure. */
char *homedir = getenv("HOME");
if (cellDef->cd_file == NULL)
sprintf(cstring, "%s", pathstart);
else if (!strncmp(cellDef->cd_file, homedir, strlen(homedir))
&& (*(cellDef->cd_file + strlen(homedir)) == '/'))
sprintf(cstring, "~%s", cellDef->cd_file + strlen(homedir));
else
sprintf(cstring, "%s", pathstart);
}
}
/*
* ----------------------------------------------------------------------------
*
@ -3192,8 +3529,7 @@ dbWriteCellFunc(cellUse, cdarg)
struct writeArg *arg = (struct writeArg *) cdarg;
Transform *t;
Rect *b;
bool subbed = FALSE;
char cstring[256], *pathend, *pathstart, *parent;
char cstring[1024], *pathend, *pathstart, *parent;
t = &(cellUse->cu_transform);
b = &(cellUse->cu_def->cd_bbox);
@ -3244,92 +3580,13 @@ dbWriteCellFunc(cellUse, cdarg)
}
else
{
#ifdef MAGIC_WRAPPER
char *tvar;
/* Check for the leading component of the file path being equal to */
/* one of several common variable names for the PDK location, and */
/* if there is a match, then substitute the variable name for the */
/* matching leading path component. */
if (subbed == FALSE)
{
tvar = (char *)Tcl_GetVar(magicinterp, "PDK_PATH", TCL_GLOBAL_ONLY);
if (tvar)
if (!strncmp(pathstart, tvar, strlen(tvar)))
{
sprintf(cstring, "use %s %c%s $PDK_PATH%s\n",
cellUse->cu_def->cd_name,
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
cellUse->cu_id, pathstart + strlen(tvar));
subbed = TRUE;
}
}
if (subbed == FALSE)
{
tvar = (char *)Tcl_GetVar(magicinterp, "PDKPATH", TCL_GLOBAL_ONLY);
if (tvar)
if (!strncmp(pathstart, tvar, strlen(tvar)))
{
sprintf(cstring, "use %s %c%s $PDKPATH%s\n",
cellUse->cu_def->cd_name,
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
cellUse->cu_id, pathstart + strlen(tvar));
subbed = TRUE;
}
}
if (subbed == FALSE)
{
tvar = (char *)Tcl_GetVar(magicinterp, "PDK_ROOT", TCL_GLOBAL_ONLY);
if (tvar)
if (!strncmp(pathstart, tvar, strlen(tvar)))
{
sprintf(cstring, "use %s %c%s $PDK_ROOT%s\n",
cellUse->cu_def->cd_name,
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
cellUse->cu_id, pathstart + strlen(tvar));
subbed = TRUE;
}
}
if (subbed == FALSE)
{
tvar = (char *)Tcl_GetVar(magicinterp, "PDKROOT", TCL_GLOBAL_ONLY);
if (tvar)
if (!strncmp(pathstart, tvar, strlen(tvar)))
{
sprintf(cstring, "use %s %c%s $PDKROOT%s\n",
cellUse->cu_def->cd_name,
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
cellUse->cu_id, pathstart + strlen(tvar));
subbed = TRUE;
}
}
#endif
if (subbed == FALSE)
{
/* If path starts with home path, then replace with "~" */
/* to make IP semi-portable between home directories */
/* with the same file structure. */
char *homedir = getenv("HOME");
if (!strncmp(cellUse->cu_def->cd_file, homedir, strlen(homedir))
&& (*(cellUse->cu_def->cd_file + strlen(homedir)) == '/'))
{
sprintf(cstring, "use %s %c%s ~%s\n", cellUse->cu_def->cd_name,
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
cellUse->cu_id, cellUse->cu_def->cd_file +
strlen(homedir));
}
else
{
sprintf(cstring, "use %s %c%s %s\n", cellUse->cu_def->cd_name,
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
cellUse->cu_id, pathstart);
}
}
sprintf(cstring, "use %s %c%s ", cellUse->cu_def->cd_name,
(cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ',
cellUse->cu_id);
DBPathSubstitute(pathstart, cstring + strlen(cstring), cellUse->cu_def);
strcat(cstring, "\n");
}
FPRINTR(arg->wa_file, cstring);
cellUse->cu_def->cd_flags |= CDVISITED;

View File

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

View File

@ -83,6 +83,15 @@ DBPropPut(cellDef, name, value)
cellDef->cd_flags |= CDFIXEDBBOX;
}
/* Special handling of GDS_FILE, which uses CDVENDORGDS as a quick lookup */
if (!strcmp(name, "GDS_FILE"))
{
if (value == (ClientData)NULL)
cellDef->cd_flags &= ~CDVENDORGDS;
else
cellDef->cd_flags |= CDVENDORGDS;
}
entry = HashFind(htab, name);
oldvalue = (char *)HashGetValue(entry);
if (oldvalue != NULL) freeMagic(oldvalue);

View File

@ -425,7 +425,8 @@ DBTechFinalConnect()
for (n = 0; n < dbNumContacts; n++)
{
lp = dbContactInfo[n];
TTMaskSetOnlyType(&DBNotConnectTbl[lp->l_type], lp->l_type);
TTMaskZero(&DBNotConnectTbl[lp->l_type]);
TTMaskSetMask(&DBNotConnectTbl[lp->l_type], &DBConnectTbl[lp->l_type]);
rMask = DBResidueMask(lp->l_type);
/* Different contact types may share residues. */

View File

@ -33,6 +33,10 @@
#include "utils/hash.h"
#endif /* _HASH_H */
#ifndef _STACK_H
#include "utils/stack.h"
#endif /* _STACK_H */
#ifndef _BPLANE_H
#include "bplane/bplane.h"
#endif /* _BPLANE_H */
@ -658,6 +662,54 @@ typedef struct treeFilter
/* To do: Make the tpath entries dynamically allocated */
#define FLATTERMSIZE 4096 /* Used for generating flattened labels */
/* ------------ Information used in connectivity searches --------------*/
/* The following structure is used to hold several pieces of information
* that must be passed through multiple levels of search function. This
* structure is used by DBSrConnect, DBTreeCopyConnect, SimTreeCopyConnect,
* and DBTreeCopyConnectDCS.
*/
struct conSrArg
{
CellDef *csa_def; /* Definition being searched. */
int csa_pNum; /* Index of plane being searched */
TileTypeBitMask *csa_connect; /* Table indicating what connects
* to what.
*/
int (*csa_clientFunc)(); /* Client function to call. */
ClientData csa_clientData; /* Argument for clientFunc. */
bool csa_clear; /* FALSE means pass 1, TRUE
* means pass 2.
*/
Rect csa_bounds; /* Area that limits search. */
};
typedef struct
{
Rect area; /* Area to process */
TileTypeBitMask *connectMask; /* Connection mask for search */
TileType dinfo; /* Info about triangular search areas */
} conSrArea;
struct conSrArg2
{
CellUse *csa2_use; /* Destination use */
TileTypeBitMask *csa2_connect; /* Table indicating what connects
* to what.
*/
SearchContext *csa2_topscx; /* Original top-level search context */
int csa2_xMask; /* Cell window mask for search */
Rect *csa2_bounds; /* Area that limits the search */
Stack *csa2_stack; /* Stack of full csa2_list entries */
conSrArea *csa2_list; /* List of areas to process */
int csa2_top; /* Index of next area to process */
int csa2_lasttop; /* Previous top index */
};
#define CSA2_LIST_SIZE 65536 /* Number of entries per list */
/* -------------- Undo information passed to DBPaintPlane ------------- */
typedef struct
@ -725,6 +777,7 @@ extern void DBFileRecovery();
extern bool DBWriteBackup();
extern bool DBReadBackup();
extern void DBRemoveBackup();
extern void DBPathSubstitute();
/* Labels */
extern Label *DBPutLabel();
@ -790,7 +843,9 @@ extern CellUse *DBFindUse();
/* Insertion/deletion of cell uses into the cell tile plane of a parent */
extern void DBPlaceCell();
extern void DBPlaceCellNoModify();
extern void DBDeleteCell();
extern void DBDeleteCellNoModify();
extern void DBClearCellPlane();
/* Insertion/deletion of cell uses into the name space of a parent */
@ -821,6 +876,7 @@ extern void DBCellCopyLabels();
extern void DBCellCopyAllLabels();
extern void DBCellCopyCells();
extern void DBCellCopyAllCells();
extern Plane *DBCellGenerateSubstrate();
/* Contact image handling */
extern TileType DBPlaneToResidue();

View File

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

View File

@ -790,6 +790,31 @@ DBWSetBox(rootDef, rect)
dbwRecordBoxArea(FALSE);
}
/*
* ----------------------------------------------------------------------------
* DBWResetBox() ---
*
* Make sure that boxRootDef is set to NULL if it is equal to the
* specified CellDef. This is used by the cell delete function to
* make sure that if an edit cell is deleted, the boxRootDef is not
* pointing to an invalid area of memory.
*
* Results:
* None.
*
* Side effects:
* Global variable boxRootDef may be set to NULL.
*
* ----------------------------------------------------------------------------
*/
void
DBWResetBox(CellDef *def)
{
if (def == boxRootDef)
boxRootDef = NULL;
}
/*
* ----------------------------------------------------------------------------
* ToolMoveBox --

View File

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

View File

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

View File

@ -26,6 +26,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <sys/types.h>
#include <stdio.h>
#include <string.h> // for memcpy()
#include <math.h> // for sqrt() for diagonal check
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
@ -268,6 +269,47 @@ areaCheck(tile, arg)
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* areaNMCheck ---
*
* Check for errors in triangular area of a tile
*
* ----------------------------------------------------------------------------
*/
int
areaNMCheck(tile, arg)
Tile *tile;
struct drcClientData *arg;
{
Rect rect; /* Area where error is to be recorded. */
/* Ignore the tile that initiates the check, because the error area */
/* of a non-Manhattan check may fall inside of it. */
if (tile == arg->dCD_initial) return 0;
TiToRect(tile, &rect);
/* Only consider the portion of the suspicious tile that overlaps
* the clip area for errors, unless this is a trigger rule.
*/
if (!(arg->dCD_cptr->drcc_flags & DRC_TRIGGER))
GeoClip(&rect, arg->dCD_clip);
GeoClip(&rect, arg->dCD_constraint);
if ((rect.r_xbot >= rect.r_xtop) || (rect.r_ybot >= rect.r_ytop))
return 0;
(*(arg->dCD_function))(arg->dCD_celldef, &rect, arg->dCD_cptr,
arg->dCD_clientData);
(*(arg->dCD_errors))++;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
@ -412,8 +454,11 @@ drcTile (tile, arg)
if (IsSplit(tile))
{
int deltax, deltay;
TileType tt, to;
/* Check rules for DRC_ANGLES rule and process */
TileType tt = TiGetLeftType(tile);
tt = TiGetLeftType(tile);
if (tt != TT_SPACE)
{
for (cptr = DRCCurStyle->DRCRulesTbl[TT_SPACE][tt];
@ -436,8 +481,98 @@ drcTile (tile, arg)
}
}
/* This drc is only for the left edge of the tile */
if (SplitSide(tile)) goto checkbottom;
/* Full check of edge rules along the diagonal. */
if (SplitSide(tile))
{
tt = TiGetRightType(tile); /* inside type */
to = TiGetLeftType(tile); /* outside type */
}
else
{
tt = TiGetLeftType(tile); /* inside type */
to = TiGetRightType(tile); /* outside type */
}
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
cptr = cptr->drcc_next)
{
int deltax, deltay, w, h;
double r;
TileType dinfo, dsplit;
/* Work to be done: Handle triggering rules for non-Manhattan */
/* edges; especially important for the wide-spacing rule. */
if (cptr->drcc_flags & DRC_TRIGGER)
{
cptr = cptr->drcc_next; // Skip both triggering and triggered rules
continue;
}
/* Note: Triggered wide-spacing rule will require handling */
/* the DRC_MAXWIDTH rule on non-Manhattan edges. */
if (cptr->drcc_flags & (DRC_ANGLES | DRC_AREA | DRC_MAXWIDTH
| DRC_RECTSIZE | DRC_OFFGRID))
continue;
TiToRect(tile, &errRect);
/* Find the rule distances according to the scale factor */
dist = cptr->drcc_dist;
/* drcc_edgeplane is used to avoid checks on edges */
/* in more than one plane */
if (arg->dCD_plane != cptr->drcc_edgeplane) continue;
DRCstatRules++;
DRCstatSlow++;
arg->dCD_cptr = cptr;
arg->dCD_entries = 0;
TTMaskCom2(&tmpMask, &cptr->drcc_mask);
TTMaskClearType(&tmpMask, TT_ERROR_S);
arg->dCD_initial = tile;
/* Compute position that is the rule distance away from */
/* the tile's diagonal edge, by Euclidean measure */
/* (rounded down if fractional). Use the forward */
/* position, and negate if reversed. */
w = RIGHT(tile) - LEFT(tile);
h = TOP(tile) - BOTTOM(tile);
r = 1.0 / (1.0 + ((double)(w * w) / (double)(h * h)));
deltax = (int)((double)cptr->drcc_dist * sqrt(r));
deltay = (deltax * w) / h;
if (SplitSide(tile) == 1) deltax = -deltax;
if (SplitDirection(tile) == SplitSide(tile)) deltay = -deltay;
dinfo = TiGetTypeExact(tile) & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE);
if (!(cptr->drcc_flags & DRC_REVERSE))
{
/* Forward case is behind the triangle */
deltax = -deltax;
deltay = -deltay;
/* Split side changes in the reverse case */
if (SplitSide(tile))
dinfo &= (~TT_SIDE);
else
dinfo |= TT_SIDE;
}
/* errRect is the tile area offset by (deltax, deltay) */
errRect.r_xbot += deltax;
errRect.r_ybot += deltay;
errRect.r_xtop += deltax;
errRect.r_ytop += deltay;
DBSrPaintNMArea((Tile *) NULL,
arg->dCD_celldef->cd_planes[cptr->drcc_plane], dinfo,
&errRect, &tmpMask, areaNMCheck, (ClientData) arg);
}
DRCstatEdges++;
}
/*
@ -604,9 +739,17 @@ drcTile (tile, arg)
}
else if (cptr->drcc_flags & DRC_MAXWIDTH)
{
/* bends_illegal option only */
if (firsttile)
drcCheckMaxwidth(tile, arg, cptr);
if (cptr->drcc_flags & DRC_MAXWIDTH_BOTH)
{
if (firsttile)
drcCheckMaxwidth(tile, arg, cptr, TRUE);
}
else
{
/* bends_illegal option only */
if (firsttile)
drcCheckMaxwidth(tile, arg, cptr, FALSE);
}
continue;
}
@ -671,8 +814,8 @@ drcTile (tile, arg)
else tpl = tpleft;
/* Make sure the edge stops at edgeBot */
if ((TiGetTopType(tpl) != TiGetBottomType(tpleft)) ||
(TiGetTopType(tpr) != TiGetBottomType(tile)))
if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
(TiGetLeftType(tpr) != TiGetLeftType(tile)))
{
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpr)))
{
@ -698,8 +841,8 @@ drcTile (tile, arg)
else tpl = tpleft;
/* Make sure the edge stops at edgeTop */
if ((TiGetBottomType(tpl) != TiGetTopType(tpleft)) ||
(TiGetBottomType(tpr) != TiGetTopType(tile)))
if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
(TiGetLeftType(tpr) != TiGetLeftType(tile)))
{
if (TTMaskHasType(&cptr->drcc_corner,
TiGetBottomType(tpr)))
@ -745,8 +888,8 @@ drcTile (tile, arg)
else tpr = tile;
/* Make sure the edge stops at edgeTop */
if ((TiGetBottomType(tpl) != TiGetTopType(tpleft)) ||
(TiGetBottomType(tpr) != TiGetTopType(tile)))
if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
(TiGetLeftType(tpr) != TiGetLeftType(tile)))
{
if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpl)))
{
@ -772,8 +915,8 @@ drcTile (tile, arg)
else tpr = tile;
/* Make sure the edge stops at edgeBot */
if ((TiGetTopType(tpl) != TiGetBottomType(tpleft)) ||
(TiGetTopType(tpr) != TiGetBottomType(tile)))
if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
(TiGetLeftType(tpr) != TiGetLeftType(tile)))
{
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpl)))
{
@ -834,12 +977,6 @@ drcTile (tile, arg)
}
}
/* This drc is only for the bottom edge of the tile */
checkbottom:
if (IsSplit(tile))
if (SplitSide(tile) == SplitDirection(tile)) return 0;
/*
* Check design rules along a horizontal boundary between two tiles.
*
@ -1044,7 +1181,7 @@ checkbottom:
for (tpx = TR(tile); BOTTOM(tpx) > edgeY; tpx = LB(tpx));
else tpx = tile;
if (TTMaskHasType(&cptr->drcc_corner, TiGetLeftType(tpx)))
if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpx)))
{
errRect.r_xtop += cdist;
if (DRCEuclidean)
@ -1061,7 +1198,7 @@ checkbottom:
if (LEFT(tile) >= errRect.r_xbot) tpx = BL(tile);
else tpx = tile;
if (TTMaskHasType(&cptr->drcc_corner, TiGetRightType(tpx)))
if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpx)))
{
errRect.r_xbot -= cdist;
if (DRCEuclidean)
@ -1098,7 +1235,7 @@ checkbottom:
for (tpx = BL(tpbot); TOP(tpx) < edgeY; tpx = RT(tpx));
else tpx = tpbot;
if (TTMaskHasType(&cptr->drcc_corner, TiGetRightType(tpx)))
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpx)))
{
errRect.r_xbot -= cdist;
if (DRCEuclidean)
@ -1114,7 +1251,7 @@ checkbottom:
if (RIGHT(tpbot) <= errRect.r_xtop) tpx = TR(tpbot);
else tpx = tpbot;
if (TTMaskHasType(&cptr->drcc_corner, TiGetLeftType(tpx)))
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpx)))
{
errRect.r_xtop += cdist;
if (DRCEuclidean)

View File

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

View File

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

View File

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

View File

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

View File

@ -999,11 +999,12 @@ simdevVisit(dev, hc, scale, trans)
float scale; /* Scale transform for output */
Transform *trans; /* Coordinate transform */
{
DevTerm *gate, *source, *drain;
DevTerm *gate, *source, *drain, *term;
EFNode *subnode, *snode, *dnode;
int l, w;
Rect r;
char name[12];
bool is_subckt = FALSE;
HierName *hierName = hc->hc_hierName;
sprintf(name, "output");
@ -1057,7 +1058,6 @@ simdevVisit(dev, hc, scale, trans)
case DEV_FET:
case DEV_MOSFET:
case DEV_ASYMMETRIC:
case DEV_MSUBCKT:
/* The sim file format only understands "n" and "p" for FETs. */
/* The extraction method says nothing about which is which. */
/* The EFDevTypes[] should ideally start with "n" or "p". If */
@ -1089,6 +1089,19 @@ simdevVisit(dev, hc, scale, trans)
}
}
break;
case DEV_MSUBCKT:
case DEV_CSUBCKT:
case DEV_RSUBCKT:
case DEV_SUBCKT:
/* Use the 'x' type in .sim format. This is implemented in the */
/* IRSIM "user subcircuit" package, so it has a valid syntax. */
/* It is used by the extresist code in magic as a way to work */
/* around the lack of substrate and lack of device names in the */
/* .sim format. */
is_subckt = TRUE;
fprintf(esSimF, "x");
break;
default:
fprintf(esSimF, "%c", EFDevTypes[dev->dev_type][0]);
break;
@ -1121,8 +1134,31 @@ simdevVisit(dev, hc, scale, trans)
else if (dev->dev_nterm > 2)
simdevOutNode(hierName, drain->dterm_node->efnode_name->efnn_hier, name, esSimF);
if (dev->dev_nterm > 3) /* For subcircuit support ('x' device) */
{
int i;
sprintf(name, "subckt");
for (i = 3; i < dev->dev_nterm; i++)
{
term = &dev->dev_terms[i];
simdevOutNode(hierName, term->dterm_node->efnode_name->efnn_hier,
name, esSimF);
}
}
if (is_subckt && subnode)
{
/* As a general policy on subcircuits supporting extresist, */
/* output the subcircuit node as the last port of the */
/* subcircuit definition. */
putc(' ', esSimF);
simdevSubstrate(hierName, subnode->efnode_name->efnn_hier,
dev->dev_type, 0.0, FALSE, esSimF);
}
/* Support gemini's substrate comparison */
if (esFormat == LBL && subnode)
else if (esFormat == LBL && subnode)
{
putc(' ', esSimF);
simdevSubstrate(hierName, subnode->efnode_name->efnn_hier,
@ -1165,6 +1201,15 @@ simdevVisit(dev, hc, scale, trans)
else if (dev->dev_class == DEV_CAPREV) { /* generate a capacitor */
fprintf(esSimF, " %f", (double)(dev->dev_cap));
}
else if (is_subckt)
{
/* Output length, width, and position as attributes */
fprintf(esSimF, " l=%g w=%g x=%g y=%g",
l * scale, w * scale, r.r_xbot * scale, r.r_ybot * scale);
/* Output tile type as an attribute for quick lookup by ResReadSim */
fprintf(esSimF, " t=%d", fetInfo[dev->dev_type].devType);
}
else if ((dev->dev_class != DEV_DIODE) && (dev->dev_class != DEV_PDIODE)
&& (dev->dev_class != DEV_NDIODE)) {
@ -1235,6 +1280,13 @@ simdevVisit(dev, hc, scale, trans)
}
}
}
if (is_subckt)
{
/* Last token on a subcircuit 'x' line is the subcircuit name */
fprintf(esSimF, " %s", EFDevTypes[dev->dev_type]);
}
fprintf(esSimF, "\n");
return 0;
@ -1572,9 +1624,8 @@ int simnodeVisit(node, res, cap)
if (esLabF)
{
fprintf(esLabF, "94 ");
EFHNOut(hierName, esLabF);
fprintf(esLabF, " %d %d %s;\n",
fprintf(esLabF, " %d %d %s\n",
node->efnode_loc.r_xbot, node->efnode_loc.r_ybot,
EFLayerNames[node->efnode_type]);
}

View File

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

View File

@ -1553,10 +1553,15 @@ subcktVisit(use, hierName, is_top)
}
}
/* SPICE subcircuit names must begin with A-Z. This will also be */
/* enforced when writing X subcircuit calls. */
/* SPICE subcircuit names must begin with A-Z. */
subcktname = def->def_name;
while (!isalpha(*subcktname)) subcktname++;
if (!isalpha(*subcktname))
{
subcktname = mallocMagic(2 + strlen(def->def_name));
sprintf(subcktname, "x%s", def->def_name);
freeMagic(def->def_name);
def->def_name = subcktname;
}
if (tchars > 80) fprintf(esSpiceF, "\n+");
fprintf(esSpiceF, " %s", subcktname); /* subcircuit model name */
@ -1664,7 +1669,13 @@ topVisit(def, doStub)
/* SPICE subcircuit names must begin with A-Z. This will also be */
/* enforced when writing X subcircuit calls. */
subcktname = def->def_name;
while (!isalpha(*subcktname)) subcktname++;
if (!isalpha(*subcktname))
{
subcktname = mallocMagic(2 + strlen(def->def_name));
sprintf(subcktname, "x%s", def->def_name);
freeMagic(def->def_name);
def->def_name = subcktname;
}
fprintf(esSpiceF, ".subckt %s", subcktname);
tchars = 8 + strlen(subcktname);
@ -1924,7 +1935,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
hierD = extHierSDAttr(&dev->dev_terms[pn]);
resclass == (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain :
resclass = (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain :
esFetInfo[dev->dev_type].resClassSource;
// For parameter a<n> followed by parameter p<n>,
@ -1987,7 +1998,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM)
pn = plist->parm_type[1] - '0';
if (pn >= dev->dev_nterm) pn = dev->dev_nterm - 1;
resclass == (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain :
resclass = (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain :
esFetInfo[dev->dev_type].resClassSource;
hierD = extHierSDAttr(&dev->dev_terms[pn]);
@ -2219,47 +2230,39 @@ getCurDevMult()
/*
*-----------------------------------------------------------------------------
* swapDrainSource
*
* Swap drain and source ordering and the related stuff
* including the drain/source area parameters
*
* This is typycally called if any terminal is marked with attribute "D" or "S"
* This is typically called if any terminal is marked with attribute "D" or "S"
* (label "D$" or "S$" at poly-diffusion interface),
* then swap order of source and drain compared to the default ordering.
*
* Note:
* Before calling this function, ensure that dev->dev_nterm >= 3
*
* Results:
* None
*
* Side effects:
* Soure (dev->dev_terms[1]) and drain (dev->dev_terms[2]) terminals
* are swapped.
*
*-----------------------------------------------------------------------------
*/
void
swapDrainSource(dev, source, drain)
swapDrainSource(dev)
Dev *dev;
DevTerm **source, **drain;
{
DevParam *plist;
/* swap drain/source ordering */
if (drain) *drain = &dev->dev_terms[1];
if (source) *source = &dev->dev_terms[2];
/* Swap drain/source-related parameters. Note that the parameter */
/* *definitions* are swapped, so if this is done, it must be */
/* reverted before the next device is processed. */
DevTerm tmpTerm;
plist = efGetDeviceParams(EFDevTypes[dev->dev_type]);
while (plist != NULL)
{
// Diagnostic
// TxPrintf(" * param: %s; type: %c%c\n", plist->parm_name, plist->parm_type[0], plist->parm_type[1]);
/* Swap drain/source parameters only */
if (!(strcmp(plist->parm_type, "a1")) || !(strcmp(plist->parm_type, "p1")))
plist->parm_type[1] = '0' + 2;
else if (!(strcmp(plist->parm_type, "a2")) || !(strcmp(plist->parm_type, "p2")))
plist->parm_type[1] = '0' + 1;
/* move pointer */
plist = plist->parm_next;
}
/* swap original terminals */
memcpy(&tmpTerm, &(dev->dev_terms[1]), sizeof(DevTerm));
memcpy(&(dev->dev_terms[1]), &(dev->dev_terms[2]), sizeof(DevTerm));
memcpy(&(dev->dev_terms[2]), &tmpTerm, sizeof(DevTerm));
}
@ -2309,7 +2312,7 @@ spcdevVisit(dev, hc, scale, trans)
DevTerm *gate, *source, *drain;
EFNode *subnode, *snode, *dnode, *subnodeFlat = NULL;
int l, w, i, parmval;
bool subAP= FALSE, hierS, hierD, extHierSDAttr(), swapped = FALSE ;
bool subAP= FALSE, hierS, hierD, extHierSDAttr();
float sdM;
char name[12], devchar;
bool has_model = TRUE;
@ -2331,8 +2334,11 @@ spcdevVisit(dev, hc, scale, trans)
gate = &dev->dev_terms[0];
if (dev->dev_nterm >= 2)
source = drain = &dev->dev_terms[1];
if (dev->dev_nterm >= 3)
{
drain = &dev->dev_terms[2];
/* If any terminal is marked with attribute "D" or "S" */
/* (label "D$" or "S$" at poly-diffusion interface), */
/* then force order of source and drain accordingly. */
@ -2342,11 +2348,8 @@ spcdevVisit(dev, hc, scale, trans)
(dev->dev_terms[2].dterm_attrs &&
!strcmp(dev->dev_terms[2].dterm_attrs, "S")))
{
swapDrainSource(dev, &source, &drain);
swapped = True;
swapDrainSource(dev);
}
else
drain = &dev->dev_terms[2];
}
subnode = dev->dev_subsnode;
@ -2852,9 +2855,6 @@ spcdevVisit(dev, hc, scale, trans)
}
fprintf(esSpiceF, "\n");
/* If S/D parameters on a subcircuit were swapped, put them back */
if (swapped) swapDrainSource(dev, NULL, NULL);
return 0;
}
@ -4083,7 +4083,7 @@ update_w(resClass, w, n)
{
(nc->m_w.widths) = (float *)mallocMagic((unsigned)sizeof(float)
* efNumResistClasses);
for (i = 0; i < EFDevNumTypes; i++)
for (i = 0; i < efNumResistClasses; i++)
nc->m_w.widths[i] = 0.0;
}
nc->m_w.widths[resClass] += (float)w;

View File

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

View File

@ -32,6 +32,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header$";
#include "utils/malloc.h"
#include "extflat/extflat.h"
#include "extflat/EFint.h"
#include "tiles/tile.h"
#include "extract/extract.h" /* for device class list */
/*
@ -183,6 +184,7 @@ efBuildNode(def, isSubsnode, nodeName, nodeCap, x, y, layerName, av, ac)
newname = (EFNodeName *) mallocMagic((unsigned)(sizeof (EFNodeName)));
newname->efnn_hier = EFStrToHN((HierName *) NULL, nodeName);
newname->efnn_port = -1; /* No port assignment */
newname->efnn_refc = 0; /* Only reference is self */
newname->efnn_next = NULL;
HashSetValue(he, (char *) newname);
}
@ -453,6 +455,8 @@ efBuildEquiv(def, nodeName1, nodeName2)
nn1 = (EFNodeName *) HashGetValue(he1);
nn2 = (EFNodeName *) HashGetValue(he2);
if (nn1 == nn2) return; /* These nodes already merged */
if (nn2 == (EFNodeName *) NULL)
{
/* Create nodeName1 if it doesn't exist */
@ -481,11 +485,35 @@ efBuildEquiv(def, nodeName1, nodeName2)
return; /* Repeated "equiv" statement */
if (nn1->efnn_node != nn2->efnn_node)
{
struct efnode *node1 = nn1->efnn_node;
struct efnode *node2 = nn2->efnn_node;
HashSearch hs;
if (efWarn)
efReadError("Merged nodes %s and %s\n", nodeName1, nodeName2);
efNodeMerge(&nn1->efnn_node, &nn2->efnn_node);
if (nn1->efnn_port > 0) nn2->efnn_port = nn1->efnn_port;
else if (nn2->efnn_port > 0) nn1->efnn_port = nn2->efnn_port;
/* If a node has been merged away, make sure that its name */
/* and all aliases point to the merged name's hash. */
if (nn1->efnn_node == NULL)
{
nn2->efnn_refc += nn1->efnn_refc + 1;
HashStartSearch(&hs);
while (he1 = HashNext(&def->def_nodes, &hs))
if ((EFNodeName *)HashGetValue(he1) == nn1)
HashSetValue(he1, (char *)nn2);
}
else if (nn2->efnn_node == NULL)
{
nn1->efnn_refc += nn2->efnn_refc + 1;
HashStartSearch(&hs);
while (he2 = HashNext(&def->def_nodes, &hs))
if ((EFNodeName *)HashGetValue(he2) == nn2)
HashSetValue(he2, (char *)nn1);
}
}
return;
}
@ -1553,6 +1581,7 @@ efNodeAddName(node, he, hn)
newnn->efnn_node = node;
newnn->efnn_hier = hn;
newnn->efnn_port = -1;
newnn->efnn_refc = 0;
HashSetValue(he, (char *) newnn);
/* If the node is a port of the top level cell, denoted by flag */
@ -1861,7 +1890,15 @@ efFreeNodeTable(table)
{
for (hn = nn->efnn_hier; hn; hn = hn->hn_parent)
(void) HashFind(&efFreeHashTable, (char *) hn);
freeMagic((char *) nn);
/* Node equivalences made by "equiv" statements are handled */
/* by reference count. Don't free the node structure until */
/* all references have been seen. */
if (nn->efnn_refc > 0)
nn->efnn_refc--;
else
freeMagic((char *) nn);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -58,7 +58,7 @@ ClientData extUnInit = (ClientData) CLIENTDEFAULT;
int extOutputUsesFunc();
FILE *extFileOpen();
void extCellFile();
Plane* extCellFile();
void extHeader();
@ -83,7 +83,7 @@ void extHeader();
* ----------------------------------------------------------------------------
*/
void
Plane *
ExtCell(def, outName, doLength)
CellDef *def; /* Cell being extracted */
char *outName; /* Name of output file; if NULL, derive from def name */
@ -95,6 +95,7 @@ ExtCell(def, outName, doLength)
{
char *filename;
FILE *f;
Plane *savePlane;
bool doLocal;
doLocal = (ExtOptions & EXT_DOLOCAL) ? TRUE : FALSE;
@ -115,7 +116,7 @@ ExtCell(def, outName, doLength)
}
extNumFatal = extNumWarnings = 0;
extCellFile(def, f, doLength);
savePlane = extCellFile(def, f, doLength);
(void) fclose(f);
if (extNumFatal > 0 || extNumWarnings > 0)
@ -129,6 +130,7 @@ ExtCell(def, outName, doLength)
extNumWarnings, extNumWarnings != 1 ? "s" : "");
TxPrintf("\n");
}
return savePlane;
}
/*
@ -219,6 +221,137 @@ extFileOpen(def, file, mode, doLocal, prealfile)
return (PaOpen(name, mode, ".ext", ".", ".", prealfile));
}
/*
* ----------------------------------------------------------------------------
*
* extPrepSubstrate ---
*
* Prepare a replacement plane for the plane representing the substrate, as
* defined in ExtCurStyle->exts_globSubstratePlane. The target CellDef is
* searched for types that shield (i.e., isolate) a section of the layout
* from the global substrate. The tile type that represents the substrate
* is painted into the isolated regions.
*
* The purpose of this method is to deal with the common methodology in
* which the substrate is not represented by any tile type, because no mask
* is defined for the substrate. Typically, an entire cell such as a digital
* standard cell may be placed on the default substrate or in a deep nwell
* region. It is therefore necessary to be able to detect what is underneath
* a cell on the plane representing the substrate to determine if the area is
* the default substrate or an isolated region. If an isolated region, it
* must be painted with a tile type so that the extraction code can tag the
* tiles with a Region and assign it a node. This code creates the substrate
* paint in the isolated regions for the duration of the extration, then
* reverts back to the original plane afterward.
*
* Results:
* Returns a Plane structure that is the original substrate plane from
* CellDef "def", with isolated substrate regions filled with the
* substrate tile type. If there are no isolated substrate regions,
* or if a substrate plane or substrate type is not defined by the
* technology, then the routine returns NULL.
*
* Side effects:
* All modifications are limited to the returned plane structure.
*
* ----------------------------------------------------------------------------
*/
Plane *
extPrepSubstrate(def)
CellDef *def;
{
SearchContext scx;
CellUse dummy;
TileType subType;
TileTypeBitMask subMask, notSubMask;
Plane *subPlane, *savePlane;
int pNum;
/* Determine if substrate copying is required. */
if (ExtCurStyle->exts_globSubstratePlane == -1) return NULL;
/* Find a type to use for the substrate, and the mask of all types */
/* in the same plane as the substrate that are not connected to the */
/* substrate. If there is not a simple type representing the substrate */
/* then do not attempt to resolve substrate regions. */
TTMaskZero(&subMask);
TTMaskSetMask(&subMask, &ExtCurStyle->exts_globSubstrateTypes);
for (subType = TT_TECHDEPBASE; subType < DBNumUserLayers; subType++)
if (TTMaskHasType(&subMask, subType))
if (DBPlane(subType) == ExtCurStyle->exts_globSubstratePlane)
break;
TTMaskCom2(&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)
CellDef *def; /* Def to be extracted */
FILE *f; /* Output to this file */
@ -250,9 +383,13 @@ extCellFile(def, f, doLength)
*/
{
NodeRegion *reg;
Plane *saveSub;
UndoDisable();
/* Prep any isolated substrate areas */
saveSub = extPrepSubstrate(def);
/* Output the header: timestamp, technology, calls on cell uses */
if (!SigInterruptPending) extHeader(def, f);
@ -274,6 +411,7 @@ extCellFile(def, f, doLength)
extLength(extParentUse, f);
UndoEnable();
return saveSub;
}
/*

View File

@ -897,6 +897,9 @@ extSideOverlap(tp, esws)
subcap = (ExtCurStyle->exts_perimCap[ta][outtype] *
MIN(areaAccountedFor, length));
rbp->nreg_cap -= subcap;
/* Ignore residual error at ~zero zeptoFarads. Probably */
/* there should be better handling of round-off here. */
if ((rbp->nreg_cap > -0.001) && (rbp->nreg_cap < 0.001)) rbp->nreg_cap = 0;
if (CAP_DEBUG)
extNregAdjustCap(rbp, -subcap, "obsolete_perimcap");
} else if (CAP_DEBUG)

View File

@ -484,7 +484,10 @@ extHardFreeAll(def, tReg)
/* Free all LabelLists and then the region */
for (ll = reg->treg_labels; ll; ll = ll->ll_next)
{
if (ll->ll_label->lab_flags & LABEL_GENERATE) freeMagic(ll->ll_label);
freeMagic((char *) ll);
}
freeMagic((char *) reg);
}
}

View File

@ -60,16 +60,34 @@ int extHierConnectFunc2();
int extHierConnectFunc3();
Node *extHierNewNode();
/*----------------------------------------------------------------------*/
/* extHierSubShieldFunc -- */
/* */
/* Simple callback function for extHierSubstrate() that halts the */
/* search if any substrate shield type is found in the search area */
/* */
/*----------------------------------------------------------------------*/
/*----------------------------------------------*/
/* extHierSubstrate */
/* */
/* Find the substrate node of a child cell and */
/* make a connection between parent and child */
/* substrates. If either of the substrate */
/* nodes is already in the hash table, then the */
/* table will be updated as necessary. */
/*----------------------------------------------*/
int
extHierSubShieldFunc(tile)
Tile *tile;
{
return 1;
}
/*----------------------------------------------------------------------*/
/* extHierSubstrate -- */
/* */
/* Find the substrate node of a child cell and make a connection */
/* between parent and child substrates. If either of the */
/* substrate nodes is already in the hash table, then the table */
/* will be updated as necessary. */
/* */
/* This function also determines if a child cell's substrate is */
/* isolated by a substrate shield type, in which case no merge is */
/* done. */
/* */
/*----------------------------------------------------------------------*/
void
extHierSubstrate(ha, use, x, y)
@ -84,6 +102,8 @@ extHierSubstrate(ha, use, x, y)
Node *node1, *node2;
char *name1, *name2, *childname;
CellDef *def;
Rect subArea;
int pNum;
NodeRegion *extFindNodes();
@ -107,6 +127,49 @@ extHierSubstrate(ha, use, x, y)
/* Find the child's substrate node */
nodeList = extFindNodes(use->cu_def, (Rect *) NULL, TRUE);
if (nodeList == NULL)
{
ExtResetTiles(use->cu_def, extUnInit);
return;
}
/* Check if the child's substrate node is covered by any substrate */
/* shield type (e.g., deep nwell). This is a stupid-simple check */
/* on the node's lower left point. This will fail if (1) only */
/* space exists on the substrate plane in the child cell, or (2) if */
/* some but not all devices in the child are covered by a shield */
/* type. Item (1) is handled by checking if the region point is */
/* outside the cell bound and using the cell bound as the search */
/* area if so. However, it really should look for a device in the */
/* subcell that connects to the substrate. Item (2) is up to the */
/* designer to avoid (but should be flagged as an extraction */
/* error). */
if (GEO_ENCLOSE(&nodeList->nreg_ll, &use->cu_def->cd_bbox))
{
GeoTransPoint(&use->cu_transform, &nodeList->nreg_ll, &subArea.r_ll);
subArea.r_ur.p_x = subArea.r_ll.p_x + 1;
subArea.r_ur.p_y = subArea.r_ll.p_y + 1;
}
else
subArea = ha->ha_subArea;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
if (TTMaskIntersect(&DBPlaneTypes[pNum],
&ExtCurStyle->exts_globSubstrateShieldTypes))
{
if (DBSrPaintArea((Tile *) NULL,
def->cd_planes[pNum], &subArea,
&ExtCurStyle->exts_globSubstrateShieldTypes,
extHierSubShieldFunc, (ClientData)NULL) != 0)
{
freeMagic(nodeList);
ExtResetTiles(use->cu_def, extUnInit);
return;
}
}
}
/* Make sure substrate labels are represented */
ExtLabelRegions(use->cu_def, ExtCurStyle->exts_nodeConn, &nodeList,
@ -196,6 +259,8 @@ extHierConnections(ha, cumFlat, oneFlat)
/* Look for sticky labels in the child cell that are not */
/* connected to any geometry. */
if (!(ExtOptions & EXT_DOLABELCHECK)) return;
for (lab = sourceDef->cd_labels; lab; lab = lab->lab_next)
{
CellDef *cumDef = cumFlat->et_use->cu_def;
@ -283,6 +348,8 @@ extHierConnectFunc1(oneTile, ha)
/* This allows the extractor to catch "sticky" labels that are not */
/* attached to a physical layer in the parent cell. */
if (!(ExtOptions & EXT_DOLABELCHECK)) return 0;
// NOTE by Tim, 9/10/2014: This generates phantom nodes when the
// labels are created by the "hard" node search; I think this code
// should be restricted to sticky labels only. But not certain.
@ -330,31 +397,7 @@ extHierConnectFunc1(oneTile, ha)
node1->node_names = node2->node_names;
freeMagic((char *) node2);
}
#if 0
/* Copy this label to the parent def with a */
/* special flag, so we can output it as a node */
/* and then delete it. Don't duplicate labels */
/* that are already in the parent. */
for (newlab = ha->ha_parentUse->cu_def->cd_labels;
newlab; newlab = newlab->lab_next)
if (!strcmp(newlab->lab_text, lab->lab_text))
break;
if (newlab == NULL)
{
n = sizeof(Label) + strlen(lab->lab_text)
- sizeof lab->lab_text + 1;
newlab = (Label *)mallocMagic((unsigned)n);
bcopy((char *)lab, (char *)newlab, (int)n);
newlab->lab_next = ha->ha_parentUse->cu_def->cd_labels;
ha->ha_parentUse->cu_def->cd_labels = newlab;
}
#endif
}
}
return (0);
}

View File

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

View File

@ -616,6 +616,16 @@ closeit:
return (ret);
}
/* Linked list structure to use to store the substrate plane from each */
/* extracted CellDef so that they can be returned to the original after */
/* extraction. */
struct saveList {
Plane *sl_plane;
CellDef *sl_def;
struct saveList *sl_next;
};
/*
* ----------------------------------------------------------------------------
*
@ -645,7 +655,9 @@ extExtractStack(stack, doExtract, rootDef)
{
int fatal = 0, warnings = 0;
bool first = TRUE;
Plane *savePlane;
CellDef *def;
struct saveList *newsl, *sl = (struct saveList *)NULL;
while (def = (CellDef *) StackPop(stack))
{
@ -654,7 +666,16 @@ extExtractStack(stack, doExtract, rootDef)
{
if (doExtract)
{
ExtCell(def, (char *) NULL, (def == rootDef));
savePlane = ExtCell(def, (char *) NULL, (def == rootDef));
if (savePlane != NULL)
{
newsl = (struct saveList *)mallocMagic(sizeof(struct saveList));
newsl->sl_plane = savePlane;
newsl->sl_def = def;
newsl->sl_next = sl;
sl = newsl;
}
fatal += extNumFatal;
warnings += extNumWarnings;
}
@ -668,6 +689,16 @@ extExtractStack(stack, doExtract, rootDef)
}
}
/* Replace any modified substrate planes */
for (; sl; sl = sl->sl_next)
{
ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
// DBFreePaintPlane(sl->sl_plane);
// TiFreePlane(sl->sl_plane);
freeMagic(sl);
}
if (!doExtract)
{
TxPrintf("\n");

View File

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

View File

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

View File

@ -148,6 +148,8 @@ ExtractTest(w, cmd)
if (cmd->tx_argc == 1)
{
Plane *savePlane;
selectedCell = CmdGetSelectedCell((Transform *) NULL);
if (selectedCell == NULL)
{
@ -156,7 +158,8 @@ ExtractTest(w, cmd)
}
extDispInit(selectedCell->cu_def, w);
ExtCell(selectedCell->cu_def, selectedCell->cu_def->cd_name, FALSE);
savePlane = ExtCell(selectedCell->cu_def, selectedCell->cu_def->cd_name, FALSE);
ExtRevertSubstrate(selectedCell->cu_def, savePlane);
return;
}

View File

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

View File

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

View File

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

View File

@ -92,6 +92,11 @@ CmdLef(w, cmd)
* other than pin area surrounding labels,
* with the indicated setback distance.
*/
int lefPinOnly = -1; /* If >= 0, make pins only where labels
* are defined, not the whole net. Values
* > 0 limit how far pins can extend into
* the interior of the cell.
*/
bool lefTopLayer = FALSE; /* If TRUE, only output the topmost
* layer used by a pin, and make
* all layers below it obstructions.
@ -234,6 +239,17 @@ CmdLef(w, cmd)
i++;
}
}
else if (!strncmp(cmd->tx_argv[i], "-pinonly", 8))
{
lefPinOnly = 0;
if ((i < (cmd->tx_argc - 1)) &&
StrIsNumeric(cmd->tx_argv[i + 1]))
{
lefPinOnly = cmdParseCoord(w, cmd->tx_argv[i + 1],
FALSE, TRUE);
i++;
}
}
else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9))
lefTopLayer = TRUE;
else if (!strncmp(cmd->tx_argv[i], "-nomaster", 9))
@ -244,8 +260,8 @@ CmdLef(w, cmd)
}
else goto wrongNumArgs;
}
LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, lefTopLayer,
lefDoMaster, recurse);
LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, lefPinOnly,
lefTopLayer, lefDoMaster, recurse);
}
break;
case LEF_WRITE:
@ -286,6 +302,23 @@ CmdLef(w, cmd)
else
TxPrintf("The \"-hide\" option is only for lef write\n");
}
else if (!strncmp(cmd->tx_argv[i], "-pinonly", 8))
{
if (is_lef)
{
lefPinOnly = 0;
if ((i < (cmd->tx_argc - 1)) &&
StrIsNumeric(cmd->tx_argv[i + 1]))
{
lefPinOnly = cmdParseCoord(w, cmd->tx_argv[i + 1],
FALSE, TRUE);
cargs--;
i++;
}
}
else
TxPrintf("The \"-pinonly\" option is only for lef write\n");
}
else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9))
{
if (is_lef)
@ -339,7 +372,8 @@ CmdLef(w, cmd)
DefWriteCell(selectedUse->cu_def, namep, allSpecial, units);
else
LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def
== EditRootDef, lefTech, lefHide, lefTopLayer, lefDoMaster);
== EditRootDef, lefTech, lefHide, lefPinOnly,
lefTopLayer, lefDoMaster);
break;
case LEF_HELP:
wrongNumArgs:

View File

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

View File

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

View File

@ -538,7 +538,8 @@ PlotSetParam(name, value)
{
int j;
TxError("%s is not a supported plot type. Plot types are:\n");
TxError("%s is not a supported plot type. Plot types are:\n",
value);
for (j = 0 ; plotTypeNames[j] != NULL; j++)
{
TxError("\t%s\n", plotTypeNames[j]);

View File

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

View File

@ -17,6 +17,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/geofast.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "utils/stack.h"
#include "database/database.h"
#include "utils/malloc.h"
#include "textio/textio.h"
@ -29,30 +30,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "textio/txcommands.h"
#include "resis/resis.h"
typedef struct
{
Rect area; /* Area to process */
TileTypeBitMask *connectMask; /* Connection mask for search */
TileType dinfo; /* Info about triangular search areas */
} conSrArea;
struct conSrArg2
{
CellUse *csa2_use; /* Destination use */
TileTypeBitMask *csa2_connect; /* Table indicating what connects
* to what.
*/
SearchContext *csa2_topscx; /* Original top-level search context */
int csa2_xMask; /* Cell window mask for search */
Rect *csa2_bounds; /* Area that limits the search */
conSrArea *csa2_list; /* List of areas to process */
int csa2_top; /* Index of next area to process */
int csa2_size; /* Max. number bins in area list */
};
#define CSA2_LIST_START_SIZE 256
extern int dbcUnconnectFunc();
extern int dbcConnectLabelFunc();
extern int dbcConnectFuncDCS();
@ -67,7 +44,6 @@ TileTypeBitMask ResSubsTypeBitMask;
/* Forward declarations */
extern void ResCalcPerimOverlap();
/*
* ----------------------------------------------------------------------------
*
@ -100,7 +76,7 @@ dbcConnectFuncDCS(tile, cx)
TileType dinfo = 0;
SearchContext *scx = cx->tc_scx;
SearchContext scx2;
int pNum;
int i, pNum;
CellDef *def;
ExtDevice *devptr;
TerminalPath tpath;
@ -296,29 +272,29 @@ dbcConnectFuncDCS(tile, cx)
newarea.r_ytop += 1;
}
/* Check if any of the last 5 entries has the same type and */
/* area. If so, don't duplicate the existing entry. */
/* (NOTE: Connect masks are all from the same table, so */
/* they can be compared by address, no need for TTMaskEqual)*/
for (i = csa2->csa2_lasttop; (i >= 0) && (i > csa2->csa2_lasttop - 5); i--)
if (connectMask == csa2->csa2_list[i].connectMask)
if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea))
return 0;
/* Register the area and connection mask as needing to be processed */
if (++csa2->csa2_top == csa2->csa2_size)
if (++csa2->csa2_top == CSA2_LIST_SIZE)
{
/* Reached list size limit---need to enlarge the list */
/* Double the size of the list every time we hit the limit */
conSrArea *newlist;
int i, lastsize = csa2->csa2_size;
csa2->csa2_size *= 2;
newlist = (conSrArea *)mallocMagic(csa2->csa2_size * sizeof(conSrArea));
memcpy((void *)newlist, (void *)csa2->csa2_list,
(size_t)lastsize * sizeof(conSrArea));
// for (i = 0; i < lastsize; i++)
// {
// newlist[i].area = csa2->csa2_list[i].area;
// newlist[i].connectMask = csa2->csa2_list[i].connectMask;
// newlist[i].dinfo = csa2->csa2_list[i].dinfo;
// }
freeMagic((char *)csa2->csa2_list);
newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
csa2->csa2_list = newlist;
csa2->csa2_top = 0;
}
csa2->csa2_list[csa2->csa2_top].area = newarea;
@ -443,10 +419,11 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse)
csa2.csa2_connect = connect;
csa2.csa2_topscx = scx;
csa2.csa2_size = CSA2_LIST_START_SIZE;
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_START_SIZE
* sizeof(conSrArea));
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
csa2.csa2_top = -1;
csa2.csa2_lasttop = -1;
csa2.csa2_stack = StackNew(100);
if (first)
{
@ -474,7 +451,22 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse)
newmask = csa2.csa2_list[csa2.csa2_top].connectMask;
scx->scx_area = csa2.csa2_list[csa2.csa2_top].area;
newtype = csa2.csa2_list[csa2.csa2_top].dinfo;
csa2.csa2_top--;
if (csa2.csa2_top == 0)
{
if (StackLook(csa2.csa2_stack) != (ClientData)NULL)
{
freeMagic(csa2.csa2_list);
csa2.csa2_list = (conSrArea *)StackPop(csa2.csa2_stack);
csa2.csa2_top = CSA2_LIST_SIZE - 1;
}
else
csa2.csa2_top--;
}
else
csa2.csa2_top--;
csa2.csa2_lasttop = csa2.csa2_top;
if (newtype & TT_DIAGONAL)
DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFuncDCS,
(ClientData) &csa2);
@ -482,6 +474,7 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse)
DBTreeSrTiles(scx, newmask, xMask, dbcConnectFuncDCS, (ClientData) &csa2);
}
freeMagic((char *)csa2.csa2_list);
StackFree(csa2.csa2_stack);
for (CurrentT = DevList; CurrentT != NULL; CurrentT=CurrentT->nextDev)
{

View File

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

View File

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

View File

@ -27,12 +27,13 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "textio/textio.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
#include "extflat/extflat.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/utils.h"
#include "utils/tech.h"
#include "textio/txcommands.h"
#include "resis/resis.h"
#include "resis/resis.h"
/* constants defining where various fields can be found in .sim files. */
@ -49,11 +50,10 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#define COUPLEVALUE 3
#define REALNAME 1
#define ALIASNAME 2
#define NODECIFCOMMAND 0
#define NODENODENAME 1
#define NODENODEX 2
#define NODENODEY 3
#define NODETYPE 4
#define NODES_NODENAME 0
#define NODES_NODEX 1
#define NODES_NODEY 2
#define NODES_NODETYPE 3
#define NODE_BBOX_LL_X 5
#define NODE_BBOX_LL_Y 6
#define NODE_BBOX_UR_X 7
@ -119,10 +119,10 @@ extern void ResSimProcessDrivePoints();
*/
int
ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc)
ResReadSim(simfile, fetproc, capproc, resproc, attrproc, mergeproc, subproc)
char *simfile;
int (*fetproc)(),(*capproc)(),(*resproc)();
int (*attrproc)(),(*mergeproc)();
int (*fetproc)(), (*capproc)(), (*resproc)();
int (*attrproc)(), (*mergeproc)(), (*subproc)();
{
char line[MAXLINE][MAXTOKEN];
@ -172,6 +172,8 @@ ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc)
line[ATTRIBUTEVALUE],
simfile, &extfile);
break;
case 'x': fettype = DBNumTypes;
break;
case 'D':
case 'c':
case 'r': break;
@ -184,6 +186,10 @@ ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc)
TxError("Error in Reading device line of sim file.\n");
result = 1;
}
else if (fettype == DBNumTypes)
{
result = (*subproc)(line);
}
else if (fettype != MINFINITY)
{
float sheetr;
@ -229,13 +235,6 @@ ResReadNode(nodefile)
char *cp;
float lambda;
/* NOTE: Units from the .nodes file are in centimicrons.
* Divide by the extract scale (exts_unitsPerLambda) to get back
* to database units. This assumes that exts_unitsPerLambda doesn't
* change between output and readback.
*/
lambda = (float)ExtCurStyle->exts_unitsPerLambda;
fp = PaOpen(nodefile,"r",".nodes",".", (char *) NULL, (char **) NULL);
if (fp == NULL)
{
@ -244,19 +243,19 @@ ResReadNode(nodefile)
}
while (gettokens(line,fp) != 0)
{
entry = HashFind(&ResNodeTable,line[NODENODENAME]);
entry = HashFind(&ResNodeTable,line[NODES_NODENAME]);
node = ResInitializeNode(entry);
node->location.p_x = (int)((float)atof(line[NODENODEX]) / lambda);
node->location.p_y = (int)((float)atof(line[NODENODEY]) / lambda);
node->location.p_x = atoi(line[NODES_NODEX]);
node->location.p_y = atoi(line[NODES_NODEY]);
#ifdef ARIEL
node->rs_bbox.r_xbot = (int)((float)atof(line[NODE_BBOX_LL_X]) / lambda);
node->rs_bbox.r_ybot = (int)((float)atof(line[NODE_BBOX_LL_Y]) / lambda);
node->rs_bbox.r_xtop = (int)((float)atof(line[NODE_BBOX_UR_X]) / lambda);
node->rs_bbox.r_ytop = (int)((float)atof(line[NODE_BBOX_UR_Y]) / lambda);
node->rs_bbox.r_xbot = atoi(line[NODE_BBOX_LL_X]);
node->rs_bbox.r_ybot = atoi(line[NODE_BBOX_LL_Y]);
node->rs_bbox.r_xtop = atoi(line[NODE_BBOX_UR_X]);
node->rs_bbox.r_ytop = atoi(line[NODE_BBOX_UR_Y]);
#endif
if (cp = strchr(line[NODETYPE], ';')) *cp = '\0';
node->type = DBTechNameType(line[NODETYPE]);
if (cp = strchr(line[NODES_NODETYPE], ';')) *cp = '\0';
node->type = DBTechNameType(line[NODES_NODETYPE]);
if (node->type == -1)
{
@ -317,6 +316,130 @@ gettokens(line,fp)
}
/*
*-------------------------------------------------------------------------
*
* ResSimSubckt-- Processes a subcircuit line from a sim file.
* This uses the "user subcircuit" extension defined in
* IRSIM, although it is mostly intended as a way to work
* around the device type limitations of the .sim format
* when using extresist.
*
* Results: returns 0 if line was added correctly.
*
* Side Effects: Allocates devices and adds nodes to the node hash table.
*
*-------------------------------------------------------------------------
*/
int
ResSimSubckt(line)
char line[][MAXTOKEN];
{
RDev *device;
int rvalue, i, j, k;
static int nowarning = TRUE;
float lambda;
TileType ttype = TT_SPACE;
char *lptr = NULL, *wptr = NULL;
device = (RDev *) mallocMagic((unsigned) (sizeof(RDev)));
device->status = FALSE;
device->nextDev = ResRDevList;
lambda = (float)ExtCurStyle->exts_unitsPerLambda / resscale;
device->location.p_x = 0;
device->location.p_y = 0;
device->rs_gattr=RDEV_NOATTR;
device->rs_sattr=RDEV_NOATTR;
device->rs_dattr=RDEV_NOATTR;
ResRDevList = device;
device->layout = NULL;
/* The last argument is the name of the device */
for (i = 1; line[i][0] != '\0'; i++);
i--;
for (j = 0; j < EFDevNumTypes; j++)
if (!strcmp(EFDevTypes[j], line[i]))
break;
/* Read attributes, especially to pick up values for L, W, X, and Y,
* that are critical for use by extresist.
*/
for (k = 1; line[k][0] != '\0'; k++)
{
char *eqptr;
eqptr = strchr(line[k], '=');
if (eqptr != NULL)
{
if (k < i) i = k;
eqptr++;
switch (line[k][0]) {
case 'l':
lptr = eqptr;
break;
case 'w':
wptr = eqptr;
break;
case 'x':
device->location.p_x = (int)((float)atof(eqptr) / lambda);
break;
case 'y':
device->location.p_y = (int)((float)atof(eqptr) / lambda);
break;
case 't':
ttype = (int)(atoi(eqptr));
break;
}
}
}
/* This should not be needed, as ext2sim should encode device type */
/* in the attributes list. */
if (ttype == TT_SPACE)
{
if (j == EFDevNumTypes)
{
TxError("Failure to find device type %s\n", line[i]);
return 1;
}
ttype = extGetDevType(EFDevTypes[j]);
}
device->rs_ttype = ttype;
if (lptr != NULL && wptr != NULL)
{
float rpersquare;
ExtDevice *devptr;
devptr = ExtCurStyle->exts_device[ttype];
rpersquare =(float)devptr->exts_linearResist;
device->resistance = MagAtof(lptr) * rpersquare/MagAtof(wptr);
}
else
device->resistance = 0;
rvalue = 0;
for (k = 1; k < i; k++)
{
if (k > SUBS)
{
TxError("Device %s has more than 4 ports (not handled).\n", line[i]);
break; /* No method to handle more ports than this */
}
rvalue += ResSimNewNode(line[k], k, device);
}
return rvalue;
}
/*
*-------------------------------------------------------------------------
*
@ -330,7 +453,7 @@ gettokens(line,fp)
*/
int
ResSimDevice(line,rpersquare,ttype)
ResSimDevice(line, rpersquare, ttype)
char line[][MAXTOKEN];
float rpersquare;
TileType ttype;
@ -428,7 +551,7 @@ ResSimDevice(line,rpersquare,ttype)
*/
int
ResSimNewNode(line,type,device)
ResSimNewNode(line, type, device)
char line[];
int type;
RDev *device;
@ -443,7 +566,7 @@ ResSimNewNode(line,type,device)
TxError("Missing device connection\n");
return(1);
}
entry = HashFind(&ResNodeTable,line);
entry = HashFind(&ResNodeTable, line);
node = ResInitializeNode(entry);
tptr = (devPtr *) mallocMagic((unsigned) (sizeof(devPtr)));
tptr->thisDev = device;
@ -458,6 +581,8 @@ ResSimNewNode(line,type,device)
break;
case DRAIN: device->drain = node;
break;
case SUBS: device->subs = node;
break;
default: TxError("Bad Terminal Specifier\n");
break;
}

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

View File

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

View File

@ -52,26 +52,6 @@ int rtrDelta; /* Change in layer width */
* is used to clear the markings again.
*/
/* The following structure is used to hold several pieces
* of information that must be passed through multiple
* levels of search function.
*/
struct conSrArg
{
CellDef *csa_def; /* Definition being searched. */
int csa_pNum; /* Index of plane being searched. */
TileTypeBitMask *csa_connect; /* Table indicating what connects
* to what.
*/
int (*csa_clientFunc)(); /* Client function to call. */
ClientData csa_clientData; /* Argument for clientFunc. */
bool csa_clear; /* FALSE means pass 1, TRUE
* means pass 2.
*/
Rect csa_bounds; /* Area that limits search. */
};
/*
* The search path is maintained on the C runtime stack
* with rtrTileStack sructures. Each entry on the stack

View File

@ -253,6 +253,144 @@ selClearFunc(scx)
else return 2;
}
/*
* ----------------------------------------------------------------------------
*
* selIntersectPaintFunc2 ---
*
* ----------------------------------------------------------------------------
*/
int
selIntersectPaintFunc2(tile, rect)
Tile *tile; /* The tile to copy paint from. */
Rect *rect; /* Area to clip to */
{
Rect r;
TiToRect(tile, &r);
GEOCLIP(&r, rect); /* Clip out the intersection area */
DBPaint(SelectDef, &r, TiGetTypeExact(tile)); /* Paint back into SelectDef */
return 0; /* Keep the search going. */
}
/*
* ----------------------------------------------------------------------------
*
* selIntersectPaintFunc --
*
* Erase paint of types in rMask from the area of the tile.
*
* ----------------------------------------------------------------------------
*/
int
selIntersectPaintFunc(tile)
Tile *tile; /* The tile to copy paint from. */
{
TileTypeBitMask tMask;
Rect r;
int pNum;
TiToRect(tile, &r);
for (pNum = 0; pNum < DBNumPlanes; pNum++)
{
DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[pNum], &r,
&DBAllButSpaceAndDRCBits, selIntersectPaintFunc2,
(ClientData)&r);
}
return 0; /* Keep the search going. */
}
/*
* ----------------------------------------------------------------------------
*
* SelectIntersect --
*
* This procedure selects all information that falls in a given area
* and contains the intersection of all the supplied types.
*
* Results:
* None.
*
* Side effects:
* The indicated information is added to the select cell, and
* outlined on the screen. Only information of particular
* types, and in expanded cells (according to xMask) is
* selected.
*
* ----------------------------------------------------------------------------
*/
void
SelectIntersect(scx, type, xMask, negate)
SearchContext *scx; /* Describes the area in which material
* is to be selected. The resulting
* coordinates should map to the coordinates
* of EditRootDef. The cell use should be
* the root of a window.
*/
TileType type; /* Indicates which layer to intersect with
* the current selection.
*/
int xMask; /* Indicates window (or windows) where cells
* must be expanded for their contents to be
* considered. 0 means treat everything as
* expanded.
*/
bool negate; /* If true, search on NOT(type) */
{
TileTypeBitMask tMask, rMask;
TileType s, t;
int plane;
SearchContext scx2;
/* The source definition may not change */
if (SelectRootDef != scx->scx_use->cu_def) return;
SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
/* Copy SelectDef contents (paint only) into Select2Def */
DBCellClearDef(Select2Def);
scx2.scx_use = SelectUse;
scx2.scx_area = SelectUse->cu_bbox;
GeoTransTrans(&GeoIdentityTransform, &SelectUse->cu_transform, &scx2.scx_trans);
DBCellCopyAllPaint(&scx2, &DBAllButSpaceAndDRCBits, CU_DESCEND_NO_LOCK,
Select2Use);
/* Clear the original selection */
DBCellClearDef(SelectDef);
/* Select all paint of type "type" and copy into SelectDef */
TTMaskSetOnlyType(&tMask, type);
plane = DBPlane(type);
(void) DBCellCopyAllPaint(scx, &tMask, xMask, SelectUse);
/* Scan Select2Def for all geometry inside the area of "type", and */
/* copy back to SelectDef as "type" */
if (negate)
{
TTMaskCom(&tMask);
TTMaskAndMask(&tMask, &DBPlaneTypes[plane]);
}
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[plane],
&scx->scx_area, &tMask, selIntersectPaintFunc, (ClientData)NULL);
if (negate) TTMaskSetOnlyType(&tMask, type); /* Restore original mask */
DBEraseMask(SelectDef, &TiPlaneRect, &tMask);
/* Display the new selection. */
SelRememberForUndo(FALSE, SelectRootDef, &scx->scx_area);
DBReComputeBbox(SelectDef);
DBWHLRedraw(SelectRootDef, &scx->scx_area, TRUE);
DBWAreaChanged(SelectDef, &SelectDef->cd_extended, DBW_ALLWINDOWS,
&DBAllButSpaceBits);
}
/*
* ----------------------------------------------------------------------------
@ -749,7 +887,7 @@ SelectRegion(scx, type, xMask, pArea, less)
UndoDisable();
DBCellClearDef(Select2Def);
DBTreeCopyConnect(scx, &connections[type], xMask, connections,
&TiPlaneRect, TRUE, Select2Use);
&TiPlaneRect, SelectDoLabels, Select2Use);
UndoEnable();
/* Now transfer what we found into the main selection cell. Pick
@ -850,7 +988,7 @@ SelectNet(scx, type, xMask, pArea, less)
UndoDisable();
DBCellClearDef(Select2Def);
DBTreeCopyConnect(scx, &mask, xMask, DBConnectTbl,
&TiPlaneRect, TRUE, Select2Use);
&TiPlaneRect, SelectDoLabels, Select2Use);
UndoEnable();
/* Network undo method added by Nishit and Tim, July 8-10, 2004 */
@ -1074,7 +1212,7 @@ SelectAndCopy2(newSourceDef)
SearchContext scx;
Rect editArea, labelArea, expanded;
int plane;
void (*savedPaintPlane)();
int (*savedPaintPlane)();
extern int selACPaintFunc(); /* Forward reference. */
extern int selACCellFunc();

View File

@ -22,6 +22,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include "utils/magic.h"
#include "utils/geometry.h"
@ -47,6 +48,7 @@ static int selStretchX, selStretchY; /* Stretch distances. Only one should
* ever be non-zero.
*/
static TileType selStretchType; /* Type of material being stretched. */
unsigned char SelectDoLabels = SEL_DO_LABELS; /* Whether or not to select subcell labels */
typedef struct planeAndArea
{
@ -716,6 +718,43 @@ SelectShort(char *lab1, char *lab2)
destlab = selLabel;
}
/* Was nothing selected? Then run the equivalent of "goto lab1 ; select net */
if (srclab == NULL && destlab == NULL)
{
CellUse *use;
TileType ttype;
Rect rect;
SearchContext scx;
MagWindow *window;
DBWclientRec *crec;
int windowMask;
window = ToolGetBoxWindow(&rect, &windowMask);
if (!window) return NULL;
use = (CellUse *)window->w_surfaceID;
ttype = CmdFindNetProc(lab1, use, &rect, FALSE);
if (ttype == TT_SPACE) return NULL;
bzero(&scx, sizeof(SearchContext));
scx.scx_use = use;
scx.scx_trans = GeoIdentityTransform;
scx.scx_area = rect;
crec = (DBWclientRec *)window->w_clientData;
SelectNet(&scx, ttype, crec->dbw_bitmask, (Rect *)NULL, FALSE);
for (selLabel = SelectDef->cd_labels; selLabel != NULL; selLabel =
selLabel->lab_next)
{
if ((srclab == NULL) && Match(lab1, selLabel->lab_text))
srclab = selLabel;
if ((destlab == NULL) && Match(lab2, selLabel->lab_text))
destlab = selLabel;
}
}
/* Must be able to find both labels */
if (srclab == NULL || destlab == NULL) return NULL;

View File

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

View File

@ -35,6 +35,7 @@ extern void SelectRegion();
extern void SelectInit();
extern void SelectClear();
extern void SelectCell();
extern void SelectIntersect();
extern void SelRemoveArea();
extern int SelRemoveSel2();
extern int SelectRemoveCellUse();
@ -56,6 +57,15 @@ extern void SelectStretch();
extern void SelectArray();
extern void SelectDump();
/* Flag to indicate whether selection captures subcell labels */
extern unsigned char SelectDoLabels;
/* Flag values for SelectDoLabels: */
#define SEL_NO_LABELS 0
#define SEL_DO_LABELS 1
#define SEL_SIMPLE_LABELS 2
/* The following is the root cell that contains the current selection. */
extern CellDef *SelectRootDef;

View File

@ -31,6 +31,7 @@
#include "utils/geofast.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "utils/stack.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "textio/textio.h"
@ -45,54 +46,6 @@
#include "utils/styles.h"
#include "graphics/graphics.h"
/* The following structure is used to hold several pieces
* of information that must be passed through multiple
* levels of search function.
*/
struct conSrArg
{
CellDef *csa_def; /* Definition being searched. */
Plane *csa_plane; /* Current plane being searched. */
TileTypeBitMask *csa_connect; /* Table indicating what connects
* to what.
*/
int (*csa_clientFunc)(); /* Client function to call. */
ClientData csa_clientData; /* Argument for clientFunc. */
bool csa_clear; /* FALSE means pass 1, TRUE
* means pass 2.
*/
Rect csa_bounds; /* Area that limits search. */
};
/* For SimTreeSrConnect, the extraction proceeds in one pass, copying
* all connected stuff from a hierarchy into a single cell. A list
* is kept to record areas that still have to be searched for
* hierarchical stuff.
*/
typedef struct
{
Rect area; /* Area to process */
TileTypeBitMask *connectMask; /* Connection mask for search */
TileType dinfo; /* Info about triangular search areas */
} conSrArea;
struct conSrArg2
{
CellUse *csa2_use; /* Destination use */
TileTypeBitMask *csa2_connect; /* Table indicating what connects
* to what.
*/
Rect *csa2_bounds; /* Area that limits the search */
conSrArea *csa2_list; /* List of areas to process */
int csa2_top; /* Index of next area to process */
int csa2_size; /* Max. number bins in area list */
};
#define CSA2_LIST_START_SIZE 256
/* Forward declarations */
extern char *DBPrintUseId();
@ -303,27 +256,29 @@ SimConnectFunc(tile, cx)
return 1;
}
/* Check if any of the last 5 entries has the same type and */
/* area. If so, don't duplicate the existing entry. */
/* (NOTE: Connect masks are all from the same table, so */
/* they can be compared by address, no need for TTMaskEqual)*/
for (i = csa2->csa2_lasttop; (i >= 0) && (i > csa2->csa2_lasttop - 5); i--)
if (connectMask == csa2->csa2_list[i].connectMask)
if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea))
return 0;
/* Register the area and connection mask as needing to be processed */
if (++csa2->csa2_top == csa2->csa2_size)
if (++csa2->csa2_top == CSA2_LIST_SIZE)
{
/* Reached list size limit---need to enlarge the list */
/* Double the size of the list every time we hit the limit */
conSrArea *newlist;
int i, lastsize = csa2->csa2_size;
csa2->csa2_size *= 2;
newlist = (conSrArea *)mallocMagic(csa2->csa2_size * sizeof(conSrArea));
for (i = 0; i < lastsize; i++)
{
newlist[i].area = csa2->csa2_list[i].area;
newlist[i].connectMask = csa2->csa2_list[i].connectMask;
newlist[i].dinfo = csa2->csa2_list[i].dinfo;
}
freeMagic((char *)csa2->csa2_list);
newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
csa2->csa2_list = newlist;
csa2->csa2_top = 0;
}
csa2->csa2_list[csa2->csa2_top].area = newarea;
@ -407,10 +362,11 @@ SimTreeCopyConnect(scx, mask, xMask, connect, area, destUse, Node_Name)
csa2.csa2_bounds = area;
csa2.csa2_connect = connect;
csa2.csa2_size = CSA2_LIST_START_SIZE;
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_START_SIZE
* sizeof(conSrArea));
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
csa2.csa2_top = -1;
csa2.csa2_lasttop = -1;
csa2.csa2_stack = StackNew(100);
tpath.tp_first = tpath.tp_next = pathName;
tpath.tp_last = pathName + MAXPATHNAME;
@ -425,7 +381,21 @@ SimTreeCopyConnect(scx, mask, xMask, connect, area, destUse, Node_Name)
newmask = csa2.csa2_list[csa2.csa2_top].connectMask;
scx->scx_area = csa2.csa2_list[csa2.csa2_top].area;
newtype = csa2.csa2_list[csa2.csa2_top].dinfo;
csa2.csa2_top--;
if (csa2.csa2_top == 0)
{
if (StackLook(csa2.csa2_stack) != (ClientData)NULL)
{
freeMagic(csa2.csa2_list);
csa2.csa2_list = (conSrArea *)StackPop(csa2.csa2_stack);
csa2.csa2_top = CSA2_LIST_SIZE - 1;
}
else
csa2.csa2_top--;
}
else
csa2.csa2_top--;
csa2.csa2_lasttop = csa2.csa2_top;
if (newtype & TT_DIAGONAL)
SimTreeSrNMTiles(scx, newtype, newmask, xMask, &tpath,
@ -435,6 +405,7 @@ SimTreeCopyConnect(scx, mask, xMask, connect, area, destUse, Node_Name)
(ClientData) &csa2);
}
freeMagic((char *)csa2.csa2_list);
StackFree(csa2.csa2_stack);
/* Recompute the bounding box of the destination and record
* its area for redisplay.
@ -636,7 +607,7 @@ SimSrConnect(def, startArea, mask, connect, bounds, func, clientData)
csa.csa_clientData = clientData;
csa.csa_clear = FALSE;
csa.csa_connect = connect;
csa.csa_plane = def->cd_planes[startPlane];
csa.csa_pNum = startPlane;
if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
return result;

View File

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

View File

@ -8,6 +8,8 @@
# Revision 1
# October 29, 2020
# Revision 2 (names are hashed from properties)
# March 9, 2021
# Added spice-to-layout procedure
#--------------------------------------------------------------
# Sets up the environment for a toolkit. The toolkit must
# supply a namespace that is the "library name". For each
@ -105,6 +107,307 @@ magic::macro ^P "magic::gencell {} ; raise .params"
magic::tag select "[magic::tag select]; magic::gencell_update %1"
#--------------------------------------------------------------
# Supporting procedures for netlist_to_layout procedure
#--------------------------------------------------------------
# move_forward_by_width --
#
# Given an instance name, find the instance and position the
# cursor box at the right side of the instance.
proc magic::move_forward_by_width {instname} {
select cell $instname
set anum [lindex [array -list count] 1]
set xpitch [lindex [array -list pitch] 0]
set bbox [box values]
set posx [lindex $bbox 0]
set posy [lindex $bbox 1]
set width [expr [lindex $bbox 2] - $posx]
set posx [expr $posx + $width + $xpitch * $anum]
box position ${posx}i ${posy}i
return [lindex $bbox 3]
}
# get_and_move_inst --
#
# Given a cell name, creat an instance of the cell named "instname"
# at the current cursor box position. If option "anum" is given
# and > 1, then array the cell.
proc magic::get_and_move_inst {cellname instname {anum 1}} {
set newinst [getcell $cellname]
select cell $newinst
if {$newinst == ""} {return}
identify $instname
if {$anum > 1} {array 1 $anum}
set bbox [box values]
set posx [lindex $bbox 2]
set posy [lindex $bbox 1]
box position ${posx}i ${posy}i
return [lindex $bbox 3]
}
# create_new_pin --
#
# Create a new pin of size 1um x 1um at the current cursor box
# location. If "layer" is given, then create the pin on the
# given layer. Otherwise, the pin is created on the m1 layer.
proc magic::create_new_pin {pinname portnum {layer m1}} {
box size 1um 1um
paint $layer
label $pinname FreeSans 16 0 0 0 c $layer
port make $portnum
box move s 2um
}
# generate_layout_add --
#
# Add a new subcircuit to a layout and seed it with components
# as found in the list "complist", and add pins according to the
# pin names in "subpins". Each entry in "complist" is a single
# device line from a SPICE file.
proc magic::generate_layout_add {subname subpins complist library} {
global PDKNAMESPACE
# Create a new subcircuit
load $subname -quiet
box 0 0 0 0
# Generate pins
if {[llength $subpins] > 0} {
set pinlist [split $subpins]
set i 0
foreach pin $pinlist {
# Escape [ and ] in pin name
set pin_esc [string map {\[ \\\[ \] \\\]} $pin]
magic::create_new_pin $pin_esc $i
incr i
}
}
# Set initial position for importing cells
box size 0 0
set posx 0
set posy [expr {round(3 / [cif scale out])}]
box position ${posx}i ${posy}i
# Seed layout with components
foreach comp $complist {
set pinlist {}
set paramlist {}
# NOTE: This routine deals with subcircuit calls and devices
# with models. It needs to determine when a device is instantiated
# without a model, and ignore such devices.
# Parse SPICE line into pins, device name, and parameters. Make
# sure parameters incorporate quoted expressions as {} or ''.
set rest $comp
while {$rest != ""} {
if {[regexp -nocase {^[ \t]*[^= \t]+=[^=]+} $rest]} {
break
} elseif {[regexp -nocase {^[ \t]*([^ \t]+)[ \t]*(.*)$} $rest \
valid token rest]} {
lappend pinlist $token
} else {
set rest ""
}
}
while {$rest != ""} {
if {[regexp -nocase {^([^= \t]+)=\'([^\']+)\'[ \t]*(.*)} $rest \
valid pname value rest]} {
lappend paramlist [list $pname "{$value}"]
} elseif {[regexp -nocase {^([^= \t]+)=\{([^\}]+)\}[ \t]*(.*)} $rest \
valid pname value rest]} {
lappend paramlist [list $pname "{$value}"]
} elseif {[regexp -nocase {^([^= \t]+)=([^= \t]+)[ \t]*(.*)} $rest \
valid pname value rest]} {
lappend paramlist [list $pname $value]
} else {
puts stderr "Error parsing line \"$comp\""
puts stderr "at: \"$rest\""
set rest ""
}
}
if {[llength $pinlist] < 2} {
puts stderr "Error: No device type found in line \"$comp\""
puts stderr "Tokens found are: \"$pinlist\""
continue
}
set instname [lindex $pinlist 0]
set devtype [lindex $pinlist end]
set pinlist [lrange $pinlist 0 end-1]
set mult 1
foreach param $paramlist {
set parmname [lindex $param 0]
set parmval [lindex $param 1]
if {[string toupper $parmname] == "M"} {
if {[catch {set mult [expr {int($parmval)}]}]} {
set mult [expr [string trim $parmval "'"]]
}
}
}
# devtype is assumed to be in library. If not, it will attempt to
# use 'getcell' on devtype. Note that this code depends on the
# PDK setting varible PDKNAMESPACE.
if {$library != ""} {
set libdev ${library}::${devtype}
} else {
set libdev ${PDKNAMESPACE}::${devtype}
}
set outparts {}
lappend outparts "magic::gencell $libdev $instname"
# Output all parameters. Parameters not used by the toolkit are
# ignored by the toolkit.
lappend outparts "-spice"
foreach param $paramlist {
lappend outparts [string tolower [lindex $param 0]]
lappend outparts [lindex $param 1]
}
if {[catch {eval [join $outparts]}]} {
# Assume this is not a gencell, and get an instance.
magic::get_and_move_inst $devtype $instname $mult
} else {
# Move forward for next gencell
magic::move_forward_by_width $instname
}
}
save $subname
}
#--------------------------------------------------------------
# Wrapper for generating an initial layout from a SPICE netlist
# using the defined PDK toolkit procedures
#
# "netfile" is the name of a SPICE netlist
# "library" is the name of the PDK library namespace
#--------------------------------------------------------------
proc magic::netlist_to_layout {netfile library} {
if {![file exists $netfile]} {
puts stderr "No such file $netfile"
return
}
# Read data from file. Remove comment lines and concatenate
# continuation lines.
set topname [file rootname [file tail $netfile]]
puts stdout "Creating layout from [file tail $netfile]"
if {[file ext $netfile] == ".cdl"} {
set is_cdl true
} else {
set is_cdl false
}
if [catch {open $netfile r} fnet] {
puts stderr "Error: Cannot open file \"$netfile\" for reading."
return
}
set fdata {}
set lastline ""
while {[gets $fnet line] >= 0} {
# Handle CDL format *.PININFO (convert to .PININFO ...)
if {$is_cdl && ([string range $line 0 1] == "*.")} {
if {[string tolower [string range $line 2 8]] == "pininfo"} {
set line [string range $line 1 end]
}
}
if {[string index $line 0] != "*"} {
if {[string index $line 0] == "+"} {
if {[string range $line end end] != " "} {
append lastline " "
}
append lastline [string range $line 1 end]
} else {
lappend fdata $lastline
set lastline $line
}
}
}
lappend fdata $lastline
close $fnet
set insub false
set incmd false
set subname ""
set subpins ""
set complist {}
set toplist {}
# suspendall
set ignorekeys {.global .ic .option .end}
# Parse the file
foreach line $fdata {
if {$incmd} {
if {[regexp -nocase {^[ \t]*\.endc} $line]} {
set incmd false
}
} elseif {! $insub} {
set ftokens [split $line]
set keyword [string tolower [lindex $ftokens 0]]
if {[lsearch $ignorekeys $keyword] != -1} {
continue
} elseif {$keyword == ".command"} {
set incmd true
} elseif {$keyword == ".subckt"} {
set subname [lindex $ftokens 1]
set subpins [lrange $ftokens 2 end]
set insub true
} elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \
valid instname rest]} {
lappend toplist $line
} elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \
valid instname rest]} {
# These are testbench devices and should be ignored
continue
}
} else {
if {[regexp -nocase {^[ \t]*\.ends} $line]} {
set insub false
magic::generate_layout_add $subname $subpins $complist $library
set subname ""
set subpins ""
set complist {}
} elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \
valid instname rest]} {
lappend complist $line
} elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \
valid instname rest]} {
# These are testbench devices and should be ignored
continue
}
}
}
# Add in any top-level components (not in subcircuits)
if {[llength $toplist] > 0} {
magic::generate_layout_add $topname "" $toplist $library
}
# resumeall
}
#-------------------------------------------------------------
# gencell
#
@ -184,6 +487,11 @@ proc magic::gencell {gencell_name {instname {}} args} {
set gencell_type $gencell_name
}
# Check that the device exists as a gencell, or else return an error
if {[namespace eval ::${library} info commands ${gencell_type}_convert] == ""} {
error "No import routine for ${library} library cell ${gencell_type}!"
}
if {$instname == {}} {
# Case: Interactive, new device with parameters in args (if any)
if {$spicemode == 1} {
@ -237,6 +545,7 @@ proc magic::gencell {gencell_name {instname {}} args} {
}
}
}
return 0
}
#-------------------------------------------------------------
@ -436,6 +745,14 @@ proc magic::gencell_change {instname gencell_type library parameters} {
# then keep the old instance name.
if {[string first $old_gname $instname] != 0} {
set newinstname $instname
} else {
# The buttons "Apply" and "Okay" need to be changed for the new
# instance name
catch {.params.buttons.apply config -command \
"magic::gencell_change $newinstname $gencell_type $library {}"}
catch {.params.buttons.okay config -command \
"magic::gencell_change $newinstname $gencell_type $library {} ;\
destroy .params"}
}
}
identify $newinstname

View File

@ -58,11 +58,31 @@ proc magic::makecrashbackup {} {
global Opts
*bypass crash save
if {$Opts(backupinterval) > 0} {
after $Opts(backupinterval) magic::makecrashbackup
if {![catch set Opts(backupinterval)]} {
if {$Opts(backupinterval) > 0} {
after $Opts(backupinterval) magic::makecrashbackup
}
}
}
#----------------------------------------------------------------
# magic::crashbackups ---
#
# Create periodic backups. Options are:
#
# start: Begin periodic backups. If interval is not
# specified, then set interval to 10 minutes.
#
# resume: Resume periodic backups if started and stopped,
# but not if disabled or never started.
#
# stop: Stop periodic backups.
#
# disable: Disable periodic backups; set to state of
# never having been started.
#
#----------------------------------------------------------------
proc magic::crashbackups {{option start}} {
global Opts
@ -71,12 +91,25 @@ proc magic::crashbackups {{option start}} {
if {[catch set Opts(backupinterval)]} {
set Opts(backupinterval) 600000
}
after $Opts(backupinterval) magic::makecrashbackup
if {$Opts(backupinterval) > 0} {
after $Opts(backupinterval) magic::makecrashbackup
}
}
resume {
if {![catch set Opts(backupinterval)]} {
if {$Opts(backupinterval) > 0} {
after $Opts(backupinterval) magic::makecrashbackup
}
}
}
stop -
cancel {
after cancel magic::makecrashbackup
}
disable {
after cancel magic::makecrashbackup
unset Opts(backupinterval)
}
}
}
@ -123,12 +156,17 @@ proc magic::popstack {} {
} else {
set ltag [tag load]
tag load {}
suspendall
load [lindex $editstack end]
set snaptype [snap]
snap internal
view [lindex $editstack end-1]
tag load $ltag
set editstack [lrange $editstack 0 end-2]
snap $snaptype
catch {magic::cellmanager}
catch {magic::captions}
resumeall
tag load $ltag
set editstack [lrange $editstack 0 end-2]
}
return
}

View File

@ -554,7 +554,6 @@ set Opts(crosshair) 0
set Opts(hidelocked) 0
set Opts(hidespecial) 0
set Opts(toolbar) 0
set Opts(scale) 1.0
set Opts(toolscale) 1.0
set Opts(drc) 1
set Opts(autobuttontext) 1
@ -1135,6 +1134,16 @@ proc magic::openwrapper {{cell ""} {framename ""}} {
toplevel $framename
tkwait visibility $framename
# Get scale from the TkDefaultFont size, unless Opts(scale) is already
# set. On standard displays, an "M" in the Sans font is usually 10
# pixels wide, and 22 on high resolution displays, so this maps to
# a scale of 1 on standard displays and a scale of 2 on high resolution
# displays. Make sure scale doesn't go to zero or bad things happen.
if [catch {set Opts(scale)}] {
set Opts(scale) [expr {max(1, int([font measure TkDefaultFont M] / 10))}]
}
# Resize the window
if {[catch {wm geometry ${framename} $Winopts(${framename},geometry)}]} {
catch {wm geometry ${framename} $Opts(geometry)}

View File

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

View File

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