Compare commits
73 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
66faf1d907 | |
|
|
37db9e453b | |
|
|
2d5c4be6dd | |
|
|
a9673e45ae | |
|
|
8f95efc257 | |
|
|
fd12c39c37 | |
|
|
7d9167257a | |
|
|
058b320c3f | |
|
|
fee4b887c0 | |
|
|
04e91d640d | |
|
|
7d9210a3f1 | |
|
|
03bbc544b2 | |
|
|
ee79bba5e4 | |
|
|
15943d0cb1 | |
|
|
7bdd9e1d4f | |
|
|
725c8e9235 | |
|
|
73ffad3802 | |
|
|
037daf1121 | |
|
|
d0ef32de0f | |
|
|
0d9b862c0e | |
|
|
71dc472797 | |
|
|
2929ef583e | |
|
|
ecd6ec56ae | |
|
|
f3478cba7b | |
|
|
ba5154698d | |
|
|
1023461ca5 | |
|
|
197763e46e | |
|
|
cb7855235a | |
|
|
8f684ad5be | |
|
|
f3404f67b7 | |
|
|
cedd64adcb | |
|
|
afca58f162 | |
|
|
95baea1c22 | |
|
|
751757a02c | |
|
|
c32bae1a24 | |
|
|
0c913eca59 | |
|
|
2f00f6d8f1 | |
|
|
9ab7b77dc4 | |
|
|
00c0208f18 | |
|
|
cb30ac369b | |
|
|
7e9b6fb61e | |
|
|
3b1de8ff40 | |
|
|
10a6c8635f | |
|
|
e2292f5d70 | |
|
|
736c507fe8 | |
|
|
c20a267a2b | |
|
|
bad0b67ce8 | |
|
|
727649b308 | |
|
|
4dde62b206 | |
|
|
94edc2a23d | |
|
|
b248f186ec | |
|
|
1656866f41 | |
|
|
99297e33ec | |
|
|
727833fcd3 | |
|
|
feb5d61294 | |
|
|
4b120eb417 | |
|
|
55eadcfb90 | |
|
|
b4f62abb40 | |
|
|
deefe0e3a3 | |
|
|
57c33c48c7 | |
|
|
76f97c90e5 | |
|
|
297a05c4ed | |
|
|
b768fcc3f9 | |
|
|
4943da5ce4 | |
|
|
512400e39f | |
|
|
0cbed6078a | |
|
|
9760ef6d1d | |
|
|
bd13febb72 | |
|
|
81436b75ed | |
|
|
8822f8dce2 | |
|
|
f03003b79f | |
|
|
802c31d16a | |
|
|
308224109f |
|
|
@ -53,6 +53,7 @@ int calmaNonManhattan;
|
|||
int CalmaFlattenLimit = 10;
|
||||
int NameConvertErrors = 0;
|
||||
bool CalmaRewound = FALSE;
|
||||
bool CalmaRecordPaths = FALSE;
|
||||
TileTypeBitMask *CalmaMaskHints = NULL;
|
||||
|
||||
extern HashTable calmaDefInitHash;
|
||||
|
|
@ -505,28 +506,33 @@ calmaParseStructure(
|
|||
|
||||
if (CalmaReadOnly || predefined)
|
||||
{
|
||||
PropertyRecord *proprec;
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
|
||||
fpcopy = (char *)mallocMagic(20);
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||
proprec->prop_type = PROPERTY_TYPE_DOUBLE;
|
||||
proprec->prop_len = 1;
|
||||
proprec->prop_value.prop_double[0] = filepos;
|
||||
DBPropPut(cifReadCellDef, "GDS_START", (ClientData)proprec);
|
||||
|
||||
filepos = FTELL(calmaInputFile);
|
||||
sprintf(fpcopy, "%"DLONG_PREFIX"d", (dlong) filepos);
|
||||
DBPropPut(cifReadCellDef, "GDS_END", (ClientData)fpcopy);
|
||||
|
||||
DBPropPut(cifReadCellDef, "GDS_FILE", (ClientData)fncopy);
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||
proprec->prop_type = PROPERTY_TYPE_DOUBLE;
|
||||
proprec->prop_len = 1;
|
||||
proprec->prop_value.prop_double[0] = filepos;
|
||||
DBPropPut(cifReadCellDef, "GDS_END", (ClientData)proprec);
|
||||
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) - 7 +
|
||||
strlen(cstring));
|
||||
proprec->prop_type = PROPERTY_TYPE_STRING;
|
||||
proprec->prop_len = 1;
|
||||
strcpy(proprec->prop_value.prop_string, cstring);
|
||||
DBPropPut(cifReadCellDef, "GDS_FILE", (ClientData)proprec);
|
||||
|
||||
if (predefined)
|
||||
{
|
||||
|
|
@ -783,8 +789,8 @@ calmaElementSref(
|
|||
char *filename)
|
||||
{
|
||||
int nbytes, rtype, cols, rows, nref, n, i, savescale;
|
||||
int xlo, ylo, xhi, yhi, xsep, ysep;
|
||||
bool madeinst = FALSE;
|
||||
int xlo, ylo, xhi, yhi, xsep, ysep, angle;
|
||||
bool madeinst = FALSE, rotated = FALSE;
|
||||
char *sname = NULL;
|
||||
bool isArray = FALSE;
|
||||
bool dolookahead = FALSE;
|
||||
|
|
@ -984,17 +990,73 @@ calmaElementSref(
|
|||
refarray[2].p_x = refarray[2].p_y = 0;
|
||||
}
|
||||
|
||||
/* If the array is given an angle, then the meaning of rows and
|
||||
* columns needs to be swapped for the purpose of ignoring
|
||||
* X or Y values in the case of a 1-row or 1-column entry.
|
||||
*/
|
||||
angle = GeoTransAngle(&trans, 0);
|
||||
if ((angle == 90) || (angle == 270) || (angle == -90) || (angle == -270))
|
||||
rotated = TRUE;
|
||||
|
||||
/* If this is a cell reference, then we scale to magic coordinates
|
||||
* and place the cell in the magic database. However, if this is
|
||||
* a cell to be flattened a la "gds flatten", then we keep the GDS
|
||||
* coordinates, and don't scale to the magic database.
|
||||
*
|
||||
* NOTE: Scaling everything in the middle or reading array data
|
||||
* and then retroactively adjusting the array data read earlier
|
||||
* is problematic, and probably incorrect.
|
||||
*/
|
||||
|
||||
|
||||
for (n = 0; n < nref; n++)
|
||||
{
|
||||
savescale = calmaReadScale1;
|
||||
|
||||
/* If there is only one column, then X data in the 2nd or 3rd
|
||||
* entry is irrelevant. If there is only one row, then Y data
|
||||
* in the 2nd or 3rd entry is irrelevant. Prevent issues caused
|
||||
* by incorrect/uninitialized data in these positions by ignoring
|
||||
* them as needed.
|
||||
*/
|
||||
|
||||
if ((n > 0) && ((!rotated && (rows == 1)) || (rotated && (cols == 1))))
|
||||
{
|
||||
calmaReadX(&refarray[n], 1);
|
||||
calmaSkipBytes(4);
|
||||
refarray[n].p_y = refarray[0].p_y;
|
||||
}
|
||||
else if ((n > 0) && ((!rotated && (cols == 1)) || (rotated && (rows == 1))))
|
||||
{
|
||||
calmaSkipBytes(4);
|
||||
calmaReadY(&refarray[n], 1);
|
||||
refarray[n].p_x = refarray[0].p_x;
|
||||
}
|
||||
else
|
||||
calmaReadPoint(&refarray[n], 1);
|
||||
|
||||
if (savescale != calmaReadScale1)
|
||||
{
|
||||
/* Scale changed, so update previous points read */
|
||||
int newscale = calmaReadScale1 / savescale;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
refarray[i].p_x *= newscale;
|
||||
refarray[i].p_y *= newscale;
|
||||
}
|
||||
}
|
||||
|
||||
if (FEOF(calmaInputFile))
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (n = 0; n < nref; n++)
|
||||
refunscaled[n] = refarray[n]; // Save for CDFLATGDS cells
|
||||
|
||||
for (n = 0; n < nref; n++)
|
||||
{
|
||||
savescale = cifCurReadStyle->crs_scaleFactor;
|
||||
calmaReadPoint(&refarray[n], 1);
|
||||
refunscaled[n] = refarray[n]; // Save for CDFLATGDS cells
|
||||
|
||||
refarray[n].p_x = CIFScaleCoord(refarray[n].p_x, COORD_EXACT);
|
||||
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
||||
{
|
||||
|
|
@ -1015,9 +1077,6 @@ calmaElementSref(
|
|||
}
|
||||
refarray[n].p_x *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
||||
}
|
||||
|
||||
if (FEOF(calmaInputFile))
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Skip remainder */
|
||||
|
|
|
|||
|
|
@ -114,6 +114,8 @@ calmaInputRescale(
|
|||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* calmaReadX ---
|
||||
* calmaReadY ---
|
||||
* calmaReadPoint ---
|
||||
*
|
||||
* Read a point from the input.
|
||||
|
|
@ -132,11 +134,17 @@ calmaInputRescale(
|
|||
* encountered, then everything in the GDS planes is rescaled
|
||||
* to match.
|
||||
*
|
||||
* Notes:
|
||||
* This routine has been split into individual X and Y reads so that
|
||||
* array data can be read while ignoring offset information when there
|
||||
* is only one row or column; otherwise, bad or uninitialized data
|
||||
* in the record can cause unnecessary and incorrect scaling.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
calmaReadPoint(
|
||||
calmaReadX(
|
||||
Point *p,
|
||||
int iscale)
|
||||
{
|
||||
|
|
@ -163,6 +171,15 @@ calmaReadPoint(
|
|||
}
|
||||
}
|
||||
p->p_x /= calmaReadScale2;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
calmaReadY(
|
||||
Point *p,
|
||||
int iscale)
|
||||
{
|
||||
int rescale;
|
||||
|
||||
READI4((p)->p_y);
|
||||
p->p_y *= (calmaReadScale1 * iscale);
|
||||
|
|
@ -188,6 +205,15 @@ calmaReadPoint(
|
|||
p->p_y /= calmaReadScale2;
|
||||
}
|
||||
|
||||
void
|
||||
calmaReadPoint(
|
||||
Point *p,
|
||||
int iscale)
|
||||
{
|
||||
calmaReadX(p, iscale);
|
||||
calmaReadY(p, iscale);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
|
|
@ -692,7 +718,12 @@ calmaElementPath(void)
|
|||
}
|
||||
}
|
||||
|
||||
CIFPropRecordPath(cifReadCellDef, pathheadp, TRUE, "path");
|
||||
/* If requested by command option, record the path centerline as a
|
||||
* property of the cell def.
|
||||
*/
|
||||
if (CalmaRecordPaths)
|
||||
CIFPropRecordPath(cifReadCellDef, pathheadp, TRUE, "path");
|
||||
|
||||
CIFPaintWirePath(pathheadp, width,
|
||||
(pathtype == CALMAPATH_SQUAREFLUSH || pathtype == CALMAPATH_CUSTOM) ?
|
||||
FALSE : TRUE, plane, CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||
|
|
|
|||
|
|
@ -528,7 +528,7 @@ calmaDumpStructure(
|
|||
|
||||
/* Is view abstract? */
|
||||
DBPropGet(edef, "LEFview", &isAbstract);
|
||||
chklibname = (char *)DBPropGet(edef, "GDS_FILE", &isReadOnly);
|
||||
chklibname = DBPropGetString(edef, "GDS_FILE", &isReadOnly);
|
||||
|
||||
if (isAbstract && isReadOnly)
|
||||
{
|
||||
|
|
@ -738,7 +738,7 @@ calmaFullDump(
|
|||
* names in the GDS file do not shadow any names in the database.
|
||||
*/
|
||||
|
||||
viewopts = (char *)DBPropGet(def, "LEFview", &isAbstract);
|
||||
viewopts = DBPropGetString(def, "LEFview", &isAbstract);
|
||||
if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
|
||||
{
|
||||
/* Generate a SHORT name for this cell (else it is easy to run into the
|
||||
|
|
@ -918,7 +918,7 @@ calmaProcessDef(
|
|||
DBPropGet(def, "GDS_END", &hasGDSEnd);
|
||||
DBPropGet(def, "CIFhier", &needHier);
|
||||
|
||||
filename = (char *)DBPropGet(def, "GDS_FILE", &isReadOnly);
|
||||
filename = DBPropGetString(def, "GDS_FILE", &isReadOnly);
|
||||
|
||||
/* When used with "calma addendum true", don't output the read-only */
|
||||
/* cells. This makes the library incomplete and dependent on the */
|
||||
|
|
@ -1033,13 +1033,12 @@ calmaProcessDef(
|
|||
}
|
||||
else
|
||||
{
|
||||
offptr = (char *)DBPropGet(def, "GDS_END", NULL);
|
||||
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
|
||||
cval = DBPropGetDouble(def, "GDS_END", NULL);
|
||||
cellend = (off_t)cval;
|
||||
offptr = (char *)DBPropGet(def, "GDS_BEGIN", &oldStyle);
|
||||
cval = DBPropGetDouble(def, "GDS_BEGIN", &oldStyle);
|
||||
if (!oldStyle)
|
||||
{
|
||||
offptr = (char *)DBPropGet(def, "GDS_START", NULL);
|
||||
cval = DBPropGetDouble(def, "GDS_START", NULL);
|
||||
|
||||
/* Write our own header and string name, to ensure */
|
||||
/* that the magic cell name and GDS name match. */
|
||||
|
|
@ -1056,7 +1055,6 @@ calmaProcessDef(
|
|||
calmaOutStructName(CALMA_STRNAME, def, outf);
|
||||
}
|
||||
|
||||
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
|
||||
cellstart = (off_t)cval;
|
||||
|
||||
/* GDS_START has been defined as the start of data after the cell */
|
||||
|
|
@ -1263,7 +1261,7 @@ calmaOutFunc(
|
|||
int dbunits;
|
||||
calmaOutputStruct cos;
|
||||
bool propfound;
|
||||
char *propvalue;
|
||||
PropertyRecord *proprec;
|
||||
|
||||
cos.f = f;
|
||||
cos.area = (cliprect == &TiPlaneRect) ? NULL : cliprect;
|
||||
|
|
@ -1323,14 +1321,20 @@ calmaOutFunc(
|
|||
|
||||
/* Include any fixed bounding box as part of the area to process, */
|
||||
/* in case the fixed bounding box is larger than the geometry. */
|
||||
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
|
||||
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
Rect bbox;
|
||||
|
||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
||||
&bbox.r_xtop, &bbox.r_ytop) == 4)
|
||||
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||
(proprec->prop_len == 4))
|
||||
{
|
||||
bbox.r_xbot = proprec->prop_value.prop_integer[0];
|
||||
bbox.r_ybot = proprec->prop_value.prop_integer[1];
|
||||
bbox.r_xtop = proprec->prop_value.prop_integer[2];
|
||||
bbox.r_ytop = proprec->prop_value.prop_integer[3];
|
||||
GeoInclude(&bbox, &bigArea);
|
||||
}
|
||||
}
|
||||
|
||||
CIFErrorDef = def;
|
||||
|
|
|
|||
|
|
@ -508,7 +508,7 @@ calmaDumpStructureZ(
|
|||
|
||||
/* Is view abstract? */
|
||||
DBPropGet(edef, "LEFview", &isAbstract);
|
||||
chklibname = (char *)DBPropGet(edef, "GDS_FILE", &isReadOnly);
|
||||
chklibname = DBPropGetString(edef, "GDS_FILE", &isReadOnly);
|
||||
|
||||
if (isAbstract && isReadOnly)
|
||||
{
|
||||
|
|
@ -716,7 +716,7 @@ calmaFullDumpZ(
|
|||
* names in the GDS file do not shadow any names in the database.
|
||||
*/
|
||||
|
||||
viewopts = (char *)DBPropGet(def, "LEFview", &isAbstract);
|
||||
viewopts = DBPropGetString(def, "LEFview", &isAbstract);
|
||||
if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
|
||||
{
|
||||
/* Generate a SHORT name for this cell (else it is easy to run into the
|
||||
|
|
@ -870,7 +870,7 @@ calmaProcessDefZ(
|
|||
DBPropGet(def, "GDS_START", &hasContent);
|
||||
DBPropGet(def, "GDS_END", &hasGDSEnd);
|
||||
DBPropGet(def, "CIFhier", &needHier);
|
||||
filename = (char *)DBPropGet(def, "GDS_FILE", &isReadOnly);
|
||||
filename = DBPropGetString(def, "GDS_FILE", &isReadOnly);
|
||||
|
||||
/* When used with "calma addendum true", don't output the read-only */
|
||||
/* cells. This makes the library incomplete and dependent on the */
|
||||
|
|
@ -985,13 +985,12 @@ calmaProcessDefZ(
|
|||
}
|
||||
else
|
||||
{
|
||||
offptr = (char *)DBPropGet(def, "GDS_END", NULL);
|
||||
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
|
||||
cval = DBPropGetDouble(def, "GDS_END", NULL);
|
||||
cellend = (z_off_t)cval;
|
||||
offptr = (char *)DBPropGet(def, "GDS_BEGIN", &oldStyle);
|
||||
cval = DBPropGetDouble(def, "GDS_BEGIN", &oldStyle);
|
||||
if (!oldStyle)
|
||||
{
|
||||
offptr = (char *)DBPropGet(def, "GDS_START", NULL);
|
||||
cval = DBPropGetDouble(def, "GDS_START", NULL);
|
||||
|
||||
/* Write our own header and string name, to ensure */
|
||||
/* that the magic cell name and GDS name match. */
|
||||
|
|
@ -1008,7 +1007,6 @@ calmaProcessDefZ(
|
|||
calmaOutStructNameZ(CALMA_STRNAME, def, outf);
|
||||
}
|
||||
|
||||
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
|
||||
cellstart = (z_off_t)cval;
|
||||
|
||||
/* GDS_START has been defined as the start of data after the cell */
|
||||
|
|
@ -1186,6 +1184,7 @@ calmaOutFuncZ(
|
|||
int dbunits;
|
||||
calmaOutputStructZ cos;
|
||||
bool propfound;
|
||||
PropertyRecord *proprec;
|
||||
char *propvalue;
|
||||
extern int compport(const void *one, const void *two); /* Forward declaration */
|
||||
|
||||
|
|
@ -1247,14 +1246,20 @@ calmaOutFuncZ(
|
|||
|
||||
/* Include any fixed bounding box as part of the area to process, */
|
||||
/* in case the fixed bounding box is larger than the geometry. */
|
||||
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
|
||||
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
Rect bbox;
|
||||
|
||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
||||
&bbox.r_xtop, &bbox.r_ytop) == 4)
|
||||
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||
(proprec->prop_len == 4))
|
||||
{
|
||||
bbox.r_xbot = proprec->prop_value.prop_integer[0];
|
||||
bbox.r_ybot = proprec->prop_value.prop_integer[1];
|
||||
bbox.r_xtop = proprec->prop_value.prop_integer[2];
|
||||
bbox.r_ytop = proprec->prop_value.prop_integer[3];
|
||||
GeoInclude(&bbox, &bigArea);
|
||||
}
|
||||
}
|
||||
|
||||
CIFErrorDef = def;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ extern TileTypeBitMask *CalmaMaskHints;
|
|||
extern bool CalmaMergeTiles;
|
||||
extern bool CalmaFlattenArrays;
|
||||
extern bool CalmaNoDRCCheck;
|
||||
extern bool CalmaRecordPaths;
|
||||
extern bool CalmaFlattenUses;
|
||||
extern int CalmaFlattenLimit;
|
||||
extern float CalmaMagScale;
|
||||
|
|
@ -81,6 +82,8 @@ extern int calmaProcessDefZ(CellDef *def, gzFile outf, bool do_library);
|
|||
#endif
|
||||
extern bool calmaReadI2Record(int type, int *pvalue);
|
||||
extern bool calmaReadI4Record(int type, int *pvalue);
|
||||
extern void calmaReadX(Point *p, int iscale);
|
||||
extern void calmaReadY(Point *p, int iscale);
|
||||
extern void calmaReadPoint(Point *p, int iscale);
|
||||
extern bool calmaReadR8(double *pd);
|
||||
extern bool calmaReadStampRecord(int type, int *stampptr);
|
||||
|
|
|
|||
372
cif/CIFgen.c
372
cif/CIFgen.c
|
|
@ -25,6 +25,7 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
|
|||
#include <stdlib.h> /* for abs() */
|
||||
#include <math.h> /* for ceil() and sqrt() */
|
||||
#include <ctype.h>
|
||||
#include <string.h> /* for strcmp() */
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
|
|
@ -1500,6 +1501,7 @@ cifBloatAllFunc(
|
|||
|
||||
while (!StackEmpty(BloatStack))
|
||||
{
|
||||
Rect cifarea;
|
||||
TileType tt;
|
||||
|
||||
POPTILE(t, dinfo, BloatStack);
|
||||
|
|
@ -1516,8 +1518,6 @@ cifBloatAllFunc(
|
|||
|
||||
if (op->co_distance > 0)
|
||||
{
|
||||
Rect cifarea;
|
||||
|
||||
cifarea.r_xbot = area.r_xbot;
|
||||
cifarea.r_ybot = area.r_ybot;
|
||||
cifarea.r_xtop = area.r_xtop;
|
||||
|
|
@ -1555,40 +1555,42 @@ cifBloatAllFunc(
|
|||
{
|
||||
tt = TiGetTypeExact(t);
|
||||
if (op->co_distance > 0)
|
||||
GeoClip(&area, &clipArea);
|
||||
DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &area,
|
||||
DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &cifarea,
|
||||
CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
else
|
||||
DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &area,
|
||||
CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
}
|
||||
|
||||
/* Top */
|
||||
for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
|
||||
if (TTMaskHasType(connect, TiGetBottomType(tp)))
|
||||
PUSHTILE(tp,
|
||||
(SplitDirection(tp) == ((tt & TT_DIRECTION) ? 1 : 0)) ?
|
||||
(TileType)0 : (TileType)TT_SIDE,
|
||||
BloatStack);
|
||||
if ((op->co_distance == 0) || (area.r_ytop < clipArea.r_ytop))
|
||||
for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
|
||||
if (TTMaskHasType(connect, TiGetBottomType(tp)))
|
||||
PUSHTILE(tp, (SplitDirection(tp) == ((tt & TT_DIRECTION) ? 1 : 0)) ?
|
||||
(TileType)0 : (TileType)TT_SIDE, BloatStack);
|
||||
|
||||
/* Left */
|
||||
for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
|
||||
if (TTMaskHasType(connect, TiGetRightType(tp)))
|
||||
PUSHTILE(tp, (TileType)TT_SIDE, BloatStack);
|
||||
if ((op->co_distance == 0) || (area.r_xbot > clipArea.r_xbot))
|
||||
for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
|
||||
if (TTMaskHasType(connect, TiGetRightType(tp)))
|
||||
PUSHTILE(tp, (TileType)TT_SIDE, BloatStack);
|
||||
|
||||
/* Bottom */
|
||||
for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
|
||||
if (TTMaskHasType(connect, TiGetTopType(tp)))
|
||||
PUSHTILE(tp,
|
||||
(SplitDirection(tp) == ((tt & TT_DIRECTION) ? 1 : 0)) ?
|
||||
(TileType)TT_SIDE : (TileType)0,
|
||||
BloatStack);
|
||||
if ((op->co_distance == 0) || (area.r_ybot > clipArea.r_ybot))
|
||||
for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
|
||||
if (TTMaskHasType(connect, TiGetTopType(tp)))
|
||||
PUSHTILE(tp, (SplitDirection(tp) == ((tt & TT_DIRECTION) ? 1 : 0)) ?
|
||||
(TileType)TT_SIDE : (TileType)0, BloatStack);
|
||||
|
||||
/* Right */
|
||||
for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
|
||||
if (TTMaskHasType(connect, TiGetLeftType(tp)))
|
||||
PUSHTILE(tp, (TileType)0, BloatStack);
|
||||
if ((op->co_distance == 0) || (area.r_xtop < clipArea.r_xtop))
|
||||
for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
|
||||
if (TTMaskHasType(connect, TiGetLeftType(tp)))
|
||||
PUSHTILE(tp, (TileType)0, BloatStack);
|
||||
}
|
||||
|
||||
/* Clear self */
|
||||
TiSetClient(tile, CIF_UNPROCESSED);
|
||||
// TiSetClient(tile, CIF_UNPROCESSED);
|
||||
|
||||
/* NOTE: Tiles must be cleared after the bloat-all function has
|
||||
* completed. However, for bloat-all with a limiting distance,
|
||||
|
|
@ -4458,14 +4460,16 @@ bridgeErase(
|
|||
maskBits = DBPlaneTypes[i];
|
||||
TTMaskAndMask(&maskBits, &brlims->co_paintMask);
|
||||
if (!TTMaskEqual(&maskBits, &DBZeroTypeBits))
|
||||
if (DBSrPaintArea((Tile *) NULL, brlims->def->cd_planes[i], area, &brlims->co_paintMask, cifPaintFunc, CIFEraseTable))
|
||||
if (DBSrPaintArea((Tile *) NULL, brlims->def->cd_planes[i],
|
||||
area, &brlims->co_paintMask, cifPaintFunc, CIFEraseTable))
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (t = 0; t < TT_MAXTYPES; t++, temps++)
|
||||
{
|
||||
if (TTMaskHasType(&brlims->co_cifMask, t))
|
||||
if (DBSrPaintArea((Tile *) NULL, *temps, area, &CIFSolidBits, cifPaintFunc, CIFEraseTable))
|
||||
if (DBSrPaintArea((Tile *) NULL, *temps, area, &CIFSolidBits,
|
||||
cifPaintFunc, CIFEraseTable))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -4766,6 +4770,106 @@ cifBridgeLimFunc2(
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifNotSquareFunc --
|
||||
*
|
||||
* Process each tile and remove those which are square and not
|
||||
* connected to any other tile of the same type. This operator aids
|
||||
* in the detection of bar contacts to distinguish them from regular
|
||||
* (square) contact cuts. Because of the special nature of the
|
||||
* operator, only the negative-sense operator "not-square" is
|
||||
* implemented, as the positive-sense operator is not especially
|
||||
* useful (and can be implemented if needed with "not-square" and
|
||||
* "and-not").
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Modifies the CIF planes.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifNotSquareFunc(
|
||||
Tile *tile,
|
||||
TileType dinfo,
|
||||
ClientData clientData) /* (unused) */
|
||||
{
|
||||
Tile *tp;
|
||||
TileType ttype;
|
||||
Rect area;
|
||||
int width, height;
|
||||
bool isolated = TRUE;
|
||||
|
||||
if (IsSplit(tile)) return 0; /* Non-Manhattan tiles are never square */
|
||||
ttype = TiGetType(tile);
|
||||
if (ttype == TT_SPACE) return 0; /* Don't handle space tiles */
|
||||
|
||||
/* Search all four sides of the tile. Tiles are only considered square
|
||||
* for the purposes of this operator if they are also unconnected to any
|
||||
* other tile.
|
||||
*/
|
||||
|
||||
/* Top */
|
||||
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
||||
if (TiGetBottomType(tp) == ttype)
|
||||
{
|
||||
isolated = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Left */
|
||||
if (isolated)
|
||||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
||||
if (TiGetBottomType(tp) == ttype)
|
||||
{
|
||||
isolated = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Bottom */
|
||||
if (isolated)
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
||||
if (TiGetBottomType(tp) == ttype)
|
||||
{
|
||||
isolated = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Right */
|
||||
if (isolated)
|
||||
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
||||
if (TiGetBottomType(tp) == ttype)
|
||||
{
|
||||
isolated = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
TiToRect(tile, &area);
|
||||
|
||||
if (isolated)
|
||||
{
|
||||
width = area.r_xtop - area.r_xbot;
|
||||
height = area.r_ytop - area.r_ybot;
|
||||
if (width == height) return 0; /* Square and isolated */
|
||||
}
|
||||
|
||||
area.r_xbot *= cifScale;
|
||||
area.r_ybot *= cifScale;
|
||||
area.r_xtop *= cifScale;
|
||||
area.r_ytop *= cifScale;
|
||||
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||
|
||||
CIFTileOps += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -4779,6 +4883,7 @@ cifBridgeLimFunc2(
|
|||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Modifies the CIF planes.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -4940,6 +5045,47 @@ cifInteractingRegions(
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifCopyPropPlaneFunc --
|
||||
*
|
||||
* Copy the contents of a plane saved as a plane-type property into the
|
||||
* current CIF plane. The property plane is in magic internal
|
||||
* coordinates, so each tile needs to be scaled and redrawn into the
|
||||
* current CIF plane.
|
||||
*
|
||||
* Results:
|
||||
* Zero to keep the search going
|
||||
*
|
||||
* Side effects:
|
||||
* Copies translated geometry into the target plane.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifCopyPropPlaneFunc(Tile *tile,
|
||||
TileType dinfo,
|
||||
Plane *curPlane)
|
||||
{
|
||||
Rect bbox;
|
||||
|
||||
TiToRect(tile, &bbox);
|
||||
|
||||
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
|
||||
|
||||
bbox.r_xbot *= cifScale;
|
||||
bbox.r_ybot *= cifScale;
|
||||
bbox.r_xtop *= cifScale;
|
||||
bbox.r_ytop *= cifScale;
|
||||
|
||||
cifScale = 1;
|
||||
DBNMPaintPlane(curPlane, CIF_SOLIDTYPE, &bbox,
|
||||
CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -4991,13 +5137,15 @@ CIFGenLayer(
|
|||
CIFSquaresInfo csi;
|
||||
SearchContext scx;
|
||||
TileType ttype;
|
||||
char *netname;
|
||||
char *netname, *text;
|
||||
Label *label;
|
||||
BloatStruct bls;
|
||||
BridgeStruct brs;
|
||||
BridgeLimStruct brlims;
|
||||
BridgeData *bridge;
|
||||
BloatData *bloats;
|
||||
BloatData *bloats, locbloat;
|
||||
bool hstop = FALSE;
|
||||
PropertyRecord *proprec;
|
||||
char *propvalue;
|
||||
bool found;
|
||||
|
||||
|
|
@ -5395,7 +5543,6 @@ CIFGenLayer(
|
|||
nextPlane = temp;
|
||||
break;
|
||||
|
||||
|
||||
case CIFOP_MAXRECT:
|
||||
cifPlane = curPlane;
|
||||
|
||||
|
|
@ -5418,6 +5565,19 @@ CIFGenLayer(
|
|||
nextPlane = temp;
|
||||
break;
|
||||
|
||||
case CIFOP_NOTSQUARE:
|
||||
DBClearPaintPlane(nextPlane);
|
||||
cifPlane = nextPlane;
|
||||
cifScale = 1;
|
||||
DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
|
||||
&CIFSolidBits, cifNotSquareFunc,
|
||||
(ClientData)NULL);
|
||||
|
||||
temp = curPlane;
|
||||
curPlane = nextPlane;
|
||||
nextPlane = temp;
|
||||
break;
|
||||
|
||||
case CIFOP_NET:
|
||||
if (hier)
|
||||
{
|
||||
|
|
@ -5443,6 +5603,105 @@ CIFGenLayer(
|
|||
}
|
||||
break;
|
||||
|
||||
case CIFOP_TAGGED:
|
||||
if (hier)
|
||||
{
|
||||
hstop = TRUE; /* Stop hierarchical processing */
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find all relevant labels by text matching and then continue
|
||||
* like CIFOP_BLOATALL. CIFOP_BLOATALL uses a BloatData record
|
||||
* which is not part of CIFOP_TAGGED. Create a BloatData record
|
||||
* on the fly for each tagged area based on type, and swap it for
|
||||
* the text, so that cifBloatAllFunc believes this is actually a
|
||||
* CIFOP_BLOATALL operation. Note that we don't actually care
|
||||
* what layer the label is attached to (lab_type). We are looking
|
||||
* for labels whose lab_rect values overlap the types that are given
|
||||
* in the rule.
|
||||
*/
|
||||
|
||||
cifPlane = curPlane;
|
||||
bls.op = op;
|
||||
bls.def = cellDef;
|
||||
bls.temps = temps;
|
||||
|
||||
text = (char *)op->co_client;
|
||||
|
||||
bloats = &locbloat;
|
||||
if (!TTMaskIsZero(&op->co_cifMask))
|
||||
{
|
||||
bloats->bl_plane = -1;
|
||||
for (ttype = 0; ttype < TT_MAXTYPES; ttype++)
|
||||
{
|
||||
if (TTMaskHasType(&op->co_cifMask, ttype))
|
||||
bloats->bl_distance[ttype] = 1;
|
||||
else
|
||||
bloats->bl_distance[ttype] = 0;
|
||||
}
|
||||
}
|
||||
else if (!TTMaskIsZero(&op->co_paintMask))
|
||||
{
|
||||
int plane, pmask;
|
||||
pmask = DBTechTypesToPlanes(&op->co_paintMask);
|
||||
for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
|
||||
if (PlaneMaskHasPlane(pmask, plane))
|
||||
break;
|
||||
bloats->bl_plane = plane;
|
||||
for (ttype = 0; ttype < TT_MAXTYPES; ttype++)
|
||||
{
|
||||
if (TTMaskHasType(&op->co_paintMask, ttype))
|
||||
bloats->bl_distance[ttype] = 1;
|
||||
else
|
||||
bloats->bl_distance[ttype] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Replace the client data with the bloat record */
|
||||
op->co_client = (ClientData)bloats;
|
||||
|
||||
if (bloats->bl_plane < 0)
|
||||
{
|
||||
/* bl_plane == -1 indicates bloating into a CIF templayer, */
|
||||
/* so the only connecting type should be CIF_SOLIDTYPE. */
|
||||
TTMaskSetOnlyType(&bls.connect, CIF_SOLIDTYPE);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
TTMaskZero(&bls.connect);
|
||||
for (i = 0; i < TT_MAXTYPES; i++)
|
||||
if (bloats->bl_distance[i] != 0)
|
||||
TTMaskSetType(&bls.connect, i);
|
||||
}
|
||||
|
||||
for (label = cellDef->cd_labels; label; label = label->lab_next)
|
||||
if (!strcmp(label->lab_text, text))
|
||||
cifSrTiles(op, &label->lab_rect, cellDef, temps,
|
||||
cifBloatAllFunc, (ClientData)&bls);
|
||||
|
||||
/* Reset marked tiles */
|
||||
|
||||
if (bloats->bl_plane < 0) /* Bloat types are CIF types */
|
||||
{
|
||||
bls.temps = temps;
|
||||
for (ttype = 0; ttype < TT_MAXTYPES; ttype++, bls.temps++)
|
||||
if (bloats->bl_distance[ttype] > 0)
|
||||
(void) DBSrPaintArea((Tile *)NULL, *bls.temps, &TiPlaneRect,
|
||||
&CIFSolidBits, cifProcessResetFunc,
|
||||
(ClientData)NULL);
|
||||
}
|
||||
else
|
||||
DBSrPaintArea((Tile *)NULL, cellDef->cd_planes[bloats->bl_plane],
|
||||
&TiPlaneRect, &bls.connect, cifProcessResetFunc,
|
||||
(ClientData)NULL);
|
||||
|
||||
/* Replace the client data */
|
||||
op->co_client = (ClientData)text;
|
||||
|
||||
break;
|
||||
|
||||
case CIFOP_BOUNDARY:
|
||||
if (hier)
|
||||
{
|
||||
|
|
@ -5454,10 +5713,17 @@ CIFGenLayer(
|
|||
|
||||
if (origDef && (origDef->cd_flags & CDFIXEDBBOX))
|
||||
{
|
||||
propvalue = (char *)DBPropGet(origDef, "FIXED_BBOX", &found);
|
||||
proprec = DBPropGet(origDef, "FIXED_BBOX", &found);
|
||||
if (!found) break;
|
||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
||||
&bbox.r_xtop, &bbox.r_ytop) != 4) break;
|
||||
|
||||
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||
(proprec->prop_len == 4))
|
||||
{
|
||||
bbox.r_xbot = proprec->prop_value.prop_integer[0];
|
||||
bbox.r_ybot = proprec->prop_value.prop_integer[1];
|
||||
bbox.r_xtop = proprec->prop_value.prop_integer[2];
|
||||
bbox.r_ytop = proprec->prop_value.prop_integer[3];
|
||||
}
|
||||
|
||||
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
|
||||
bbox.r_xbot *= cifScale;
|
||||
|
|
@ -5519,46 +5785,22 @@ CIFGenLayer(
|
|||
|
||||
case CIFOP_MASKHINTS:
|
||||
{
|
||||
int j, numfound;
|
||||
int n;
|
||||
char propname[512];
|
||||
char *propptr;
|
||||
char *layername = (char *)op->co_client;
|
||||
Tile *t;
|
||||
|
||||
sprintf(propname, "MASKHINTS_%s", layername);
|
||||
snprintf(propname, 512, "MASKHINTS_%s", layername);
|
||||
|
||||
propvalue = (char *)DBPropGet(cellDef, propname, &found);
|
||||
if (cellDef == (CellDef *)NULL) break;
|
||||
proprec = DBPropGet(cellDef, propname, &found);
|
||||
if (!found) break; /* No mask hints available */
|
||||
propptr = propvalue;
|
||||
while (*propptr)
|
||||
{
|
||||
numfound = sscanf(propptr, "%d %d %d %d",
|
||||
&bbox.r_xbot, &bbox.r_ybot,
|
||||
&bbox.r_xtop, &bbox.r_ytop);
|
||||
|
||||
if (numfound != 4)
|
||||
{
|
||||
/* To do: Allow keyword "rect", "tri", or "poly"
|
||||
* at the start of the list and parse accordingly.
|
||||
* For now, this only flags an error.
|
||||
*/
|
||||
TxError("%s: Cannot read rectangle values.\n", propname);
|
||||
break;
|
||||
}
|
||||
cifPlane = curPlane;
|
||||
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
|
||||
bbox.r_xbot *= cifScale;
|
||||
bbox.r_xtop *= cifScale;
|
||||
bbox.r_ybot *= cifScale;
|
||||
bbox.r_ytop *= cifScale;
|
||||
cifScale = 1;
|
||||
DBNMPaintPlane(curPlane, CIF_SOLIDTYPE, &bbox,
|
||||
CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
while (*propptr && isspace(*propptr)) propptr++;
|
||||
while (*propptr && !isspace(*propptr)) propptr++;
|
||||
}
|
||||
}
|
||||
ASSERT (proprec->prop_type == PROPERTY_TYPE_PLANE, "CIFGenLayer");
|
||||
t = PlaneGetHint(proprec->prop_value.prop_plane);
|
||||
DBSrPaintArea(t, proprec->prop_value.prop_plane,
|
||||
&TiPlaneRect, &CIFSolidBits,
|
||||
cifCopyPropPlaneFunc, (ClientData)curPlane);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
166
cif/CIFhier.c
166
cif/CIFhier.c
|
|
@ -209,52 +209,41 @@ typedef struct _maskHintsData
|
|||
{
|
||||
Transform *mh_trans;
|
||||
CellDef *mh_def;
|
||||
Plane *mh_plane;
|
||||
} MaskHintsData;
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifMaskHints --
|
||||
* cifCopyMaskHintFunc --
|
||||
*
|
||||
* Copy a mask hint into a target cell by adding it to the
|
||||
* property list of the target cell. If the target cell already
|
||||
* has the same mask hint key, then the mask hint value is
|
||||
* appended to the property in the target cell def.
|
||||
* Callback function used by cifFlatMaskHints. Transforms a tile
|
||||
* from the original plane and paints it into the target plane,
|
||||
* both of which are properties.
|
||||
*
|
||||
* Returns:
|
||||
* 0 to keep the search going.
|
||||
* Results:
|
||||
* Zero to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* Modifies properties of the target cell def.
|
||||
* Paints geometry into the target plane.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* DEPRECATED */
|
||||
int
|
||||
cifMaskHints(
|
||||
char *name,
|
||||
char *value,
|
||||
CellDef *targetDef)
|
||||
cifCopyMaskHintFunc(Tile *tile,
|
||||
TileType dinfo,
|
||||
ClientData cdata)
|
||||
{
|
||||
char *propvalue, *newval;
|
||||
bool propfound;
|
||||
MaskHintsData *mhd = (MaskHintsData *)cdata;
|
||||
Rect r, newr;
|
||||
|
||||
if (!strncmp(name, "MASKHINTS_", 10))
|
||||
{
|
||||
/* Check if name exists already in the flattened cell */
|
||||
propvalue = (char *)DBPropGet(targetDef, name, &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
/* Append value to the property */
|
||||
newval = mallocMagic(strlen(value) + strlen(propvalue) + 2);
|
||||
sprintf(newval, "%s %s", propvalue, value);
|
||||
}
|
||||
else
|
||||
newval = StrDup((char **)NULL, value);
|
||||
TiToRect(tile, &r);
|
||||
|
||||
/* Transform tile area to coordinates of mhd->mh_plane and paint */
|
||||
GeoTransRect(mhd->mh_trans, &r, &newr);
|
||||
DBPaintPlane(mhd->mh_plane, &newr, CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||
|
||||
DBPropPut(targetDef, name, newval);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -264,8 +253,8 @@ cifMaskHints(
|
|||
* cifFlatMaskHints --
|
||||
*
|
||||
* Copy a mask hint into a flattened cell by transforming it into the
|
||||
* coordinate system of the flattened cell, and adding it to the
|
||||
* property list of the flattened cell.
|
||||
* coordinate system of the flattened cell, and painting it into the
|
||||
* property plane of the flattened cell.
|
||||
*
|
||||
* Returns:
|
||||
* 0 to keep the search going.
|
||||
|
|
@ -279,67 +268,40 @@ cifMaskHints(
|
|||
int
|
||||
cifFlatMaskHints(
|
||||
char *name,
|
||||
char *value,
|
||||
PropertyRecord *proprec,
|
||||
MaskHintsData *mhd)
|
||||
{
|
||||
Rect r, newr;
|
||||
char *vptr, *newval, *lastval, *propvalue;
|
||||
bool propfound;
|
||||
int lastlen, numvals;
|
||||
int i, lastlen, numvals;
|
||||
PropertyRecord *newproprec, *oldproprec;
|
||||
Plane *plane;
|
||||
|
||||
if (!strncmp(name, "MASKHINTS_", 10))
|
||||
{
|
||||
newval = (char *)NULL;
|
||||
vptr = value;
|
||||
while (*vptr != '\0')
|
||||
{
|
||||
numvals = sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
|
||||
&r.r_xtop, &r.r_ytop);
|
||||
if (numvals == 4)
|
||||
{
|
||||
/* Transform rectangle to top level coordinates */
|
||||
GeoTransRect(mhd->mh_trans, &r, &newr);
|
||||
lastval = newval;
|
||||
lastlen = (lastval) ? strlen(lastval) : 0;
|
||||
newval = mallocMagic(40 + lastlen);
|
||||
if (lastval)
|
||||
strcpy(newval, lastval);
|
||||
else
|
||||
*newval = '\0';
|
||||
sprintf(newval + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
|
||||
newr.r_xbot, newr.r_ybot, newr.r_xtop, newr.r_ytop);
|
||||
if (lastval) freeMagic(lastval);
|
||||
|
||||
/* Parse through the four values and check if there's more */
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
TxError("MASKHINTS_%s: Expected 4 values, found only %d\n",
|
||||
name + 10, numvals);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if name exists already in the flattened cell */
|
||||
propvalue = (char *)DBPropGet(mhd->mh_def, name, &propfound);
|
||||
oldproprec = (PropertyRecord *)DBPropGet(mhd->mh_def, name, &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
/* Append newval to the property */
|
||||
lastval = newval;
|
||||
newval = mallocMagic(strlen(lastval) + strlen(propvalue) + 2);
|
||||
sprintf(newval, "%s %s", propvalue, lastval);
|
||||
freeMagic(lastval);
|
||||
ASSERT(oldproprec->prop_value.prop_type == PROPERTY_TYPE_PLANE,
|
||||
"cifFlatMaskHints");
|
||||
plane = oldproprec->prop_value.prop_plane;
|
||||
}
|
||||
DBPropPut(mhd->mh_def, name, newval);
|
||||
else
|
||||
{
|
||||
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||
newproprec->prop_len = 0; /* (unused) */
|
||||
newproprec->prop_type = PROPERTY_TYPE_PLANE;
|
||||
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||
newproprec->prop_value.prop_plane = plane;
|
||||
DBPropPut(mhd->mh_def, name, newproprec);
|
||||
}
|
||||
|
||||
mhd->mh_plane = plane;
|
||||
DBSrPaintArea((Tile *)NULL, proprec->prop_value.prop_plane,
|
||||
&TiPlaneRect, &CIFSolidBits,
|
||||
cifCopyMaskHintFunc, (ClientData)mhd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -350,9 +312,10 @@ cifFlatMaskHints(
|
|||
* CIFCopyMaskHints --
|
||||
*
|
||||
* Callback function to copy mask hints from one cell into another.
|
||||
* (Occasionally called as a standalone function, not as a callback.)
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
* Return 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* May modify properties in the target cell.
|
||||
|
|
@ -360,7 +323,7 @@ cifFlatMaskHints(
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
int
|
||||
CIFCopyMaskHints(
|
||||
SearchContext *scx,
|
||||
CellDef *targetDef)
|
||||
|
|
@ -370,38 +333,9 @@ CIFCopyMaskHints(
|
|||
CellDef *sourceDef = scx->scx_use->cu_def;
|
||||
mhd.mh_trans = &scx->scx_trans;
|
||||
mhd.mh_def = targetDef;
|
||||
mhd.mh_plane = (Plane *)NULL;
|
||||
|
||||
DBPropEnum(sourceDef, cifFlatMaskHints, &mhd);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifHierCopyMaskHints --
|
||||
*
|
||||
* Callback function to copy mask hints from a subcell into a flattened
|
||||
* cell, which is passed in the clientData record.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0 to keep the search alive.
|
||||
*
|
||||
* Side effects:
|
||||
* May modify properties in the flattened cell.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifHierCopyMaskHints(
|
||||
SearchContext *scx,
|
||||
ClientData clientData)
|
||||
{
|
||||
MaskHintsData mhd;
|
||||
|
||||
mhd.mh_trans = &scx->scx_trans;
|
||||
mhd.mh_def = (CellDef *)clientData;
|
||||
|
||||
DBPropEnum(scx->scx_use->cu_def, cifFlatMaskHints, &mhd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -526,7 +460,7 @@ cifHierCellFunc(
|
|||
|
||||
/* Flatten mask hints in the area of interest */
|
||||
CIFCopyMaskHints(scx, CIFComponentDef);
|
||||
DBTreeSrCells(&newscx, 0, cifHierCopyMaskHints,
|
||||
DBTreeSrCells(&newscx, 0, CIFCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
/* Set CIFErrorDef to NULL to ignore errors here... these will
|
||||
|
|
@ -854,7 +788,7 @@ CIFGenSubcells(
|
|||
cifHierCopyFunc, (ClientData) CIFTotalDef);
|
||||
/* Flatten mask hints in the area of interest */
|
||||
CIFCopyMaskHints(&scx, CIFTotalDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||
(ClientData)CIFTotalDef);
|
||||
|
||||
CIFErrorDef = def;
|
||||
|
|
@ -1032,14 +966,14 @@ cifHierElementFunc(
|
|||
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFTotalDef);
|
||||
CIFCopyMaskHints(&scx, CIFTotalDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||
(ClientData)CIFTotalDef);
|
||||
|
||||
DBCellClearDef(CIFComponentDef);
|
||||
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
CIFErrorDef = (CellDef *) NULL;
|
||||
|
|
|
|||
|
|
@ -145,6 +145,8 @@ typedef struct cifop
|
|||
* CIFOP_BRIDGE - Added 6/11/20---Bridge across catecorner gaps
|
||||
* CIFOP_BRIDGELIM - Added 27/07/20---Bridge across catecorner gaps, but with limiting layers
|
||||
* CIFOP_MASKHINTS - Added 12/14/20---Add geometry from cell properties, if any.
|
||||
* CIFOP_NOTSQUARE - Added 2/26/26---Keep only geometry which is not square.
|
||||
* CIFOP_TAGGED - Added 3/11/26---Find geometry attached to the given text label
|
||||
*/
|
||||
|
||||
#define CIFOP_AND 1
|
||||
|
|
@ -172,6 +174,8 @@ typedef struct cifop
|
|||
#define CIFOP_BRIDGE 23
|
||||
#define CIFOP_BRIDGELIM 24
|
||||
#define CIFOP_MASKHINTS 25
|
||||
#define CIFOP_NOTSQUARE 26
|
||||
#define CIFOP_TAGGED 27
|
||||
|
||||
/* Definitions of bit fields used in the value of co_client for CIFOP_INTERACT */
|
||||
#define CIFOP_INT_NOT 0x1 /* Inverted sense (not interacting) */
|
||||
|
|
@ -336,9 +340,8 @@ extern Plane *CIFGenLayer(CIFOp *op, const Rect *area, CellDef *cellDef, CellDef
|
|||
bool hier, ClientData clientdata);
|
||||
extern void CIFInitCells(void);
|
||||
extern int cifHierCopyFunc(Tile *tile, TileType dinfo, TreeContext *cxp);
|
||||
extern int cifHierCopyMaskHints(SearchContext *scx, ClientData clientData);
|
||||
extern void CIFLoadStyle(char *stylename);
|
||||
extern void CIFCopyMaskHints(SearchContext *scx, CellDef *targetDef);
|
||||
extern int CIFCopyMaskHints(SearchContext *scx, CellDef *targetDef);
|
||||
|
||||
/* C99 compat */
|
||||
extern void CIFCoverageLayer(CellDef *rootDef, Rect *area, char *layer, bool dolist);
|
||||
|
|
|
|||
189
cif/CIFrdcl.c
189
cif/CIFrdcl.c
|
|
@ -613,7 +613,7 @@ CIFPaintCurrent(
|
|||
CIFOp *op;
|
||||
|
||||
plane = CIFGenLayer(cifCurReadStyle->crs_layers[i]->crl_ops,
|
||||
&TiPlaneRect, (CellDef *)NULL, (CellDef *)NULL,
|
||||
&TiPlaneRect, cifReadCellDef, cifReadCellDef,
|
||||
cifCurReadPlanes, FALSE, (ClientData)NULL);
|
||||
|
||||
/* Generate a paint/erase table, then paint from the CIF
|
||||
|
|
@ -688,6 +688,8 @@ CIFPaintCurrent(
|
|||
}
|
||||
else if (op == NULL)
|
||||
{
|
||||
LinkedRect *lrec = NULL, *lsrch;
|
||||
|
||||
/* Handle boundary layer */
|
||||
|
||||
op = cifCurReadStyle->crs_layers[i]->crl_ops;
|
||||
|
|
@ -702,6 +704,102 @@ CIFPaintCurrent(
|
|||
(ClientData)NULL) == 1))
|
||||
DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
|
||||
&CIFSolidBits, cifMakeBoundaryFunc, INT2CD(filetype));
|
||||
|
||||
/* Handle mask-hints input operator */
|
||||
|
||||
op = cifCurReadStyle->crs_layers[i]->crl_ops;
|
||||
while (op)
|
||||
{
|
||||
if (op->co_opcode == CIFOP_MASKHINTS) break;
|
||||
op = op->co_next;
|
||||
}
|
||||
|
||||
if (op && (DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
|
||||
&DBAllButSpaceBits, cifCheckPaintFunc,
|
||||
(ClientData)NULL) == 1))
|
||||
{
|
||||
/* (To do: remove the linked Rects and paint directly
|
||||
* into the plane in cifMaskHintFunc())
|
||||
*/
|
||||
DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
|
||||
&CIFSolidBits, cifMaskHintFunc,
|
||||
(ClientData)&lrec);
|
||||
|
||||
if (lrec != NULL)
|
||||
{
|
||||
PropertyRecord *proprec, *proporig;
|
||||
char *propname, *layername;
|
||||
int proplen, i, savescale;
|
||||
bool origfound = FALSE;
|
||||
Plane *plane;
|
||||
|
||||
layername = (char *)op->co_client;
|
||||
propname = (char *)mallocMagic(11 + strlen(layername));
|
||||
sprintf(propname, "MASKHINTS_%s", layername);
|
||||
|
||||
/* If there is already a mask hint plane for this layer,
|
||||
* then add to it; otherwise, create a new plane.
|
||||
*/
|
||||
proprec = DBPropGet(cifReadCellDef, layername, &origfound);
|
||||
if (origfound)
|
||||
plane = proprec->prop_value.prop_plane;
|
||||
else
|
||||
{
|
||||
proprec = (PropertyRecord *)mallocMagic(
|
||||
sizeof(PropertyRecord));
|
||||
proprec->prop_type = PROPERTY_TYPE_PLANE;
|
||||
proprec->prop_len = 0; /* (unused) */
|
||||
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||
proprec->prop_value.prop_plane = plane;
|
||||
DBPropPut(cifReadCellDef, propname, proprec);
|
||||
}
|
||||
|
||||
while (lrec != NULL)
|
||||
{
|
||||
lrec->r_r.r_xtop =
|
||||
CIFScaleCoord(lrec->r_r.r_xtop, COORD_EXACT);
|
||||
savescale = cifCurReadStyle->crs_scaleFactor;
|
||||
lrec->r_r.r_ytop =
|
||||
CIFScaleCoord(lrec->r_r.r_ytop, COORD_EXACT);
|
||||
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
||||
{
|
||||
lrec->r_r.r_xtop *=
|
||||
(savescale / cifCurReadStyle->crs_scaleFactor);
|
||||
savescale = cifCurReadStyle->crs_scaleFactor;
|
||||
}
|
||||
lrec->r_r.r_xbot =
|
||||
CIFScaleCoord(lrec->r_r.r_xbot, COORD_EXACT);
|
||||
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
||||
{
|
||||
lrec->r_r.r_xtop *=
|
||||
(savescale / cifCurReadStyle->crs_scaleFactor);
|
||||
lrec->r_r.r_ytop *=
|
||||
(savescale / cifCurReadStyle->crs_scaleFactor);
|
||||
savescale = cifCurReadStyle->crs_scaleFactor;
|
||||
}
|
||||
lrec->r_r.r_ybot =
|
||||
CIFScaleCoord(lrec->r_r.r_ybot, COORD_EXACT);
|
||||
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
||||
{
|
||||
lrec->r_r.r_xtop *=
|
||||
(savescale / cifCurReadStyle->crs_scaleFactor);
|
||||
lrec->r_r.r_ytop *=
|
||||
(savescale / cifCurReadStyle->crs_scaleFactor);
|
||||
lrec->r_r.r_xbot *=
|
||||
(savescale / cifCurReadStyle->crs_scaleFactor);
|
||||
}
|
||||
|
||||
DBPaintPlane(plane, &lrec->r_r, CIFPaintTable,
|
||||
(PaintUndoInfo *)NULL);
|
||||
|
||||
free_magic1_t mm1 = freeMagic1_init();
|
||||
freeMagic1(&mm1, lrec);
|
||||
lrec = lrec->r_next;
|
||||
freeMagic1_end(&mm1);
|
||||
}
|
||||
freeMagic(propname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Swap planes */
|
||||
|
|
@ -790,9 +888,7 @@ CIFPaintCurrent(
|
|||
|
||||
for (i = 0; i < cifNReadLayers; i++)
|
||||
{
|
||||
LinkedRect *lrec = NULL;
|
||||
char *propstr = NULL;
|
||||
char locstr[512];
|
||||
LinkedRect *lrec = NULL, *lsrch;
|
||||
Plane *tempp;
|
||||
|
||||
if (!TTMaskHasType(CalmaMaskHints, i)) continue;
|
||||
|
|
@ -817,53 +913,55 @@ CIFPaintCurrent(
|
|||
(CellDef *)NULL, CIFPlanes, FALSE, (ClientData)NULL);
|
||||
|
||||
/* Scan the resulting plane and generate linked Rect structures for
|
||||
* each shape found.
|
||||
* each shape found. (To do: Remove the linked Rects and paint
|
||||
* directly into the plane in cifMaskHintFunc(), which is more
|
||||
* efficient but not hugely so.)
|
||||
*/
|
||||
DBSrPaintArea((Tile *)NULL, presult, &TiPlaneRect, &CIFSolidBits,
|
||||
cifMaskHintFunc, (ClientData)&lrec);
|
||||
|
||||
if (lrec != NULL)
|
||||
{
|
||||
PropertyRecord *proprec;
|
||||
bool propfound;
|
||||
char *propname;
|
||||
Plane *plane;
|
||||
|
||||
propname = (char *)mallocMagic(11 + strlen(cifReadLayers[i]));
|
||||
sprintf(propname, "MASKHINTS_%s", cifReadLayers[i]);
|
||||
|
||||
propstr = (char *)NULL;
|
||||
|
||||
/* Turn all linked Rects into a mask-hints property in the
|
||||
* target cell.
|
||||
/* Paint all linked Rects into a mask-hints property plane
|
||||
* in the target cell.
|
||||
*/
|
||||
|
||||
proprec = DBPropGet(cifReadCellDef, propname, &propfound);
|
||||
if (!propfound)
|
||||
{
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||
proprec->prop_type = PROPERTY_TYPE_PLANE;
|
||||
proprec->prop_len = 0; /* (unused) */
|
||||
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||
proprec->prop_value.prop_plane = plane;
|
||||
DBPropPut(cifReadCellDef, propname, proprec);
|
||||
}
|
||||
else
|
||||
plane = proprec->prop_value.prop_plane;
|
||||
|
||||
while (lrec != NULL)
|
||||
{
|
||||
char *newstr;
|
||||
sprintf(locstr, "%d %d %d %d",
|
||||
lrec->r_r.r_xbot / CIFCurStyle->cs_scaleFactor,
|
||||
lrec->r_r.r_ybot / CIFCurStyle->cs_scaleFactor,
|
||||
lrec->r_r.r_xtop / CIFCurStyle->cs_scaleFactor,
|
||||
lrec->r_r.r_ytop / CIFCurStyle->cs_scaleFactor);
|
||||
if (propstr == NULL)
|
||||
{
|
||||
newstr = (char *)mallocMagic(strlen(locstr) + 1);
|
||||
sprintf(newstr, "%s", locstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
newstr = (char *)mallocMagic(strlen(locstr)
|
||||
+ strlen(propstr) + 2);
|
||||
sprintf(newstr, "%s %s", propstr, locstr);
|
||||
freeMagic(propstr);
|
||||
}
|
||||
propstr = newstr;
|
||||
lrec->r_r.r_xbot /= CIFCurStyle->cs_scaleFactor;
|
||||
lrec->r_r.r_ybot /= CIFCurStyle->cs_scaleFactor;
|
||||
lrec->r_r.r_xtop /= CIFCurStyle->cs_scaleFactor;
|
||||
lrec->r_r.r_ytop /= CIFCurStyle->cs_scaleFactor;
|
||||
|
||||
DBPaintPlane(plane, &lrec->r_r, CIFPaintTable,
|
||||
(PaintUndoInfo *)NULL);
|
||||
|
||||
free_magic1_t mm1 = freeMagic1_init();
|
||||
freeMagic1(&mm1, lrec);
|
||||
lrec = lrec->r_next;
|
||||
freeMagic1_end(&mm1);
|
||||
}
|
||||
/* NOTE: propstr is transferred to the CellDef and should
|
||||
* not be free'd here.
|
||||
*/
|
||||
DBPropPut(cifReadCellDef, propname, propstr);
|
||||
freeMagic(propname);
|
||||
}
|
||||
|
||||
|
|
@ -902,6 +1000,7 @@ cifMakeBoundaryFunc(
|
|||
/* If there are multiple rectangles defined with the boundary */
|
||||
/* layer, then the last one defines the FIXED_BBOX property. */
|
||||
|
||||
PropertyRecord *proprec;
|
||||
Rect area;
|
||||
char propertyvalue[128], *storedvalue;
|
||||
int savescale;
|
||||
|
|
@ -933,19 +1032,24 @@ cifMakeBoundaryFunc(
|
|||
|
||||
if (cifReadCellDef->cd_flags & CDFIXEDBBOX)
|
||||
{
|
||||
char *propvalue;
|
||||
PropertyRecord *proprec;
|
||||
bool found;
|
||||
|
||||
/* Only flag a warning if the redefined boundary was */
|
||||
/* different from the original. */
|
||||
|
||||
propvalue = (char *)DBPropGet(cifReadCellDef, "FIXED_BBOX", &found);
|
||||
proprec = DBPropGet(cifReadCellDef, "FIXED_BBOX", &found);
|
||||
if (found)
|
||||
{
|
||||
Rect bbox;
|
||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
||||
&bbox.r_xtop, &bbox.r_ytop) == 4)
|
||||
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||
(proprec->prop_len == 4))
|
||||
{
|
||||
bbox.r_xbot = proprec->prop_value.prop_integer[0];
|
||||
bbox.r_ybot = proprec->prop_value.prop_integer[1];
|
||||
bbox.r_xtop = proprec->prop_value.prop_integer[2];
|
||||
bbox.r_ytop = proprec->prop_value.prop_integer[3];
|
||||
|
||||
if ((bbox.r_xbot != area.r_xbot) ||
|
||||
(bbox.r_ybot != area.r_ybot) ||
|
||||
(bbox.r_xtop != area.r_xtop) ||
|
||||
|
|
@ -962,10 +1066,15 @@ cifMakeBoundaryFunc(
|
|||
}
|
||||
}
|
||||
|
||||
sprintf(propertyvalue, "%d %d %d %d",
|
||||
area.r_xbot, area.r_ybot, area.r_xtop, area.r_ytop);
|
||||
storedvalue = StrDup((char **)NULL, propertyvalue);
|
||||
DBPropPut(cifReadCellDef, "FIXED_BBOX", storedvalue);
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) + 2 * sizeof(int));
|
||||
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||
proprec->prop_len = 4;
|
||||
proprec->prop_value.prop_integer[0] = area.r_xbot;
|
||||
proprec->prop_value.prop_integer[1] = area.r_ybot;
|
||||
proprec->prop_value.prop_integer[2] = area.r_xtop;
|
||||
proprec->prop_value.prop_integer[3] = area.r_ytop;
|
||||
|
||||
DBPropPut(cifReadCellDef, "FIXED_BBOX", proprec);
|
||||
cifReadCellDef->cd_flags |= CDFIXEDBBOX;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,40 +244,61 @@ CIFPropRecordPath(
|
|||
{
|
||||
extern float CIFGetOutputScale(int convert);
|
||||
CIFPath *pathp;
|
||||
char *pathstr, *sptr;
|
||||
int components;
|
||||
float x, y, oscale, mult;
|
||||
char *namestr = NULL;
|
||||
int components, i, x, y, mult, pathnum;
|
||||
PropertyRecord *proprec;
|
||||
bool propfound;
|
||||
|
||||
oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */
|
||||
if (oscale == 0.0) oscale = 1.0;
|
||||
mult = (iswire == TRUE) ? 0.5 : 1.0;
|
||||
/* If "name" is a property, then append a suffix to it to ensure uniqueness */
|
||||
DBPropGet(def, propname, &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
pathnum = 0;
|
||||
namestr = mallocMagic(strlen(propname) + 10);
|
||||
while (propfound)
|
||||
{
|
||||
sprintf(namestr, "%s_%d", propname, pathnum);
|
||||
DBPropGet(def, namestr, &propfound);
|
||||
pathnum++;
|
||||
}
|
||||
}
|
||||
|
||||
pathp = pathheadp;
|
||||
components = 0;
|
||||
mult = (iswire == TRUE) ? 1 : 0;
|
||||
|
||||
/* Count the number of components in the path */
|
||||
pathp = pathheadp;
|
||||
components = 0;
|
||||
while (pathp != NULL)
|
||||
{
|
||||
pathp = pathp->cifp_next;
|
||||
components++;
|
||||
pathp = pathp->cifp_next;
|
||||
}
|
||||
/* Allocate enough space to hold 2 * N points at "infinity" */
|
||||
pathstr = (char *)mallocMagic(components * 40);
|
||||
/* Allocate enough space to hold 2 * N points. */
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
((components - 1) * 2) * sizeof(int));
|
||||
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||
proprec->prop_len = components * 2;
|
||||
|
||||
pathp = pathheadp;
|
||||
sptr = pathstr;
|
||||
i = 0;
|
||||
while (pathp != NULL)
|
||||
{
|
||||
x = (float)pathp->cifp_x * oscale * mult;
|
||||
y = (float)pathp->cifp_y * oscale * mult;
|
||||
sprintf(sptr, "%.3f %.3f ", x, y);
|
||||
sptr = sptr + strlen(sptr);
|
||||
x = pathp->cifp_x >> mult;
|
||||
y = pathp->cifp_y >> mult;
|
||||
|
||||
proprec->prop_value.prop_integer[i] = x;
|
||||
proprec->prop_value.prop_integer[i + 1] = y;
|
||||
|
||||
i += 2;
|
||||
pathp = pathp->cifp_next;
|
||||
}
|
||||
|
||||
/* Reallocate pathstr to be no larger than needed to hold the path contents */
|
||||
StrDup(&pathstr, pathstr);
|
||||
DBPropPut(def, propname, (ClientData)pathstr);
|
||||
if (namestr)
|
||||
{
|
||||
DBPropPut(def, namestr, proprec);
|
||||
freeMagic(namestr);
|
||||
}
|
||||
else
|
||||
DBPropPut(def, propname, proprec);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -324,14 +324,19 @@ cifNewReadStyle(void)
|
|||
{
|
||||
/* Destroy old style and free all memory allocated to it */
|
||||
|
||||
for (i=0; i<MAXCIFRLAYERS; i+=1)
|
||||
for (i = 0; i < MAXCIFRLAYERS; i++)
|
||||
{
|
||||
layer = cifCurReadStyle->crs_layers[i];
|
||||
if (layer != NULL)
|
||||
{
|
||||
free_magic1_t mm1 = freeMagic1_init();
|
||||
for (op = layer->crl_ops; op != NULL; op = op->co_next)
|
||||
{
|
||||
if (op->co_opcode == CIFOP_MASKHINTS ||
|
||||
op->co_opcode == CIFOP_TAGGED)
|
||||
freeMagic((char *)op->co_client);
|
||||
freeMagic1(&mm1, (char *)op);
|
||||
}
|
||||
freeMagic1_end(&mm1);
|
||||
freeMagic((char *)layer);
|
||||
}
|
||||
|
|
@ -990,6 +995,12 @@ CIFReadTechLine(
|
|||
newOp->co_opcode = CIFOP_COPYUP;
|
||||
else if (strcmp(argv[0], "boundary") == 0)
|
||||
newOp->co_opcode = CIFOP_BOUNDARY;
|
||||
else if (strcmp(argv[0], "not-square") == 0)
|
||||
newOp->co_opcode = CIFOP_NOTSQUARE;
|
||||
else if (strcmp(argv[0], "mask-hints") == 0)
|
||||
newOp->co_opcode = CIFOP_MASKHINTS;
|
||||
else if (strcmp(argv[0], "tagged") == 0)
|
||||
newOp->co_opcode = CIFOP_TAGGED;
|
||||
else
|
||||
{
|
||||
TechError("Unknown statement \"%s\".\n", argv[0]);
|
||||
|
|
@ -1016,6 +1027,15 @@ CIFReadTechLine(
|
|||
goto errorReturn;
|
||||
}
|
||||
break;
|
||||
case CIFOP_MASKHINTS:
|
||||
if (argc != 2) goto wrongNumArgs;
|
||||
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
|
||||
break;
|
||||
case CIFOP_TAGGED:
|
||||
if (argc != 3) goto wrongNumArgs;
|
||||
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
|
||||
CIFParseReadLayers(argv[2], &newOp->co_cifMask, TRUE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Link the new CIFOp onto the list. */
|
||||
|
|
@ -1099,6 +1119,7 @@ CIFReadTechFinal(void)
|
|||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
CIFReadLoadStyle(
|
||||
char *stylename)
|
||||
|
|
|
|||
18
cif/CIFsee.c
18
cif/CIFsee.c
|
|
@ -166,9 +166,9 @@ CIFPaintLayer(
|
|||
scx.scx_use = CIFDummyUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
oldCount = DBWFeedbackCount;
|
||||
|
|
@ -287,9 +287,9 @@ CIFSeeLayer(
|
|||
scx.scx_use = CIFDummyUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
oldCount = DBWFeedbackCount;
|
||||
|
|
@ -459,9 +459,9 @@ CIFCoverageLayer(
|
|||
scx.scx_use = CIFDummyUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE,
|
||||
|
|
@ -504,10 +504,10 @@ CIFCoverageLayer(
|
|||
}
|
||||
else
|
||||
{
|
||||
TxPrintf("%s Area = %lld CIF units^2\n", doBox ? "Cursor Box" :
|
||||
TxPrintf("%s Area = %"DLONG_PREFIX"d CIF units^2\n", doBox ? "Cursor Box" :
|
||||
"Cell", btotal);
|
||||
TxPrintf("Layer Bounding Area = %lld CIF units^2\n", atotal);
|
||||
TxPrintf("Layer Total Area = %lld CIF units^2\n", cstats.coverage);
|
||||
TxPrintf("Layer Bounding Area = %"DLONG_PREFIX"d CIF units^2\n", atotal);
|
||||
TxPrintf("Layer Total Area = %"DLONG_PREFIX"d CIF units^2\n", cstats.coverage);
|
||||
TxPrintf("Coverage in %s = %1.1f%%\n", doBox ? "box" :
|
||||
"cell", 100.0 * fcover);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1107,6 +1107,8 @@ CIFTechLine(
|
|||
newOp->co_opcode = CIFOP_BBOX;
|
||||
else if (strcmp(argv[0], "net") == 0)
|
||||
newOp->co_opcode = CIFOP_NET;
|
||||
else if (strcmp(argv[0], "tagged") == 0)
|
||||
newOp->co_opcode = CIFOP_TAGGED;
|
||||
else if (strcmp(argv[0], "maxrect") == 0)
|
||||
newOp->co_opcode = CIFOP_MAXRECT;
|
||||
else if (strcmp(argv[0], "boundary") == 0)
|
||||
|
|
@ -1117,6 +1119,8 @@ CIFTechLine(
|
|||
newOp->co_opcode = CIFOP_CLOSE;
|
||||
else if (strcmp(argv[0], "orthogonal") == 0)
|
||||
newOp->co_opcode = CIFOP_MANHATTAN;
|
||||
else if (strcmp(argv[0], "not-square") == 0)
|
||||
newOp->co_opcode = CIFOP_NOTSQUARE;
|
||||
else if (strcmp(argv[0], "bridge") == 0)
|
||||
newOp->co_opcode = CIFOP_BRIDGE;
|
||||
else if (strcmp(argv[0], "bridge-lim") == 0)
|
||||
|
|
@ -1355,6 +1359,7 @@ bloatCheck:
|
|||
bloatDone: break;
|
||||
|
||||
case CIFOP_NET:
|
||||
case CIFOP_TAGGED:
|
||||
if (argc != 3) goto wrongNumArgs;
|
||||
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
|
||||
cifParseLayers(argv[2], CIFCurStyle, &newOp->co_paintMask,
|
||||
|
|
@ -1669,12 +1674,12 @@ cifComputeRadii(
|
|||
|
||||
for (op = layer->cl_ops; op != NULL; op = op->co_next)
|
||||
{
|
||||
/* BBOX, NET, and MASKHINTS operators should never be used */
|
||||
/* hierarchically so ignore any grow/shrink operators that */
|
||||
/* BBOX, NET, TAGGED, and MASKHINTS operators should never be */
|
||||
/* used hierarchically so ignore any grow/shrink operators that */
|
||||
/* come after them. */
|
||||
|
||||
if (op->co_opcode == CIFOP_BBOX || op->co_opcode == CIFOP_NET ||
|
||||
op->co_opcode == CIFOP_MASKHINTS)
|
||||
op->co_opcode == CIFOP_TAGGED || op->co_opcode == CIFOP_MASKHINTS)
|
||||
break;
|
||||
|
||||
/* If CIF layers are used, switch to the max of current
|
||||
|
|
@ -1986,8 +1991,8 @@ CIFTechFinal(void)
|
|||
/* Presence of op->co_opcode in CIFOP_OR indicates a copy */
|
||||
/* of the SquaresData pointer from a following operator. */
|
||||
/* CIFOP_BBOX and CIFOP_MAXRECT uses the co_client field */
|
||||
/* as a flag field, while CIFOP_NET and CIFOP_MASKHINTS */
|
||||
/* uses it for a string. */
|
||||
/* as a flag field, while CIFOP_NET, CIFOP_MASKHINTS, and */
|
||||
/* CIFOP_TAGGED use it for a string. */
|
||||
else
|
||||
{
|
||||
switch (op->co_opcode)
|
||||
|
|
@ -1999,6 +2004,7 @@ CIFTechFinal(void)
|
|||
case CIFOP_MAXRECT:
|
||||
case CIFOP_MANHATTAN:
|
||||
case CIFOP_NET:
|
||||
case CIFOP_TAGGED:
|
||||
break;
|
||||
case CIFOP_BRIDGELIM:
|
||||
case CIFOP_BRIDGE:
|
||||
|
|
@ -2534,6 +2540,7 @@ CIFTechOutputScale(
|
|||
case CIFOP_MAXRECT:
|
||||
case CIFOP_MANHATTAN:
|
||||
case CIFOP_NET:
|
||||
case CIFOP_TAGGED:
|
||||
case CIFOP_INTERACT:
|
||||
break;
|
||||
case CIFOP_BRIDGELIM:
|
||||
|
|
@ -2649,8 +2656,8 @@ CIFTechOutputScale(
|
|||
default:
|
||||
/* op->co_opcode in CIFOP_OR is a pointer copy, */
|
||||
/* in CIFOP_BBOX and CIFOP_MAXRECT is a flag, */
|
||||
/* and in CIFOP_NET and CIFOP_MASKHINTS is a */
|
||||
/* string. */
|
||||
/* and in CIFOP_NET, CIFOP_MASKHINTS, and */
|
||||
/* CIFOP_TAGGED is a string. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
150
commands/CmdAB.c
150
commands/CmdAB.c
|
|
@ -338,14 +338,17 @@ CmdArray(
|
|||
case ARRAY_WIDTH:
|
||||
if (locargc == 2)
|
||||
{
|
||||
char *xsepvalue;
|
||||
for (la = lahead; la != NULL; la = la->ar_next)
|
||||
{
|
||||
xsepvalue = DBWPrintValue(la->arrayInfo.ar_xsep,
|
||||
w, TRUE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
if (doList)
|
||||
{
|
||||
tobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewIntObj(la->arrayInfo.ar_xsep));
|
||||
Tcl_NewStringObj(xsepvalue, -1));
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
}
|
||||
else
|
||||
|
|
@ -355,7 +358,7 @@ CmdArray(
|
|||
TxPrintf("Cell use \"%s\":", la->cellUse->cu_id);
|
||||
else
|
||||
TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name);
|
||||
TxPrintf("x separation %d\n", la->arrayInfo.ar_xsep);
|
||||
TxPrintf("x separation %s\n", xsepvalue);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
}
|
||||
#endif
|
||||
|
|
@ -374,14 +377,17 @@ CmdArray(
|
|||
case ARRAY_HEIGHT:
|
||||
if (locargc == 2)
|
||||
{
|
||||
char *ysepvalue;
|
||||
for (la = lahead; la != NULL; la = la->ar_next)
|
||||
{
|
||||
ysepvalue = DBWPrintValue(la->arrayInfo.ar_ysep,
|
||||
w, FALSE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
if (doList)
|
||||
{
|
||||
tobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewIntObj(la->arrayInfo.ar_ysep));
|
||||
Tcl_NewStringObj(ysepvalue, -1));
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
}
|
||||
else
|
||||
|
|
@ -391,7 +397,7 @@ CmdArray(
|
|||
TxPrintf("Cell use \"%s\":", la->cellUse->cu_id);
|
||||
else
|
||||
TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name);
|
||||
TxPrintf("y separation %d\n", la->arrayInfo.ar_ysep);
|
||||
TxPrintf("y separation %s\n", ysepvalue);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
}
|
||||
#endif
|
||||
|
|
@ -410,16 +416,21 @@ CmdArray(
|
|||
case ARRAY_PITCH:
|
||||
if (locargc == 2)
|
||||
{
|
||||
char *xpitch, *ypitch;
|
||||
for (la = lahead; la != NULL; la = la->ar_next)
|
||||
{
|
||||
xpitch = DBWPrintValue(la->arrayInfo.ar_xsep,
|
||||
w, TRUE);
|
||||
ypitch = DBWPrintValue(la->arrayInfo.ar_ysep,
|
||||
w, FALSE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
if (doList)
|
||||
{
|
||||
tobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewIntObj(la->arrayInfo.ar_xsep));
|
||||
Tcl_NewStringObj(xpitch, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewIntObj(la->arrayInfo.ar_ysep));
|
||||
Tcl_NewStringObj(ypitch, -1));
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
}
|
||||
else
|
||||
|
|
@ -429,8 +440,8 @@ CmdArray(
|
|||
TxPrintf("Cell use \"%s\":", la->cellUse->cu_id);
|
||||
else
|
||||
TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name);
|
||||
TxPrintf("x separation %d ", la->arrayInfo.ar_xsep);
|
||||
TxPrintf("y separation %d\n", la->arrayInfo.ar_ysep);
|
||||
TxPrintf("x separation %s ", xpitch);
|
||||
TxPrintf("y separation %s\n", ypitch);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
}
|
||||
#endif
|
||||
|
|
@ -450,16 +461,21 @@ CmdArray(
|
|||
case ARRAY_POSITION:
|
||||
if (locargc == 2)
|
||||
{
|
||||
char *xpos, *ypos;
|
||||
for (la = lahead; la != NULL; la = la->ar_next)
|
||||
{
|
||||
xpos = DBWPrintValue(la->cellUse->cu_bbox.r_xbot,
|
||||
w, TRUE);
|
||||
ypos = DBWPrintValue(la->cellUse->cu_bbox.r_ybot,
|
||||
w, FALSE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
if (doList)
|
||||
{
|
||||
tobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewIntObj(la->cellUse->cu_bbox.r_xbot));
|
||||
Tcl_NewStringObj(xpos, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewIntObj(la->cellUse->cu_bbox.r_ybot));
|
||||
Tcl_NewStringObj(ypos, -1));
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
}
|
||||
else
|
||||
|
|
@ -469,8 +485,8 @@ CmdArray(
|
|||
TxPrintf("Cell use \"%s\":", la->cellUse->cu_id);
|
||||
else
|
||||
TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name);
|
||||
TxPrintf("x=%d ", la->cellUse->cu_bbox.r_xbot);
|
||||
TxPrintf("y=%d\n", la->cellUse->cu_bbox.r_ybot);
|
||||
TxPrintf("x=%s ", xpos);
|
||||
TxPrintf("y=%s\n", ypos);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
}
|
||||
#endif
|
||||
|
|
@ -763,8 +779,8 @@ CmdBox(
|
|||
break;
|
||||
case BOX_EXISTS:
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetResult(magicinterp, ToolGetBox(NULL, NULL) ? "1" : "0",
|
||||
NULL);
|
||||
Tcl_SetObjResult(magicinterp,
|
||||
Tcl_NewBooleanObj(ToolGetBox(NULL, NULL) ? TRUE : FALSE));
|
||||
#else
|
||||
TxPrintf("%s\n", ToolGetBox(NULL, NULL) ? "True" : "False");
|
||||
#endif
|
||||
|
|
@ -874,13 +890,16 @@ CmdBox(
|
|||
TxRebuildCommand(cmd);
|
||||
return;
|
||||
}
|
||||
else if (DBWSnapToGrid != DBW_SNAP_USER)
|
||||
else if (DBWUnits != DBW_UNITS_USER)
|
||||
{
|
||||
distancex = cmdParseCoord(w, cmd->tx_argv[3], TRUE, FALSE);
|
||||
distancey = distancex;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For user units, the distance may be different in the X and Y
|
||||
* directions for a given value.
|
||||
*/
|
||||
switch (direction)
|
||||
{
|
||||
case GEO_EAST: case GEO_WEST:
|
||||
|
|
@ -908,15 +927,14 @@ CmdBox(
|
|||
case BOX_WIDTH:
|
||||
if (argc == 2)
|
||||
{
|
||||
char *boxvalues;
|
||||
boxvalues = DBWPrintValue(boxptr->r_xtop - boxptr->r_xbot,
|
||||
w, TRUE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
char *boxvalues = (char *)Tcl_Alloc(50);
|
||||
sprintf(boxvalues, "%d",
|
||||
boxptr->r_xtop - boxptr->r_xbot);
|
||||
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(boxvalues, -1));
|
||||
#else
|
||||
TxPrintf("%s box width is %d\n",
|
||||
(refEdit) ? "Edit" : "Root",
|
||||
boxptr->r_xtop - boxptr->r_xbot);
|
||||
TxPrintf("%s box width is %s\n", (refEdit) ? "Edit" : "Root",
|
||||
boxvalues);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
|
@ -928,15 +946,14 @@ CmdBox(
|
|||
case BOX_HEIGHT:
|
||||
if (argc == 2)
|
||||
{
|
||||
char *boxvalues;
|
||||
boxvalues = DBWPrintValue(boxptr->r_ytop - boxptr->r_ybot,
|
||||
w, FALSE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
char *boxvalues = (char *)Tcl_Alloc(50);
|
||||
sprintf(boxvalues, "%d",
|
||||
boxptr->r_ytop - boxptr->r_ybot);
|
||||
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(boxvalues, -1));
|
||||
#else
|
||||
TxPrintf("%s box height is %d\n",
|
||||
(refEdit) ? "Edit" : "Root",
|
||||
boxptr->r_ytop - boxptr->r_ybot);
|
||||
TxPrintf("%s box height is %s\n", (refEdit) ? "Edit" : "Root",
|
||||
boxvalues);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
|
@ -949,16 +966,24 @@ CmdBox(
|
|||
if (argc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
char *boxvalues = (char *)Tcl_Alloc(50);
|
||||
sprintf(boxvalues, "%d %d",
|
||||
boxptr->r_xtop - boxptr->r_xbot,
|
||||
boxptr->r_ytop - boxptr->r_ybot);
|
||||
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
|
||||
Tcl_Obj *tobj;
|
||||
#endif
|
||||
char *boxvaluex, *boxvaluey;
|
||||
boxvaluex = DBWPrintValue(boxptr->r_xtop - boxptr->r_xbot,
|
||||
w, TRUE);
|
||||
boxvaluey = DBWPrintValue(boxptr->r_ytop - boxptr->r_ybot,
|
||||
w, FALSE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
tobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewStringObj(boxvaluex, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewStringObj(boxvaluey, -1));
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
#else
|
||||
TxPrintf("%s box size is %d x %d\n",
|
||||
TxPrintf("%s box size is %s x %s\n",
|
||||
(refEdit) ? "Edit" : "Root",
|
||||
boxptr->r_xtop - boxptr->r_xbot,
|
||||
boxptr->r_ytop - boxptr->r_ybot);
|
||||
boxvaluex, boxvaluey);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
|
@ -973,14 +998,22 @@ CmdBox(
|
|||
if (argc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
char *boxvalues = (char *)Tcl_Alloc(50);
|
||||
sprintf(boxvalues, "%d %d",
|
||||
boxptr->r_xbot, boxptr->r_ybot);
|
||||
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
|
||||
Tcl_Obj *tobj;
|
||||
#endif
|
||||
char *boxvaluex, *boxvaluey;
|
||||
boxvaluex = DBWPrintValue(boxptr->r_xbot, w, TRUE);
|
||||
boxvaluey = DBWPrintValue(boxptr->r_ybot, w, FALSE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
tobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewStringObj(boxvaluex, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewStringObj(boxvaluey, -1));
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
#else
|
||||
TxPrintf("%s box lower-left corner at (%d, %d)\n",
|
||||
TxPrintf("%s box lower-left corner at (%s, %s)\n",
|
||||
(refEdit) ? "Edit" : "Root",
|
||||
boxptr->r_xbot, boxptr->r_ybot);
|
||||
boxvaluex, boxvaluey);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
|
@ -1012,16 +1045,31 @@ CmdBox(
|
|||
if (argc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
char *boxvalues = (char *)Tcl_Alloc(50);
|
||||
sprintf(boxvalues, "%d %d %d %d",
|
||||
boxptr->r_xbot, boxptr->r_ybot,
|
||||
boxptr->r_xtop, boxptr->r_ytop);
|
||||
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
|
||||
Tcl_Obj *tobj;
|
||||
#endif
|
||||
char *boxvaluellx, *boxvaluelly;
|
||||
char *boxvalueurx, *boxvalueury;
|
||||
|
||||
boxvaluellx = DBWPrintValue(boxptr->r_xbot, w, TRUE);
|
||||
boxvaluelly = DBWPrintValue(boxptr->r_ybot, w, FALSE);
|
||||
boxvalueurx = DBWPrintValue(boxptr->r_xtop, w, TRUE);
|
||||
boxvalueury = DBWPrintValue(boxptr->r_ytop, w, FALSE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
|
||||
tobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewStringObj(boxvaluellx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewStringObj(boxvaluelly, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewStringObj(boxvalueurx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewStringObj(boxvalueury, -1));
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
#else
|
||||
TxPrintf("%s box coordinates (%d, %d) to (%d, %d)\n",
|
||||
TxPrintf("%s box coordinates (%s, %s) to (%s, %s)\n",
|
||||
(refEdit) ? "Edit" : "Root",
|
||||
boxptr->r_xbot, boxptr->r_ybot,
|
||||
boxptr->r_xtop, boxptr->r_ytop);
|
||||
boxvaluellx, boxvaluelly, boxvalueurx, boxvalueury);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,12 +117,13 @@ bool cmdDumpParseArgs(char *cmdName, MagWindow *w, TxCommand *cmd, CellUse *dumm
|
|||
#define CALMA_READ 19
|
||||
#define CALMA_READONLY 20
|
||||
#define CALMA_RESCALE 21
|
||||
#define CALMA_WARNING 22
|
||||
#define CALMA_WRITE 23
|
||||
#define CALMA_POLYS 24
|
||||
#define CALMA_PATHS 25
|
||||
#define CALMA_UNDEFINED 26
|
||||
#define CALMA_UNIQUE 27
|
||||
#define CALMA_SAVEPATHS 22
|
||||
#define CALMA_WARNING 23
|
||||
#define CALMA_WRITE 24
|
||||
#define CALMA_POLYS 25
|
||||
#define CALMA_PATHS 26
|
||||
#define CALMA_UNDEFINED 27
|
||||
#define CALMA_UNIQUE 28
|
||||
|
||||
#define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */
|
||||
|
||||
|
|
@ -175,6 +176,7 @@ CmdCalma(
|
|||
" into edit cell",
|
||||
"readonly [yes|no] set cell as read-only and generate output from GDS file",
|
||||
"rescale [yes|no] allow or disallow internal grid subdivision",
|
||||
"savepaths [yes|no] save path centerlines as cell properties",
|
||||
"warning [option] set warning information level",
|
||||
"write file output Calma GDS-II format to \"file\"\n"
|
||||
" for the window's root cell",
|
||||
|
|
@ -738,6 +740,27 @@ CmdCalma(
|
|||
CalmaSubcellPolygons = (unsigned char)option;
|
||||
return;
|
||||
|
||||
case CALMA_SAVEPATHS:
|
||||
if (cmd->tx_argc == 2)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaRecordPaths));
|
||||
#else
|
||||
TxPrintf("Paths in GDS cells read from input file are%s recorded"
|
||||
" as cell properties.\n",
|
||||
(CalmaRecordPaths) ? " " : " not");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
else if (cmd->tx_argc != 3)
|
||||
goto wrongNumArgs;
|
||||
|
||||
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
|
||||
if (option < 0)
|
||||
goto wrongNumArgs;
|
||||
CalmaRecordPaths = (option < 4) ? FALSE : TRUE;
|
||||
return;
|
||||
|
||||
case CALMA_NO_DUP:
|
||||
if (cmd->tx_argc == 2)
|
||||
{
|
||||
|
|
@ -1300,7 +1323,7 @@ CmdCellname(
|
|||
if (cellDef == (CellDef *) NULL)
|
||||
TxError("Unknown cell %s\n", cellname);
|
||||
else
|
||||
CmdDoProperty(cellDef, cmd, 3 + ((dolist) ? 1 : 0));
|
||||
CmdDoProperty(cellDef, w, cmd, 3 + ((dolist) ? 1 : 0));
|
||||
break;
|
||||
|
||||
case IDX_DELETE:
|
||||
|
|
@ -4991,15 +5014,20 @@ cmdDumpParseArgs(
|
|||
bbox = def->cd_bbox;
|
||||
if (def->cd_flags & CDFIXEDBBOX)
|
||||
{
|
||||
char *propvalue;
|
||||
PropertyRecord *proprec;
|
||||
bool found;
|
||||
|
||||
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &found);
|
||||
proprec = DBPropGet(def, "FIXED_BBOX", &found);
|
||||
if (found)
|
||||
{
|
||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
||||
&bbox.r_xtop, &bbox.r_ytop) != 4)
|
||||
bbox = def->cd_bbox;
|
||||
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||
(proprec->prop_len == 4))
|
||||
{
|
||||
bbox.r_xbot = proprec->prop_value.prop_integer[0];
|
||||
bbox.r_ybot = proprec->prop_value.prop_integer[1];
|
||||
bbox.r_xtop = proprec->prop_value.prop_integer[2];
|
||||
bbox.r_ytop = proprec->prop_value.prop_integer[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -925,11 +925,14 @@ cmdExpandFunc(
|
|||
#define DOALL 1
|
||||
#define DOCAPACITANCE 2
|
||||
#define DOCOUPLING 3
|
||||
#define DOLENGTH 4
|
||||
#define DOLOCAL 5
|
||||
#define DORESISTANCE 6
|
||||
#define DOLABELCHECK 7
|
||||
#define DOALIASES 8
|
||||
#define DOEXTRESIST 4
|
||||
#define DOLENGTH 5
|
||||
#define DOLOCAL 6
|
||||
#define DORESISTANCE 7
|
||||
#define DOLABELCHECK 8
|
||||
#define DOALIASES 9
|
||||
#define DOUNIQUE 10
|
||||
#define DOEXTRESIST2 11
|
||||
|
||||
#define LENCLEAR 0
|
||||
#define LENDRIVER 1
|
||||
|
|
@ -972,11 +975,14 @@ CmdExtract(
|
|||
"all all options",
|
||||
"capacitance extract substrate capacitance",
|
||||
"coupling extract coupling capacitance",
|
||||
"extresist extract resistance",
|
||||
"length compute driver-receiver pathlengths",
|
||||
"local put all generated files in the current directory",
|
||||
"resistance estimate resistance",
|
||||
"lumped estimate lumped resistance",
|
||||
"labelcheck check for connections through sticky labels",
|
||||
"aliases output all net name aliases",
|
||||
"unique ensure unique node names during extraction",
|
||||
"resistance extract resistance (same as \"do extresist\")",
|
||||
NULL
|
||||
};
|
||||
static const char * const cmdExtLength[] =
|
||||
|
|
@ -1120,12 +1126,13 @@ CmdExtract(
|
|||
}
|
||||
else if (argc == 2)
|
||||
{
|
||||
char *halodisp;
|
||||
halodisp = DBWPrintValue(ExtCurStyle->exts_sideCoupleHalo,
|
||||
w, TRUE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_Obj *tobj;
|
||||
tobj = Tcl_NewIntObj(ExtCurStyle->exts_sideCoupleHalo);
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(halodisp, -1));
|
||||
#else
|
||||
TxPrintf("Side overlap halo is %d\n", ExtCurStyle->exts_sideCoupleHalo);
|
||||
TxPrintf("Side overlap halo is %s\n", halodisp);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
|
@ -1150,12 +1157,12 @@ CmdExtract(
|
|||
}
|
||||
else if (argc == 2)
|
||||
{
|
||||
char *stepdisp;
|
||||
stepdisp = DBWPrintValue(ExtCurStyle->exts_stepSize, w, TRUE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_Obj *tobj;
|
||||
tobj = Tcl_NewIntObj(ExtCurStyle->exts_stepSize);
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(stepdisp, -1));
|
||||
#else
|
||||
TxPrintf("Extraction step size is %d\n", ExtCurStyle->exts_stepSize);
|
||||
TxPrintf("Extraction step size is %s\n", stepdisp);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
|
@ -1277,9 +1284,11 @@ CmdExtract(
|
|||
TxPrintf("%s capacitance\n", OPTSET(EXT_DOCAPACITANCE));
|
||||
TxPrintf("%s coupling\n", OPTSET(EXT_DOCOUPLING));
|
||||
TxPrintf("%s length\n", OPTSET(EXT_DOLENGTH));
|
||||
TxPrintf("%s resistance\n", OPTSET(EXT_DORESISTANCE));
|
||||
TxPrintf("%s lumped R\n", OPTSET(EXT_DORESISTANCE));
|
||||
TxPrintf("%s label check\n", OPTSET(EXT_DOLABELCHECK));
|
||||
TxPrintf("%s aliases\n", OPTSET(EXT_DOALIASES));
|
||||
TxPrintf("%s unique\n", OPTSET(EXT_DOUNIQUE));
|
||||
TxPrintf("%s resistance (extresist)\n", OPTSET(EXT_DOEXTRESIST));
|
||||
return;
|
||||
#undef OPTSET
|
||||
}
|
||||
|
|
@ -1309,6 +1318,9 @@ CmdExtract(
|
|||
case DORESISTANCE: option = EXT_DORESISTANCE; break;
|
||||
case DOLABELCHECK: option = EXT_DOLABELCHECK; break;
|
||||
case DOALIASES: option = EXT_DOALIASES; break;
|
||||
case DOUNIQUE: option = EXT_DOUNIQUE; break;
|
||||
case DOEXTRESIST:
|
||||
case DOEXTRESIST2: option = EXT_DOEXTRESIST; break;
|
||||
case DOLOCAL:
|
||||
/* "extract do local" and "extract no local" are kept for
|
||||
* backwards compatibility, but now effectively implement
|
||||
|
|
|
|||
585
commands/CmdLQ.c
585
commands/CmdLQ.c
|
|
@ -45,9 +45,8 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
|
|||
#include "utils/undo.h"
|
||||
#include "select/select.h"
|
||||
#include "netmenu/netmenu.h"
|
||||
|
||||
/* C99 compat */
|
||||
#include "cif/cif.h"
|
||||
#include "cif/CIFint.h"
|
||||
|
||||
/* Forward declarations */
|
||||
|
||||
|
|
@ -2296,6 +2295,8 @@ parsepositions:
|
|||
editDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
|
||||
}
|
||||
|
||||
#define PROPERTY_TYPE_COMPAT 4 /* Last entry in cmdPropertyType */
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -2319,47 +2320,449 @@ parsepositions:
|
|||
void
|
||||
CmdDoProperty(
|
||||
CellDef *def,
|
||||
MagWindow *w,
|
||||
TxCommand *cmd,
|
||||
int argstart)
|
||||
{
|
||||
int printPropertiesFunc();
|
||||
PropertyRecord *proprec;
|
||||
char *value;
|
||||
bool propfound;
|
||||
bool propfound, dolist;
|
||||
int proptype, proplen, propvalue, i;
|
||||
dlong dvalue;
|
||||
int locargc = cmd->tx_argc - argstart + 1;
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_Obj *tobj;
|
||||
#endif
|
||||
|
||||
/* Forward declarations */
|
||||
int printPropertiesFunc();
|
||||
int printPlanePropFunc();
|
||||
|
||||
/* These should match the property codes in database.h.in, except
|
||||
* for "compat" which must come at the end.
|
||||
*/
|
||||
static const char * const cmdPropertyType[] = {
|
||||
"string", "integer", "dimension", "double", "plane", "compat", NULL
|
||||
};
|
||||
|
||||
/* If the first keyword is "list", then set dolist and increment
|
||||
* the starting argument position.
|
||||
*/
|
||||
dolist = FALSE;
|
||||
if (locargc > 1)
|
||||
{
|
||||
if (!strcmp(cmd->tx_argv[argstart], "list"))
|
||||
{
|
||||
dolist = TRUE;
|
||||
locargc--;
|
||||
argstart++;
|
||||
}
|
||||
}
|
||||
|
||||
/* If a property type is given, parse it and then strip it from
|
||||
* the arguments list.
|
||||
*/
|
||||
if (locargc > 1)
|
||||
{
|
||||
proptype = Lookup(cmd->tx_argv[argstart], cmdPropertyType);
|
||||
if (proptype >= 0)
|
||||
{
|
||||
if (proptype != PROPERTY_TYPE_COMPAT)
|
||||
{
|
||||
locargc--;
|
||||
argstart++;
|
||||
}
|
||||
}
|
||||
else
|
||||
proptype = PROPERTY_TYPE_STRING; /* default */
|
||||
}
|
||||
else
|
||||
proptype = PROPERTY_TYPE_STRING; /* default */
|
||||
|
||||
if (locargc == 1)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_Obj *tobj;
|
||||
/* Create an empty list for the interpreter result; the
|
||||
* printPropertiesFunc() function will append values to it.
|
||||
*/
|
||||
tobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
#endif
|
||||
/* print all properties and their values */
|
||||
DBPropEnum(def, printPropertiesFunc, NULL);
|
||||
DBPropEnum(def, printPropertiesFunc, (ClientData)w);
|
||||
}
|
||||
|
||||
else if (locargc == 2)
|
||||
{
|
||||
/* print the value of the indicated property */
|
||||
value = (char *)DBPropGet(def, cmd->tx_argv[argstart], &propfound);
|
||||
if (propfound)
|
||||
/* If the property type was "compat", then give the state of the
|
||||
* compatibility flag and return.
|
||||
*/
|
||||
if (proptype == PROPERTY_TYPE_COMPAT)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetResult(magicinterp, value, NULL);
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(DBPropCompat));
|
||||
#else
|
||||
TxPrintf("%s", value);
|
||||
TxPrintf("%s\n", (DBPropCompat == TRUE) ? "True" : "False");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/* Print the value of the indicated property */
|
||||
proprec = (PropertyRecord *)DBPropGet(def, cmd->tx_argv[argstart], &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
proptype = proprec->prop_type;
|
||||
#ifdef MAGIC_WRAPPER
|
||||
switch (proptype)
|
||||
{
|
||||
case PROPERTY_TYPE_STRING:
|
||||
Tcl_SetResult(magicinterp, proprec->prop_value.prop_string, NULL);
|
||||
break;
|
||||
case PROPERTY_TYPE_INTEGER:
|
||||
if (proprec->prop_len == 1)
|
||||
Tcl_SetObjResult(magicinterp,
|
||||
Tcl_NewIntObj(proprec->prop_value.prop_integer[0]));
|
||||
else
|
||||
{
|
||||
tobj = Tcl_NewListObj(0, NULL);
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewIntObj(
|
||||
proprec->prop_value.prop_integer[i]));
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
}
|
||||
break;
|
||||
case PROPERTY_TYPE_DIMENSION:
|
||||
if (proprec->prop_len == 1)
|
||||
Tcl_SetResult(magicinterp,
|
||||
DBWPrintValue(proprec->prop_value.prop_integer[0],
|
||||
w, TRUE), NULL);
|
||||
else
|
||||
{
|
||||
tobj = Tcl_NewListObj(0, NULL);
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewStringObj(DBWPrintValue(
|
||||
proprec->prop_value.prop_integer[i], w,
|
||||
((i % 2) == 0) ? TRUE : FALSE), -1));
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
}
|
||||
break;
|
||||
case PROPERTY_TYPE_PLANE:
|
||||
tobj = Tcl_NewListObj(0, NULL);
|
||||
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||
proprec->prop_value.prop_plane,
|
||||
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
|
||||
(ClientData)tobj);
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
break;
|
||||
case PROPERTY_TYPE_DOUBLE:
|
||||
if (proprec->prop_len == 1)
|
||||
Tcl_SetObjResult(magicinterp,
|
||||
Tcl_NewWideIntObj((Tcl_WideInt)
|
||||
proprec->prop_value.prop_double[0]));
|
||||
else
|
||||
{
|
||||
tobj = Tcl_NewListObj(0, NULL);
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewWideIntObj((Tcl_WideInt)
|
||||
proprec->prop_value.prop_double[i]));
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#else
|
||||
switch (proptype)
|
||||
{
|
||||
case PROPERTY_TYPE_STRING:
|
||||
TxPrintf("%s\n", proprec->prop_value.prop_string);
|
||||
break;
|
||||
case PROPERTY_TYPE_INTEGER:
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
TxPrintf("%d ", proprec->prop_value.prop_integer[i]);
|
||||
TxPrintf("\n");
|
||||
break;
|
||||
case PROPERTY_TYPE_DIMENSION:
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
TxPrintf("%s ", DBWPrintValue(
|
||||
proprec->prop_value.prop_integer[i], w,
|
||||
((i % 2) == 0) ? TRUE : FALSE);
|
||||
|
||||
TxPrintf("\n");
|
||||
break;
|
||||
case PROPERTY_TYPE_PLANE:
|
||||
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||
proprec->prop_value.prop_plane,
|
||||
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
|
||||
(ClientData)NULL);
|
||||
TxPrintf("\n");
|
||||
break;
|
||||
case PROPERTY_TYPE_DOUBLE:
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
TxPrintf( "%"DLONG_PREFIX"d",
|
||||
proprec->prop_value.prop_double[i]);
|
||||
TxPrintf("\n");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifdef MAGIC_WRAPPER
|
||||
/* If the command was "cellname list property ...", then */
|
||||
/* just return NULL if the property was not found. */
|
||||
if (strcmp(cmd->tx_argv[1], "list"))
|
||||
if (!dolist)
|
||||
#endif
|
||||
TxError("Property name \"%s\" is not defined\n", cmd->tx_argv[1]);
|
||||
TxError("Property name \"%s\" is not defined\n", cmd->tx_argv[argstart]);
|
||||
}
|
||||
}
|
||||
else if (locargc == 3)
|
||||
else if (locargc >= 3)
|
||||
{
|
||||
/* If the property type was "compat", then set the state of the
|
||||
* compatibility flag and return.
|
||||
*/
|
||||
if (proptype == PROPERTY_TYPE_COMPAT)
|
||||
{
|
||||
int idx;
|
||||
static const char * const cmdPropYesNo[] = {
|
||||
"disable", "no", "false", "off", "0",
|
||||
"enable", "yes", "true", "on", "1", 0 };
|
||||
idx = Lookup(cmd->tx_argv[2], cmdPropYesNo);
|
||||
if (idx < 0)
|
||||
{
|
||||
TxError("Unknown property compat option \"%s\"\n", cmd->tx_argv[2]);
|
||||
return;
|
||||
}
|
||||
DBPropCompat = (idx <= 4) ? FALSE : TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Catch the following known reserved keywords and cast them to the
|
||||
* expected property type. If any property type was already given
|
||||
* to the command, it is overridden. This ensures that the reserved
|
||||
* keyword functions work correctly.
|
||||
*
|
||||
* GDS_START, GDS_END: PROPERTY_TYPE_DOUBLE
|
||||
* MASKHINTS_*: PROPERTY_TYPE_PLANE
|
||||
* FIXED_BBOX: PROPERTY_TYPE_DIMENSION
|
||||
*/
|
||||
if (!strcmp(cmd->tx_argv[argstart], "GDS_START"))
|
||||
proptype = PROPERTY_TYPE_DOUBLE;
|
||||
else if (!strcmp(cmd->tx_argv[argstart], "GDS_END"))
|
||||
proptype = PROPERTY_TYPE_DOUBLE;
|
||||
else if (!strcmp(cmd->tx_argv[argstart], "GDS_FILE"))
|
||||
proptype = PROPERTY_TYPE_STRING;
|
||||
else if (!strcmp(cmd->tx_argv[argstart], "FIXED_BBOX"))
|
||||
proptype = PROPERTY_TYPE_DIMENSION;
|
||||
else if (!strcmp(cmd->tx_argv[argstart], "OBS_BBOX"))
|
||||
proptype = PROPERTY_TYPE_DIMENSION;
|
||||
else if (!strncmp(cmd->tx_argv[argstart], "MASKHINTS_", 10))
|
||||
proptype = PROPERTY_TYPE_PLANE;
|
||||
|
||||
if (strlen(cmd->tx_argv[argstart + 1]) == 0)
|
||||
DBPropPut(def, cmd->tx_argv[argstart], NULL);
|
||||
else
|
||||
{
|
||||
value = StrDup((char **)NULL, cmd->tx_argv[argstart + 1]);
|
||||
DBPropPut(def, cmd->tx_argv[argstart], value);
|
||||
if (proptype == PROPERTY_TYPE_STRING)
|
||||
{
|
||||
proplen = strlen(cmd->tx_argv[argstart + 1]);
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) -
|
||||
7 + proplen);
|
||||
proprec->prop_type = proptype;
|
||||
proprec->prop_len = proplen;
|
||||
strcpy(proprec->prop_value.prop_string, cmd->tx_argv[argstart + 1]);
|
||||
}
|
||||
else /* All non-string properties */
|
||||
{
|
||||
Plane *plane;
|
||||
Rect r;
|
||||
|
||||
/* Two choices: If locargc == 3 then all values are in one
|
||||
* argument. If locargc > 3, then parse each argument as a
|
||||
* separate value.
|
||||
*/
|
||||
if (locargc > 3)
|
||||
{
|
||||
proplen = locargc - 2;
|
||||
if (proptype == PROPERTY_TYPE_DOUBLE)
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
(proplen - 1)*sizeof(dlong));
|
||||
else if (proptype == PROPERTY_TYPE_PLANE)
|
||||
{
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||
proprec->prop_value.prop_plane = plane;
|
||||
}
|
||||
else
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
(proplen - 2)*sizeof(int));
|
||||
proprec->prop_type = proptype;
|
||||
proprec->prop_len = proplen;
|
||||
|
||||
for (i = 1; i < locargc - 1; i++)
|
||||
{
|
||||
if (proptype == PROPERTY_TYPE_INTEGER)
|
||||
{
|
||||
if (sscanf(cmd->tx_argv[argstart + i], "%d",
|
||||
&propvalue) == 1)
|
||||
proprec->prop_value.prop_integer[i - 1] = propvalue;
|
||||
else
|
||||
{
|
||||
TxError("Unable to parse value \"%s\" as an integer\n",
|
||||
cmd->tx_argv[argstart + i]);
|
||||
proprec->prop_value.prop_integer[i - 1] = 0;
|
||||
}
|
||||
}
|
||||
else if (proptype == PROPERTY_TYPE_DOUBLE)
|
||||
{
|
||||
if (sscanf(cmd->tx_argv[argstart + i], "%"DLONG_PREFIX"d",
|
||||
&dvalue) == 1)
|
||||
proprec->prop_value.prop_double[i - 1] = dvalue;
|
||||
else
|
||||
{
|
||||
TxError("Unable to parse value \"%s\" as an integer\n",
|
||||
cmd->tx_argv[argstart + i]);
|
||||
proprec->prop_value.prop_double[i - 1] = 0;
|
||||
}
|
||||
}
|
||||
else if (proptype == PROPERTY_TYPE_PLANE)
|
||||
{
|
||||
propvalue = cmdParseCoord(w, cmd->tx_argv[argstart + i],
|
||||
FALSE, ((i % 2) == 0) ? FALSE : TRUE);
|
||||
switch ((i - 1) % 4)
|
||||
{
|
||||
case 0:
|
||||
r.r_xbot = propvalue;
|
||||
break;
|
||||
case 1:
|
||||
r.r_ybot = propvalue;
|
||||
break;
|
||||
case 2:
|
||||
r.r_xtop = propvalue;
|
||||
break;
|
||||
case 3:
|
||||
r.r_ytop = propvalue;
|
||||
DBPaintPlane(plane, &r, CIFPaintTable,
|
||||
(PaintUndoInfo *)NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else /* PROPERTY_TYPE_DIMENSION */
|
||||
{
|
||||
propvalue = cmdParseCoord(w, cmd->tx_argv[argstart + i],
|
||||
FALSE, ((i % 2) == 0) ? FALSE : TRUE);
|
||||
proprec->prop_value.prop_integer[i - 1] = propvalue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Make two passes through the argument string, once to get
|
||||
* the valid number of arguments, then again to parse the
|
||||
* values, once the property record has been allocated
|
||||
*/
|
||||
if (proptype == PROPERTY_TYPE_PLANE)
|
||||
{
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||
proprec->prop_value.prop_plane = plane;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = cmd->tx_argv[argstart + 1];
|
||||
for (proplen = 0; *value != '\0'; )
|
||||
{
|
||||
if (isspace(*value) && (*value != '\0')) value++;
|
||||
if (!isspace(*value))
|
||||
{
|
||||
proplen++;
|
||||
while (!isspace(*value) && (*value != '\0')) value++;
|
||||
}
|
||||
}
|
||||
if (proplen > 0)
|
||||
{
|
||||
proprec = (PropertyRecord *)mallocMagic(
|
||||
sizeof(PropertyRecord) +
|
||||
(proplen - 2) * sizeof(int));
|
||||
proprec->prop_type = proptype;
|
||||
proprec->prop_len = proplen;
|
||||
}
|
||||
}
|
||||
/* Second pass */
|
||||
value = cmd->tx_argv[argstart + 1];
|
||||
for (proplen = 0; proplen < proprec->prop_len; proplen++)
|
||||
{
|
||||
if (isspace(*value) && (*value != '\0')) value++;
|
||||
if (!isspace(*value))
|
||||
{
|
||||
char *spptr, spchar;
|
||||
/* cmdParseCoord() can only handle one value at a
|
||||
* time, so look ahead and null out the next space
|
||||
* character if there is one.
|
||||
*/
|
||||
spptr = value + 1;
|
||||
while (!isspace(*spptr) && (*spptr != '\0')) spptr++;
|
||||
spchar = *spptr;
|
||||
*spptr = '\0';
|
||||
|
||||
if (proptype == PROPERTY_TYPE_INTEGER)
|
||||
{
|
||||
if (sscanf(value, "%d", &propvalue) != 1)
|
||||
{
|
||||
TxError("Unable to parse integer "
|
||||
"value from \"%s\"\n",
|
||||
value);
|
||||
propvalue = 0;
|
||||
}
|
||||
proprec->prop_value.prop_integer[proplen] = propvalue;
|
||||
}
|
||||
else if (proptype == PROPERTY_TYPE_DOUBLE)
|
||||
{
|
||||
if (sscanf(value, "%"DLONG_PREFIX"d", &dvalue) != 1)
|
||||
{
|
||||
TxError("Unable to parse integer "
|
||||
"value from \"%s\"\n",
|
||||
value);
|
||||
propvalue = 0;
|
||||
}
|
||||
proprec->prop_value.prop_double[proplen] = dvalue;
|
||||
}
|
||||
else if (proptype == PROPERTY_TYPE_PLANE)
|
||||
{
|
||||
propvalue = cmdParseCoord(w, value, FALSE,
|
||||
((proplen % 2) == 0) ? TRUE : FALSE);
|
||||
switch (proplen % 4)
|
||||
{
|
||||
case 0:
|
||||
r.r_xbot = propvalue;
|
||||
break;
|
||||
case 1:
|
||||
r.r_ybot = propvalue;
|
||||
break;
|
||||
case 2:
|
||||
r.r_xtop = propvalue;
|
||||
break;
|
||||
case 3:
|
||||
r.r_ytop = propvalue;
|
||||
DBPaintPlane(plane, &r, CIFPaintTable,
|
||||
(PaintUndoInfo *)NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else /* PROPERTY_TYPE_DIMENSION */
|
||||
{
|
||||
propvalue = cmdParseCoord(w, value, FALSE,
|
||||
((proplen % 2) == 0) ? TRUE : FALSE);
|
||||
proprec->prop_value.prop_integer[proplen] = propvalue;
|
||||
}
|
||||
*spptr = spchar;
|
||||
while (!isspace(*value) && (*value != '\0')) value++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DBPropPut(def, cmd->tx_argv[argstart], proprec);
|
||||
}
|
||||
def->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
|
||||
}
|
||||
|
|
@ -2380,10 +2783,14 @@ CmdDoProperty(
|
|||
* defined in database/DBprop.c.
|
||||
*
|
||||
* Usage:
|
||||
* property [name] [value]
|
||||
* property [string|integer|dimension] [name] [value]
|
||||
*
|
||||
* "name" is a unique string tag for the property, and "value" is its
|
||||
* string value.
|
||||
* If the first argument is present, it must be one of the known
|
||||
* keywords, and determines the form in which "value" is interpreted and
|
||||
* stored. "name" is a unique string tag for the property. "value" is
|
||||
* the value of the property, which is either a string, integer, or a
|
||||
* list of integers. The difference between an "integer" and a "dimension"
|
||||
* is that all values which are dimensions are scaled with internal units.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
|
|
@ -2410,9 +2817,62 @@ CmdProperty(
|
|||
else
|
||||
def = ((CellUse *) w->w_surfaceID)->cu_def;
|
||||
|
||||
CmdDoProperty(def, cmd, 1);
|
||||
CmdDoProperty(def, w, cmd, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* Callback function for printing values from a Plane property
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
int
|
||||
printPlanePropFunc(
|
||||
Tile *tile,
|
||||
TileType dinfo,
|
||||
Tcl_Obj *lobj)
|
||||
{
|
||||
Rect r;
|
||||
MagWindow *w;
|
||||
|
||||
TiToRect(tile, &r);
|
||||
windCheckOnlyWindow(&w, DBWclientID);
|
||||
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewStringObj(DBWPrintValue(r.r_xbot, w, TRUE), -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewStringObj(DBWPrintValue(r.r_ybot, w, FALSE), -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewStringObj(DBWPrintValue(r.r_xtop, w, TRUE), -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewStringObj(DBWPrintValue(r.r_ytop, w, FALSE), -1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
printPlanePropFunc(
|
||||
Tile *tile,
|
||||
TileType dinfo,
|
||||
ClientData cdata /* (unused) */
|
||||
{
|
||||
Rect r;
|
||||
MagWindow *w;
|
||||
|
||||
TiToRect(tile, &r)
|
||||
windCheckOnlyWindow(&w, DBWclientID);
|
||||
|
||||
TxPrintf("%s ", DBWPrintValue(r.r_xbot, w, TRUE);
|
||||
TxPrintf("%s ", DBWPrintValue(r.r_ybot, w, FALSE);
|
||||
TxPrintf("%s ", DBWPrintValue(r.r_xtop, w, TRUE);
|
||||
TxPrintf("%s ", DBWPrintValue(r.r_ytop, w, FALSE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* Callback function for printing a single property key:value pair
|
||||
|
|
@ -2422,27 +2882,84 @@ CmdProperty(
|
|||
int
|
||||
printPropertiesFunc(
|
||||
const char *name,
|
||||
ClientData value,
|
||||
ClientData cdata) /* not used */
|
||||
PropertyRecord *proprec,
|
||||
MagWindow *w)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
char *keyvalue;
|
||||
int i;
|
||||
|
||||
if (value == NULL)
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_Obj *tobj, *lobj;
|
||||
|
||||
tobj = Tcl_GetObjResult(magicinterp);
|
||||
lobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_NewStringObj(name, -1));
|
||||
|
||||
switch (proprec->prop_type)
|
||||
{
|
||||
keyvalue = (char *)mallocMagic(strlen(name) + 4);
|
||||
sprintf(keyvalue, "%s {}", name);
|
||||
case PROPERTY_TYPE_STRING:
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewStringObj(proprec->prop_value.prop_string, -1));
|
||||
break;
|
||||
case PROPERTY_TYPE_INTEGER:
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewIntObj(proprec->prop_value.prop_integer[i]));
|
||||
break;
|
||||
case PROPERTY_TYPE_DIMENSION:
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewStringObj(
|
||||
DBWPrintValue(proprec->prop_value.prop_integer[i],
|
||||
w, ((i % 2) == 0) ? TRUE : FALSE), -1));
|
||||
break;
|
||||
case PROPERTY_TYPE_PLANE:
|
||||
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||
proprec->prop_value.prop_plane,
|
||||
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
|
||||
(ClientData)lobj);
|
||||
break;
|
||||
case PROPERTY_TYPE_DOUBLE:
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewWideIntObj(proprec->prop_value.prop_double[i]));
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
keyvalue = (char *)mallocMagic(strlen(name) + strlen((const char *)value) + 2);
|
||||
sprintf(keyvalue, "%s %s", name, (const char *)value);
|
||||
}
|
||||
Tcl_AppendElement(magicinterp, keyvalue);
|
||||
freeMagic(keyvalue);
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj, lobj);
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
|
||||
#else
|
||||
TxPrintf("%s = %s\n", name, (const char *)value);
|
||||
switch (proprec->prop_type)
|
||||
{
|
||||
case PROPERTY_TYPE_STRING:
|
||||
TxPrintf("%s = %s\n", name, (const char *)proprec->prop_string);
|
||||
break;
|
||||
case PROPERTY_TYPE_INTEGER:
|
||||
TxPrintf("%s = ", name);
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
TxPrintf("%d ", proprec->prop_integer[i]);
|
||||
TxPrintf("\n");
|
||||
break;
|
||||
case PROPERTY_TYPE_DIMENSION:
|
||||
TxPrintf("%s = ", name);
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
TxPrintf("%s ", DBWPrintValue(proprec->prop_value.prop_integer[i],
|
||||
w, ((i % 2) == 0) ? TRUE : FALSE);
|
||||
TxPrintf("\n");
|
||||
break;
|
||||
case PROPERTY_TYPE_PLANE:
|
||||
TxPrintf("%s = ", name);
|
||||
DBSrPaintArea((Tile *)NULL, proprec->prop_value.prop_plane,
|
||||
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
|
||||
(ClientData)NULL);
|
||||
TxPrintf("\n");
|
||||
break;
|
||||
case PROPERTY_TYPE_DOUBLE:
|
||||
TxPrintf("%s = ", name);
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
TxPrintf("%"DLONG_PREFIX"d ", proprec->prop_double[i]);
|
||||
TxPrintf("\n");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0; /* keep the search alive */
|
||||
|
|
|
|||
109
commands/CmdRS.c
109
commands/CmdRS.c
|
|
@ -1084,25 +1084,33 @@ CmdSelect(
|
|||
*/
|
||||
|
||||
case SEL_BBOX:
|
||||
{
|
||||
char *selllx, *sellly, *selurx, *selury;
|
||||
|
||||
GeoTransRect(&SelectUse->cu_transform, &SelectDef->cd_bbox, &selarea);
|
||||
|
||||
selllx = DBWPrintValue(selarea.r_xbot, w, TRUE);
|
||||
sellly = DBWPrintValue(selarea.r_ybot, w, FALSE);
|
||||
selurx = DBWPrintValue(selarea.r_xtop, w, TRUE);
|
||||
selury = DBWPrintValue(selarea.r_ytop, w, FALSE);
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
lobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewIntObj(selarea.r_xbot));
|
||||
Tcl_NewStringObj(selllx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewIntObj(selarea.r_ybot));
|
||||
Tcl_NewStringObj(sellly, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewIntObj(selarea.r_xtop));
|
||||
Tcl_NewStringObj(selurx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewIntObj(selarea.r_ytop));
|
||||
Tcl_NewStringObj(selury, -1));
|
||||
Tcl_SetObjResult(magicinterp, lobj);
|
||||
#else
|
||||
TxPrintf("Select bounding box: %d %d %d %d\n",
|
||||
selarea.r_xbot, selarea.r_ybot,
|
||||
selarea.r_xtop, selarea.r_ytop);
|
||||
TxPrintf("Select bounding box: %s %s %s %s\n",
|
||||
selllx, sellly, selurx, selury);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
* Make a copy of the selection at its present loction but do not
|
||||
|
|
@ -1985,23 +1993,25 @@ cmdLabelRectFunc(
|
|||
|
||||
if (rect == NULL)
|
||||
{
|
||||
char *labllx, *lablly, *laburx, *labury;
|
||||
|
||||
/* Note: Ideally, the MagWindow pointer should be passed to this function */
|
||||
labllx = DBWPrintValue(label->lab_rect.r_xbot, (MagWindow *)NULL, TRUE);
|
||||
lablly = DBWPrintValue(label->lab_rect.r_ybot, (MagWindow *)NULL, FALSE);
|
||||
laburx = DBWPrintValue(label->lab_rect.r_xtop, (MagWindow *)NULL, TRUE);
|
||||
labury = DBWPrintValue(label->lab_rect.r_ytop, (MagWindow *)NULL, FALSE);
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
lobj = Tcl_GetObjResult(magicinterp);
|
||||
pobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj,
|
||||
Tcl_NewIntObj((double)label->lab_rect.r_xbot));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj,
|
||||
Tcl_NewIntObj((double)label->lab_rect.r_ybot));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj,
|
||||
Tcl_NewIntObj((double)label->lab_rect.r_xtop));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj,
|
||||
Tcl_NewIntObj((double)label->lab_rect.r_ytop));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(labllx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(lablly, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laburx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(labury, -1));
|
||||
Tcl_SetObjResult(magicinterp, lobj);
|
||||
#else
|
||||
TxPrintf("%d %d %d %d\n",
|
||||
label->lab_rect.r_xbot, label->lab_rect.r_ybot,
|
||||
label->lab_rect.r_xtop, label->lab_rect.r_ytop);
|
||||
TxPrintf("%s %s %s %s\n", labllx, lablly, laburx,labury);
|
||||
#endif
|
||||
}
|
||||
else if (!GEO_SAMERECT(label->lab_rect, *rect))
|
||||
|
|
@ -2317,11 +2327,13 @@ CmdSetLabel(
|
|||
{
|
||||
if (locargc == 2)
|
||||
{
|
||||
char *labsize;
|
||||
|
||||
labsize = DBWPrintValue(DefaultLabel->lab_size, w, FALSE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp,
|
||||
Tcl_NewIntObj(DefaultLabel->lab_size));
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(labsize, -1));
|
||||
#else
|
||||
TxPrintf("%d\n", DefaultLabel->lab_size);
|
||||
TxPrintf("%s\n", labsize);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
|
@ -2360,16 +2372,20 @@ CmdSetLabel(
|
|||
{
|
||||
if (locargc == 2)
|
||||
{
|
||||
char *laboffx, *laboffy;
|
||||
laboffx = DBWPrintValue(DefaultLabel->lab_offset.p_x, w,
|
||||
TRUE);
|
||||
laboffy = DBWPrintValue(DefaultLabel->lab_offset.p_y, w,
|
||||
FALSE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
lobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewIntObj(DefaultLabel->lab_offset.p_x));
|
||||
Tcl_NewStringObj(laboffx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewIntObj(DefaultLabel->lab_offset.p_y));
|
||||
Tcl_NewStringObj(laboffy, -1));
|
||||
Tcl_SetObjResult(magicinterp, lobj);
|
||||
#else
|
||||
TxPrintf("%d %d\n", DefaultLabel->lab_offset.p_x,
|
||||
DefaultLabel->lab_offset.p_y);
|
||||
TxPrintf("%s %s\n", laboffx, laboffy);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
|
@ -2884,16 +2900,39 @@ CmdSnap(
|
|||
TxPrintf("Usage: snap [internal | lambda | user]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Backwards compatibility: Use of "snap" to set units display and
|
||||
* parsing has been deprecated as of February 2026. However, as this
|
||||
* is rather disruptive to existing scripts which use "snap" to change
|
||||
* the parsing of units, then the following measure is being taken
|
||||
* (for now, anyway): If DBWUnits is set to DBW_UNITS_DEFAULT, then
|
||||
* "snap internal" will set DBWUnits as well as DBWSnapToGrid. If
|
||||
* DBWUnits is changed first (e.g., "units internal"), then "snap" will
|
||||
* affect only the snap grid. The older usage will be accompanied by a
|
||||
* warning message. Note that backwards compatibility is being kept
|
||||
* only in the case of "snap internal", which was commonly used in
|
||||
* scripts to make sure that all units were interpreted as internal
|
||||
* units.
|
||||
*/
|
||||
if ((DBWUnits == DBW_UNITS_DEFAULT) && (n == SNAP_INTERNAL))
|
||||
{
|
||||
DBWUnits = DBW_UNITS_INTERNAL;
|
||||
TxError("Warning: snap setting is also changing units. This usage "
|
||||
"is deprecated\nand may be removed in the future. Use "
|
||||
"\"units\" to change units, and\nchange units before "
|
||||
"setting snap to keep this message from appearing.\n");
|
||||
}
|
||||
|
||||
switch (n)
|
||||
{
|
||||
case SNAP_OFF: case SNAP_INTERNAL:
|
||||
DBWSnapToGrid = DBW_SNAP_INTERNAL;
|
||||
DBWSnapToGrid = DBW_UNITS_INTERNAL;
|
||||
return;
|
||||
case SNAP_LAMBDA:
|
||||
DBWSnapToGrid = DBW_SNAP_LAMBDA;
|
||||
DBWSnapToGrid = DBW_UNITS_LAMBDA;
|
||||
return;
|
||||
case SNAP_GRID: case SNAP_USER: case SNAP_ON:
|
||||
DBWSnapToGrid = DBW_SNAP_USER;
|
||||
DBWSnapToGrid = DBW_UNITS_USER;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2901,21 +2940,19 @@ printit:
|
|||
if (n == SNAP_LIST) /* list */
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetResult(magicinterp,
|
||||
(DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" :
|
||||
((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user"),
|
||||
(DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" :
|
||||
((DBWSnapToGrid == DBW_UNITS_LAMBDA) ? "lambda" : "user"),
|
||||
TCL_VOLATILE);
|
||||
#else
|
||||
TxPrintf("%s\n", (DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" :
|
||||
((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user"));
|
||||
TxPrintf("%s\n", (DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" :
|
||||
((DBWSnapToGrid == DBW_UNITS_LAMBDA) ? "lambda" : "user"));
|
||||
#endif
|
||||
else
|
||||
TxPrintf("Box is aligned to %s grid\n",
|
||||
(DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" :
|
||||
((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user"));
|
||||
(DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" :
|
||||
((DBWSnapToGrid == DBW_UNITS_LAMBDA) ? "lambda" : "user"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
|
|||
|
|
@ -73,9 +73,22 @@ TileTypeBitMask CmdYMAllButSpace;
|
|||
* lambda, a suffix of "g" indicates the user grid, and a suffix in metric
|
||||
* notation ("nm", "um", "mm", "cm") indicates natural units. Other valid
|
||||
* units are "cu" or "centimicrons" for centimicrons, or "microns" for um.
|
||||
* Units without any suffix are assumed to be in lambda if "snap"
|
||||
* (DBWSnapToGrid) is set to lambda, grid units if "snap" is set to the
|
||||
* user grid, and internal units otherwise.
|
||||
* Traditional (backwards-compatible) behavior: Units without any suffix
|
||||
* are assumed to be in lambda if "snap" (DBWSnapToGrid) is set to lambda,
|
||||
* grid units if "snap" is set to the user grid, and internal units otherwise.
|
||||
* Current behavior: Use of the "units" command to set the units to
|
||||
* any value other than "default" causes cmdScaleCoord() to parse any
|
||||
* units provided without an identifying suffix as the units indicted by
|
||||
* the "units" command. Once the "units" command has been issued, the
|
||||
* values are dependent on DBWUnits and not on DBWSnapToGrid.
|
||||
*
|
||||
* Additional behavior from magic version 8.3.596: A single command
|
||||
* option can use simple expressions using '+', '-', '*', and '/'. These
|
||||
* can be passed as a single token, without spaces, or within a string
|
||||
* token deliniated by quotes or braces, per usual Tcl syntax. Unlike
|
||||
* the Tcl "expr" command, this can solve arithmetic expressions of
|
||||
* suffixed values, evaluated independently such that different suffixes
|
||||
* may be used (e.g., "1g + 3um" meaning 1 grid pitch plus 3 microns).
|
||||
*
|
||||
* MagWindow argument w is used only with grid-based snapping, to find
|
||||
* the value of the grid for the given window. In this case, because the
|
||||
|
|
@ -99,6 +112,13 @@ TileTypeBitMask CmdYMAllButSpace;
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define PARSEOP_NONE 0
|
||||
#define PARSEOP_ADD 1
|
||||
#define PARSEOP_SUB 2
|
||||
#define PARSEOP_MUL 3
|
||||
#define PARSEOP_DIV 4
|
||||
#define PARSEOP_END 5
|
||||
|
||||
int
|
||||
cmdScaleCoord(
|
||||
MagWindow *w,
|
||||
|
|
@ -109,107 +129,195 @@ cmdScaleCoord(
|
|||
{
|
||||
char *endptr;
|
||||
double dval = 0;
|
||||
int mscale = 1;
|
||||
int mscale = 1, curunits;
|
||||
int retval, curval, parseop;
|
||||
DBWclientRec *crec;
|
||||
|
||||
if (*arg == '{') arg++;
|
||||
while (isspace(*arg)) arg++;
|
||||
if (*arg == '{' || *arg == '"') arg++;
|
||||
while (isspace(*arg) && (*arg != '\0')) arg++;
|
||||
|
||||
dval = strtod(arg, &endptr);
|
||||
dval *= (double)scale;
|
||||
parseop = PARSEOP_NONE;
|
||||
retval = 0;
|
||||
while (*arg != '\0')
|
||||
{
|
||||
dval = strtod(arg, &endptr);
|
||||
dval *= (double)scale;
|
||||
mscale = -1;
|
||||
|
||||
if (endptr == arg)
|
||||
{
|
||||
/* strtod() error condition */
|
||||
TxError("Coordinate value cannot be parsed: assuming 0\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
else if ((*endptr == 'l')
|
||||
|| ((*endptr == '\0') && (DBWSnapToGrid == DBW_SNAP_LAMBDA)))
|
||||
{
|
||||
/* lambda or default units */
|
||||
dval *= (double)DBLambda[1];
|
||||
dval /= (double)DBLambda[0];
|
||||
return round(dval);
|
||||
}
|
||||
else if ((*endptr == 'i')
|
||||
|| ((*endptr == '\0') && (DBWSnapToGrid == DBW_SNAP_INTERNAL)))
|
||||
{
|
||||
/* internal units */
|
||||
return round(dval);
|
||||
}
|
||||
else if ((*endptr == 'g')
|
||||
|| ((*endptr == '\0') && (DBWSnapToGrid == DBW_SNAP_USER)))
|
||||
{
|
||||
/* grid units */
|
||||
if (w == (MagWindow *)NULL)
|
||||
if (endptr == arg)
|
||||
{
|
||||
windCheckOnlyWindow(&w, DBWclientID);
|
||||
if (w == (MagWindow *)NULL)
|
||||
return round(dval); /* Default, if window is unknown */
|
||||
}
|
||||
crec = (DBWclientRec *) w->w_clientData;
|
||||
if (is_x)
|
||||
{
|
||||
dval *= (double)(crec->dbw_gridRect.r_xtop
|
||||
- crec->dbw_gridRect.r_xbot);
|
||||
if (!is_relative)
|
||||
dval += (double)crec->dbw_gridRect.r_xbot;
|
||||
/* strtod() error condition */
|
||||
TxError("Coordinate value cannot be parsed: assuming 0\n");
|
||||
curval = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Original behavior was to accept un-suffixed values according to the
|
||||
* "snap" setting. This behavior remains in effect until the "units"
|
||||
* command is used, in which case units follow the selected units
|
||||
* value indepedendently of the snap setting.
|
||||
*
|
||||
* Updated 12/24/2026 to handle space-separated values (in which
|
||||
* *endptr may be a space as well as NULL).
|
||||
*/
|
||||
if (DBWUnits == DBW_UNITS_DEFAULT)
|
||||
curunits = DBWSnapToGrid;
|
||||
else
|
||||
curunits = DBWUnits & DBW_UNITS_TYPE_MASK;
|
||||
|
||||
if ((*endptr == 'l')
|
||||
|| (((*endptr == '\0') || isspace(*endptr))
|
||||
&& (curunits == DBW_UNITS_LAMBDA)))
|
||||
{
|
||||
dval *= (double)(crec->dbw_gridRect.r_ytop
|
||||
- crec->dbw_gridRect.r_ybot);
|
||||
if (!is_relative)
|
||||
dval += (double)crec->dbw_gridRect.r_ybot;
|
||||
/* lambda or default units */
|
||||
dval *= (double)DBLambda[1];
|
||||
dval /= (double)DBLambda[0];
|
||||
}
|
||||
return round(dval);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* natural units referred to the current cifoutput style */
|
||||
if (*(endptr + 1) == 'm')
|
||||
else if ((*endptr == 'i')
|
||||
|| (((*endptr == '\0') || isspace(*endptr))
|
||||
&& (curunits == DBW_UNITS_INTERNAL)))
|
||||
{
|
||||
/* internal units */
|
||||
}
|
||||
else if ((*endptr == 'g')
|
||||
|| (((*endptr == '\0') || isspace(*endptr))
|
||||
&& (curunits == DBW_UNITS_USER)))
|
||||
{
|
||||
/* grid units */
|
||||
if (w == (MagWindow *)NULL)
|
||||
{
|
||||
windCheckOnlyWindow(&w, DBWclientID);
|
||||
if (w == (MagWindow *)NULL)
|
||||
{
|
||||
curval = round(dval); /* Default, if window is unknown */
|
||||
break;
|
||||
}
|
||||
}
|
||||
crec = (DBWclientRec *) w->w_clientData;
|
||||
if (is_x)
|
||||
{
|
||||
dval *= (double)(crec->dbw_gridRect.r_xtop
|
||||
- crec->dbw_gridRect.r_xbot);
|
||||
if (!is_relative)
|
||||
dval += (double)crec->dbw_gridRect.r_xbot;
|
||||
}
|
||||
else
|
||||
{
|
||||
dval *= (double)(crec->dbw_gridRect.r_ytop
|
||||
- crec->dbw_gridRect.r_ybot);
|
||||
if (!is_relative)
|
||||
dval += (double)crec->dbw_gridRect.r_ybot;
|
||||
}
|
||||
}
|
||||
else if (((*endptr == '\0') || isspace(*endptr))
|
||||
&& (curunits == DBW_UNITS_MICRONS))
|
||||
{
|
||||
mscale = 1000;
|
||||
}
|
||||
else if (*endptr != '\0')
|
||||
{
|
||||
/* natural units referred to the current cifoutput style */
|
||||
if (*(endptr + 1) == 'm')
|
||||
{
|
||||
switch (*endptr)
|
||||
{
|
||||
case 'n':
|
||||
mscale = 1;
|
||||
break;
|
||||
case 'u':
|
||||
mscale = 1000;
|
||||
break;
|
||||
case 'm':
|
||||
mscale = 1000000;
|
||||
break;
|
||||
case 'c':
|
||||
mscale = 10000000;
|
||||
break;
|
||||
default:
|
||||
TxError("Unknown metric prefix \"%cm\"; assuming "
|
||||
"internal units\n", *endptr);
|
||||
mscale = -1;
|
||||
}
|
||||
}
|
||||
else if ((*endptr == 'u') && !isalnum(*(endptr + 1)))
|
||||
/* Maybe "u" is too ambiguous but it is very commonly used as
|
||||
* an abbreviation for "micron".
|
||||
*/
|
||||
mscale = 1000;
|
||||
else if (!strncmp(endptr, "micron", 6))
|
||||
mscale = 1000;
|
||||
else if (!strncmp(endptr, "centimicron", 11) || !strcmp(endptr, "cu"))
|
||||
mscale = 10;
|
||||
else if (!isspace(*endptr) && (*endptr != '+') && (*endptr != '-') &&
|
||||
(*endptr != '*') && (*endptr != '/'))
|
||||
{
|
||||
TxError("Unknown coordinate type at \"%s\"; assuming internal units\n",
|
||||
endptr);
|
||||
mscale = -1;
|
||||
}
|
||||
}
|
||||
if (mscale != -1)
|
||||
dval /= CIFGetOutputScale(mscale);
|
||||
curval = round(dval);
|
||||
|
||||
switch (parseop)
|
||||
{
|
||||
case PARSEOP_NONE:
|
||||
retval = curval;
|
||||
break;
|
||||
case PARSEOP_ADD:
|
||||
retval += curval;
|
||||
break;
|
||||
case PARSEOP_SUB:
|
||||
retval -= curval;
|
||||
break;
|
||||
case PARSEOP_MUL:
|
||||
retval *= curval;
|
||||
break;
|
||||
case PARSEOP_DIV:
|
||||
retval /= curval;
|
||||
break;
|
||||
}
|
||||
|
||||
parseop = PARSEOP_NONE;
|
||||
while (*endptr != '\0')
|
||||
{
|
||||
switch (*endptr)
|
||||
{
|
||||
case 'n':
|
||||
mscale = 1;
|
||||
case '}':
|
||||
case '"':
|
||||
parseop = PARSEOP_END;
|
||||
break;
|
||||
case 'u':
|
||||
mscale = 1000;
|
||||
case '+':
|
||||
parseop = PARSEOP_ADD;
|
||||
endptr++;
|
||||
break;
|
||||
case 'm':
|
||||
mscale = 1000000;
|
||||
case '-':
|
||||
parseop = PARSEOP_SUB;
|
||||
endptr++;
|
||||
break;
|
||||
case 'c':
|
||||
mscale = 10000000;
|
||||
case '*':
|
||||
parseop = PARSEOP_MUL;
|
||||
endptr++;
|
||||
break;
|
||||
case '/':
|
||||
parseop = PARSEOP_DIV;
|
||||
endptr++;
|
||||
break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
endptr++;
|
||||
break;
|
||||
default:
|
||||
TxError("Unknown metric prefix \"%cm\"; assuming internal units\n",
|
||||
*endptr);
|
||||
return round(dval);
|
||||
/* Should this flag an error? */
|
||||
return retval;
|
||||
}
|
||||
if (parseop != PARSEOP_NONE) break;
|
||||
}
|
||||
else if (!strcmp(endptr, "u"))
|
||||
/* Maybe "u" is too ambiguous but it is very commonly used as
|
||||
* an abbreviation for "micron".
|
||||
*/
|
||||
mscale = 1000;
|
||||
else if (!strncmp(endptr, "micron", 6))
|
||||
mscale = 1000;
|
||||
else if (!strncmp(endptr, "centimicron", 11) || !strcmp(endptr, "cu"))
|
||||
mscale = 10;
|
||||
else if (!isspace(*endptr))
|
||||
{
|
||||
TxError("Unknown coordinate type \"%s\"; assuming internal units\n",
|
||||
endptr);
|
||||
return round(dval);
|
||||
}
|
||||
arg = endptr;
|
||||
while (isspace(*arg) && (*arg != '\0')) arg++;
|
||||
}
|
||||
if (!isspace(*endptr))
|
||||
dval /= CIFGetOutputScale(mscale);
|
||||
return round(dval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -653,13 +761,16 @@ cmdSaveCell(
|
|||
if (!tryRename || (fileName == NULL) || (strcmp(cellDef->cd_name, fileName) == 0))
|
||||
goto cleanup;
|
||||
|
||||
/* Rename the cell */
|
||||
if (!DBCellRenameDef(cellDef, fileName))
|
||||
/* Rename the cell, unless fileName is a .tcl file (scripted output) */
|
||||
if ((strlen(fileName) <= 4) || strcmp(fileName + strlen(fileName) - 4, ".tcl"))
|
||||
{
|
||||
/* This should never happen */
|
||||
TxError("Magic error: there is already a cell named \"%s\"\n",
|
||||
if (!DBCellRenameDef(cellDef, fileName))
|
||||
{
|
||||
/* This should never happen */
|
||||
TxError("Magic error: there is already a cell named \"%s\"\n",
|
||||
fileName);
|
||||
goto cleanup;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (EditCellUse && (cellDef == EditCellUse->cu_def))
|
||||
|
|
|
|||
217
commands/CmdTZ.c
217
commands/CmdTZ.c
|
|
@ -455,15 +455,18 @@ CmdTech(
|
|||
}
|
||||
if (!strncmp(cmd->tx_argv[2], "width", 5))
|
||||
{
|
||||
char *techwidth;
|
||||
tresult = DRCGetDefaultLayerWidth(t1);
|
||||
techwidth = DBWPrintValue(tresult, w, TRUE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult));
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techwidth, -1));
|
||||
#else
|
||||
TxPrintf("Minimum width is %d\n", tresult);
|
||||
TxPrintf("Minimum width is %s\n", techwidth);
|
||||
#endif
|
||||
}
|
||||
else if (!strncmp(cmd->tx_argv[2], "spac", 4))
|
||||
{
|
||||
char *techspace;
|
||||
if (cmd->tx_argc >= 5)
|
||||
{
|
||||
t2 = DBTechNoisyNameType(cmd->tx_argv[4]);
|
||||
|
|
@ -475,14 +478,16 @@ CmdTech(
|
|||
else
|
||||
t2 = t1;
|
||||
tresult = DRCGetDefaultLayerSpacing(t1, t2);
|
||||
techspace = DBWPrintValue(tresult, w, TRUE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult));
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techspace, -1));
|
||||
#else
|
||||
TxPrintf("Minimum spacing is %d\n", tresult);
|
||||
TxPrintf("Minimum spacing is %s\n", techspace);
|
||||
#endif
|
||||
}
|
||||
else if (!strncmp(cmd->tx_argv[2], "surr", 4))
|
||||
{
|
||||
char *techsurround;
|
||||
if (cmd->tx_argc >= 5)
|
||||
{
|
||||
t2 = DBTechNoisyNameType(cmd->tx_argv[4]);
|
||||
|
|
@ -498,14 +503,17 @@ CmdTech(
|
|||
}
|
||||
|
||||
tresult = DRCGetDefaultLayerSurround(t1, t2);
|
||||
techsurround = DBWPrintValue(tresult, w, TRUE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult));
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techsurround, -1));
|
||||
#else
|
||||
TxPrintf("Minimum surround is %d\n", tresult);
|
||||
TxPrintf("Minimum surround is %s\n", techsurround);
|
||||
#endif
|
||||
}
|
||||
else if (!strncmp(cmd->tx_argv[2], "direc", 5))
|
||||
{
|
||||
char *techdirec;
|
||||
|
||||
if (cmd->tx_argc >= 5)
|
||||
{
|
||||
t2 = DBTechNoisyNameType(cmd->tx_argv[4]);
|
||||
|
|
@ -521,10 +529,11 @@ CmdTech(
|
|||
}
|
||||
|
||||
tresult = DRCGetDirectionalLayerSurround(t1, t2);
|
||||
techdirec = DBWPrintValue(tresult, w, TRUE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult));
|
||||
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techdirec, -1));
|
||||
#else
|
||||
TxPrintf("Minimum surround (in one orientation) is %d\n", tresult);
|
||||
TxPrintf("Minimum surround (in one orientation) is %s\n", techdirec);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -754,6 +763,182 @@ cmdUnexpandFunc(
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CmdUnits --
|
||||
*
|
||||
* Implement the "units" command.
|
||||
*
|
||||
* Usage:
|
||||
* units [value] [print|noprint]
|
||||
*
|
||||
* where "value" may be one of "default", "internal", "lambda",
|
||||
* "user" (equivalently "grid"), or "microns".
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* The global variable DBWUnits may be changed, which changes the
|
||||
* behavior of magic when interpreting un-suffixed values or
|
||||
* displaying values.
|
||||
*
|
||||
* Notes:
|
||||
* The units behavior was previously dependent on what command was
|
||||
* issued, with results usually being given in internal units, and
|
||||
* with un-suffixed values following the snap behavior. Backwards-
|
||||
* compatible behavior is used on startup or at any time by setting
|
||||
* the units to "default". Otherwise, unit display follows the
|
||||
* given "units" setting.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define UNITS_DEFAULT 0
|
||||
#define UNITS_INTERNAL 1
|
||||
#define UNITS_LAMBDA 2
|
||||
#define UNITS_GRID 3
|
||||
#define UNITS_USER 4
|
||||
#define UNITS_MICRONS 5
|
||||
#define UNITS_LIST 6
|
||||
#define UNITS_PRINT 7
|
||||
#define UNITS_NOPRINT 8
|
||||
|
||||
void
|
||||
CmdUnits(
|
||||
MagWindow *w,
|
||||
TxCommand *cmd)
|
||||
{
|
||||
static const char * const names[] = { "default", "internal", "lambda",
|
||||
"grid", "user", "microns", "list", "print", "noprint", 0 };
|
||||
int idx, n = UNITS_LIST, n2, saveflag;
|
||||
DBWclientRec *crec;
|
||||
|
||||
if (cmd->tx_argc >= 2)
|
||||
{
|
||||
n = Lookup(cmd->tx_argv[1], names);
|
||||
if (n < 0)
|
||||
{
|
||||
TxPrintf("Usage: units [default | internal | lambda | microns"
|
||||
" | user] [print]\n");
|
||||
return;
|
||||
}
|
||||
if (DBWUnits != DBW_UNITS_DEFAULT)
|
||||
saveflag = DBWUnits & DBW_UNITS_PRINT_FLAG;
|
||||
else
|
||||
saveflag = -1;
|
||||
|
||||
switch (n)
|
||||
{
|
||||
case UNITS_DEFAULT:
|
||||
DBWUnits = DBW_UNITS_DEFAULT;
|
||||
break;
|
||||
case UNITS_INTERNAL:
|
||||
DBWUnits = DBW_UNITS_INTERNAL;
|
||||
break;
|
||||
case UNITS_LAMBDA:
|
||||
DBWUnits = DBW_UNITS_LAMBDA;
|
||||
break;
|
||||
case UNITS_USER:
|
||||
case UNITS_GRID:
|
||||
DBWUnits = DBW_UNITS_USER;
|
||||
break;
|
||||
case UNITS_MICRONS:
|
||||
DBWUnits = DBW_UNITS_MICRONS;
|
||||
break;
|
||||
case UNITS_PRINT:
|
||||
saveflag = DBW_UNITS_PRINT_FLAG;
|
||||
break;
|
||||
case UNITS_NOPRINT:
|
||||
saveflag = 0;
|
||||
break;
|
||||
}
|
||||
if (n < 0)
|
||||
{
|
||||
TxError("Unrecognized units option %s\n.", cmd->tx_argv[1]);
|
||||
return;
|
||||
}
|
||||
if (n != UNITS_LIST)
|
||||
{
|
||||
if ((cmd->tx_argc == 3) && (n != UNITS_DEFAULT))
|
||||
{
|
||||
n2 = Lookup(cmd->tx_argv[2], names);
|
||||
switch (n2)
|
||||
{
|
||||
case UNITS_PRINT:
|
||||
DBWUnits |= DBW_UNITS_PRINT_FLAG;
|
||||
break;
|
||||
case UNITS_NOPRINT:
|
||||
DBWUnits &= DBW_UNITS_TYPE_MASK;
|
||||
break;
|
||||
default:
|
||||
TxError("Unrecognized units option %s\n.", cmd->tx_argv[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((n != UNITS_DEFAULT) && (saveflag != -1))
|
||||
{
|
||||
/* Preserve the previous value of the print/noprint flag */
|
||||
DBWUnits &= DBW_UNITS_TYPE_MASK;
|
||||
DBWUnits |= saveflag;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (DBWUnits == DBW_UNITS_DEFAULT)
|
||||
idx = UNITS_DEFAULT;
|
||||
else
|
||||
switch (DBWUnits & DBW_UNITS_TYPE_MASK)
|
||||
{
|
||||
case DBW_UNITS_INTERNAL:
|
||||
idx = UNITS_INTERNAL;
|
||||
break;
|
||||
case DBW_UNITS_LAMBDA:
|
||||
idx = UNITS_LAMBDA;
|
||||
break;
|
||||
case DBW_UNITS_USER:
|
||||
idx = UNITS_USER;
|
||||
break;
|
||||
case DBW_UNITS_MICRONS:
|
||||
idx = UNITS_MICRONS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (n == UNITS_LIST) /* list */
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_Obj *tobj;
|
||||
tobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewStringObj((char *)names[idx], -1));
|
||||
if (idx != UNITS_DEFAULT)
|
||||
{
|
||||
if (DBWUnits & DBW_UNITS_PRINT_FLAG)
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewStringObj("print", 5));
|
||||
else
|
||||
Tcl_ListObjAppendElement(magicinterp, tobj,
|
||||
Tcl_NewStringObj("noprint", 7));
|
||||
}
|
||||
Tcl_SetObjResult(magicinterp, tobj);
|
||||
#else
|
||||
TxPrintf("%s", names[idx]);
|
||||
if (idx != UNITS_DEFAULT)
|
||||
if (DBWUnits & DBW_UNITS_PRINT_FLAG)
|
||||
TxPrintf(" print");
|
||||
TxPrintf("\n");
|
||||
#endif
|
||||
}
|
||||
else if (idx == UNITS_DEFAULT)
|
||||
TxPrintf("Reported units follow the snap setting.\n");
|
||||
else if (DBWUnits & DBW_UNITS_PRINT_FLAG)
|
||||
TxPrintf("Values are reported as %s, along with the units.\n", names[idx]);
|
||||
else
|
||||
TxPrintf("Values are reported as %s\n", names[idx]);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -1696,18 +1881,20 @@ CmdWire(
|
|||
case VALUES:
|
||||
if (locargc == 2)
|
||||
{
|
||||
char *wdisp;
|
||||
width = WireGetWidth();
|
||||
type = WireGetType();
|
||||
wdisp = DBWPrintValue(width, w, TRUE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
lobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewIntObj(width));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewStringObj(DBTypeLongNameTbl[type], -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewStringObj(wdisp, -1));
|
||||
Tcl_SetObjResult(magicinterp, lobj);
|
||||
#else
|
||||
TxPrintf("Wire layer %s, width %d\n",
|
||||
DBTypeLongNameTbl[type], width);
|
||||
TxPrintf("Wire layer %s, width %s\n",
|
||||
DBTypeLongNameTbl[type], wdisp);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
|
@ -1732,12 +1919,14 @@ CmdWire(
|
|||
case WIDTH:
|
||||
if (locargc == 2)
|
||||
{
|
||||
char *wdisp;
|
||||
width = WireGetWidth();
|
||||
wdisp = DBWPrintValue(width, w, TRUE);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
lobj = Tcl_NewIntObj(width);
|
||||
lobj = Tcl_NewStringObj(wdisp, -1);
|
||||
Tcl_SetObjResult(magicinterp, lobj);
|
||||
#else
|
||||
TxPrintf("Wire width is %d\n", width);
|
||||
TxPrintf("Wire width is %s\n", wdisp);
|
||||
#endif
|
||||
}
|
||||
else if (locargc != 3)
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ extern int cmdParseCoord(MagWindow *w, char *arg, bool is_relative, bool is_x);
|
|||
extern void cmdSaveCell(CellDef *cellDef, char *newName, bool noninteractive, bool tryRename);
|
||||
extern void CmdInit(void);
|
||||
|
||||
extern void CmdDoProperty(CellDef *def, TxCommand *cmd, int argstart);
|
||||
extern void CmdDoProperty(CellDef *def, MagWindow *w, TxCommand *cmd, int argstart);
|
||||
extern void CmdPaintEraseButton(MagWindow *w, Point *refPoint, bool isPaint, bool isScreen);
|
||||
|
||||
#endif /* _MAGIC__COMMANDS__COMMANDS_H */
|
||||
|
|
|
|||
|
|
@ -37,9 +37,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "windows/windows.h"
|
||||
#include "dbwind/dbwind.h"
|
||||
#include "commands/commands.h"
|
||||
|
||||
/* C99 compat */
|
||||
#include "graphics/graphics.h"
|
||||
#include "cif/CIFint.h"
|
||||
|
||||
/*
|
||||
* The following variable points to the tables currently used for
|
||||
|
|
@ -357,9 +356,43 @@ DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func)
|
|||
struct propUseDefStruct {
|
||||
CellDef *puds_source;
|
||||
CellDef *puds_dest;
|
||||
Plane *puds_plane; /* Mask hint plane in dest */
|
||||
Transform *puds_trans; /* Transform from source use to dest */
|
||||
Rect *puds_area; /* Clip area in source coordinates */
|
||||
};
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* dbCopyMaskHintPlaneFunc --
|
||||
*
|
||||
* Translate tiles from a child mask-hint property plane into the
|
||||
* coordinate system of the parent, and paint the mask-hint area
|
||||
* into the mask-hint property plane of the parent.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
dbCopyMaskHintPlaneFunc(Tile *tile,
|
||||
TileType dinfo,
|
||||
struct propUseDefStruct *puds)
|
||||
{
|
||||
Transform *trans = puds->puds_trans;
|
||||
Rect *clip = puds->puds_area;
|
||||
Rect r, rnew;
|
||||
Plane *plane = puds->puds_plane;
|
||||
|
||||
TiToRect(tile, &r);
|
||||
GeoClip(&r, clip);
|
||||
if (!GEO_RECTNULL(&r))
|
||||
{
|
||||
GeoTransRect(trans, &r, &rnew);
|
||||
DBPaintPlane(plane, &rnew, CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -380,63 +413,52 @@ struct propUseDefStruct {
|
|||
*/
|
||||
|
||||
int
|
||||
dbCopyMaskHintsFunc(key, value, puds)
|
||||
dbCopyMaskHintsFunc(key, proprec, puds)
|
||||
char *key;
|
||||
ClientData value;
|
||||
PropertyRecord *proprec;
|
||||
struct propUseDefStruct *puds;
|
||||
{
|
||||
CellDef *dest = puds->puds_dest;
|
||||
Transform *trans = puds->puds_trans;
|
||||
char *propstr = (char *)value;
|
||||
Rect *clip = puds->puds_area;
|
||||
PropertyRecord *parentproprec, *newproprec;
|
||||
char *parentprop, *newvalue, *vptr;
|
||||
Rect r, rnew;
|
||||
bool propfound;
|
||||
int i, j;
|
||||
|
||||
if (!strncmp(key, "MASKHINTS_", 10))
|
||||
{
|
||||
char *vptr, *lastval;
|
||||
int lastlen;
|
||||
Plane *plane;
|
||||
|
||||
/* Append to existing mask hint (if any) */
|
||||
parentprop = (char *)DBPropGet(dest, key, &propfound);
|
||||
newvalue = (propfound) ? StrDup((char **)NULL, parentprop) : (char *)NULL;
|
||||
ASSERT(proprec->prop_type == PROPERTY_TYPE_PLANE, "dbCopyMaskHintsFunc");
|
||||
|
||||
vptr = propstr;
|
||||
while (*vptr != '\0')
|
||||
/* Get the existing mask hint plane in the parent cell, and
|
||||
* create it if it does not already exist.
|
||||
*/
|
||||
parentproprec = (PropertyRecord *)DBPropGet(dest, key, &propfound);
|
||||
|
||||
if (propfound)
|
||||
plane = parentproprec->prop_value.prop_plane;
|
||||
else
|
||||
{
|
||||
if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
|
||||
&r.r_xtop, &r.r_ytop) == 4)
|
||||
{
|
||||
GeoTransRect(trans, &r, &rnew);
|
||||
|
||||
lastval = newvalue;
|
||||
lastlen = (lastval) ? strlen(lastval) : 0;
|
||||
newvalue = mallocMagic(40 + lastlen);
|
||||
|
||||
if (lastval)
|
||||
strcpy(newvalue, lastval);
|
||||
else
|
||||
*newvalue = '\0';
|
||||
|
||||
sprintf(newvalue + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
|
||||
rnew.r_xbot, rnew.r_ybot, rnew.r_xtop, rnew.r_ytop);
|
||||
if (lastval) freeMagic(lastval);
|
||||
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
}
|
||||
else break;
|
||||
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||
newproprec->prop_type = PROPERTY_TYPE_PLANE;
|
||||
newproprec->prop_len = 0;
|
||||
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||
newproprec->prop_value.prop_plane = plane;
|
||||
DBPropPut(dest, key, newproprec);
|
||||
}
|
||||
if (newvalue)
|
||||
DBPropPut(dest, key, newvalue);
|
||||
}
|
||||
puds->puds_plane = plane;
|
||||
|
||||
/* Copy the properties from child to parent */
|
||||
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||
proprec->prop_value.prop_plane,
|
||||
clip, &CIFSolidBits, dbCopyMaskHintPlaneFunc,
|
||||
(ClientData)puds);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -468,6 +490,7 @@ DBCellCopyMaskHints(child, parent, transform)
|
|||
puds.puds_source = child->cu_def;
|
||||
puds.puds_dest = parent;
|
||||
puds.puds_trans = transform;
|
||||
puds.puds_area = (Rect *)&TiPlaneRect;
|
||||
DBPropEnum(child->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
|
||||
}
|
||||
|
||||
|
|
@ -501,6 +524,7 @@ dbFlatCopyMaskHintsFunc(scx, def)
|
|||
puds.puds_source = scx->scx_use->cu_def;
|
||||
puds.puds_dest = def;
|
||||
puds.puds_trans = &scx->scx_trans;
|
||||
puds.puds_area = &scx->scx_area;
|
||||
|
||||
DBPropEnum(use->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
|
||||
|
||||
|
|
|
|||
|
|
@ -152,10 +152,9 @@ DBCellRename(cellname, newname, doforce)
|
|||
|
||||
if (doforce && ((celldef->cd_flags & CDVENDORGDS) == CDVENDORGDS))
|
||||
{
|
||||
char *chkgdsfile;
|
||||
bool isReadOnly;
|
||||
|
||||
chkgdsfile = (char *)DBPropGet(celldef, "GDS_FILE", &isReadOnly);
|
||||
DBPropGet(celldef, "GDS_FILE", &isReadOnly);
|
||||
/* Note that clearing GDS_FILE will also clear CDVENDORGDS flag */
|
||||
if (isReadOnly) DBPropPut(celldef, "GDS_FILE", NULL);
|
||||
|
||||
|
|
@ -1620,7 +1619,9 @@ dbAbutmentUseFunc(selUse, use, transform, data)
|
|||
{
|
||||
Rect bbox, refbox;
|
||||
Transform *trans;
|
||||
PropertyRecord *proprec;
|
||||
char *propvalue;
|
||||
char *refllx, *reflly, *refurx, *refury;
|
||||
bool found;
|
||||
bool *dolist = (bool *)data;
|
||||
|
||||
|
|
@ -1642,32 +1643,47 @@ dbAbutmentUseFunc(selUse, use, transform, data)
|
|||
}
|
||||
|
||||
trans = &use->cu_transform;
|
||||
propvalue = (char *)DBPropGet(use->cu_def, "FIXED_BBOX", &found);
|
||||
proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
|
||||
if (!found)
|
||||
bbox = use->cu_def->cd_bbox;
|
||||
else
|
||||
{
|
||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
||||
&bbox.r_xtop, &bbox.r_ytop) != 4)
|
||||
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||
(proprec->prop_len == 4))
|
||||
{
|
||||
bbox.r_xbot = proprec->prop_value.prop_integer[0];
|
||||
bbox.r_ybot = proprec->prop_value.prop_integer[1];
|
||||
bbox.r_xtop = proprec->prop_value.prop_integer[2];
|
||||
bbox.r_ytop = proprec->prop_value.prop_integer[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
TxError("Unable to parse the cell's FIXED_BBOX property; using "
|
||||
"the instance bounding box instead.\n");
|
||||
bbox = use->cu_def->cd_bbox;
|
||||
}
|
||||
}
|
||||
GeoTransRect(trans, &bbox, &refbox);
|
||||
|
||||
/* NOTE: Ideally, the MagWindow pointer should get passed to this routine */
|
||||
refllx = DBWPrintValue(refbox.r_xbot, (MagWindow *)NULL, TRUE);
|
||||
reflly = DBWPrintValue(refbox.r_ybot, (MagWindow *)NULL, FALSE);
|
||||
refurx = DBWPrintValue(refbox.r_xtop, (MagWindow *)NULL, TRUE);
|
||||
refury = DBWPrintValue(refbox.r_ytop, (MagWindow *)NULL, FALSE);
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
if (*dolist)
|
||||
{
|
||||
pobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_xbot));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_ybot));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_xtop));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_ytop));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refllx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(reflly, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refurx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refury, -1));
|
||||
Tcl_SetObjResult(magicinterp, pobj);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
TxPrintf("Abutment box: %d %d %d %d\n", refbox.r_xbot, refbox.r_ybot,
|
||||
refbox.r_xtop, refbox.r_ytop);
|
||||
|
||||
TxPrintf("Abutment box: %s %s %s %s\n", refllx, reflly, refurx, refury);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1713,7 +1713,7 @@ dbTileMoveFunc(tile, dinfo, mvvals)
|
|||
if (IsSplit(tile))
|
||||
type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
|
||||
DBNMPaintPlane(mvvals->ptarget, exact, &targetRect,
|
||||
DBStdPaintTbl(type, mvvals->pnum),
|
||||
(mvvals->pnum < 0) ? CIFPaintTable : DBStdPaintTbl(type, mvvals->pnum),
|
||||
(PaintUndoInfo *)NULL);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1806,84 +1806,48 @@ typedef struct _cellpropstruct {
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int dbScaleProp(name, value, cps)
|
||||
int dbScaleProp(name, proprec, cps)
|
||||
char *name;
|
||||
char *value;
|
||||
PropertyRecord *proprec;
|
||||
CellPropStruct *cps;
|
||||
{
|
||||
int scalen, scaled;
|
||||
char *newvalue, *vptr;
|
||||
Rect r;
|
||||
int i, scalen, scaled;
|
||||
Point p;
|
||||
|
||||
if ((strlen(name) > 5) && !strncmp(name + strlen(name) - 5, "_BBOX", 5))
|
||||
/* Only "dimension" and "plane" type properties get scaled */
|
||||
|
||||
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
|
||||
{
|
||||
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
|
||||
&r.r_xtop, &r.r_ytop) == 4)
|
||||
{
|
||||
/* Scale numerator held in point X value, */
|
||||
/* scale denominator held in point Y value */
|
||||
|
||||
scalen = cps->cps_point.p_x;
|
||||
scaled = cps->cps_point.p_y;
|
||||
|
||||
DBScalePoint(&r.r_ll, scalen, scaled);
|
||||
DBScalePoint(&r.r_ur, scalen, scaled);
|
||||
|
||||
newvalue = (char *)mallocMagic(40);
|
||||
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
|
||||
r.r_xtop, r.r_ytop);
|
||||
DBPropPut(cps->cps_def, name, newvalue);
|
||||
}
|
||||
Plane *newplane;
|
||||
newplane = DBNewPlane((ClientData)TT_SPACE);
|
||||
DBClearPaintPlane(newplane);
|
||||
/* Plane index is unused; arbitrarily substitute -1 */
|
||||
dbScalePlane(proprec->prop_value.prop_plane, newplane, -1,
|
||||
scalen, scaled, TRUE);
|
||||
DBFreePaintPlane(proprec->prop_value.prop_plane);
|
||||
TiFreePlane(proprec->prop_value.prop_plane);
|
||||
proprec->prop_value.prop_plane = newplane;
|
||||
return 0;
|
||||
}
|
||||
else if (!strncmp(name, "MASKHINTS_", 10))
|
||||
|
||||
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
|
||||
|
||||
/* Scale numerator held in point X value, */
|
||||
/* scale denominator held in point Y value */
|
||||
scalen = cps->cps_point.p_x;
|
||||
scaled = cps->cps_point.p_y;
|
||||
|
||||
for (i = 0; i < proprec->prop_len; i += 2)
|
||||
{
|
||||
char *vptr, *lastval;
|
||||
int lastlen;
|
||||
if ((i + 1) >= proprec->prop_len) break;
|
||||
|
||||
newvalue = (char *)NULL;
|
||||
vptr = value;
|
||||
while (*vptr != '\0')
|
||||
{
|
||||
if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
|
||||
&r.r_xtop, &r.r_ytop) == 4)
|
||||
{
|
||||
/* Scale numerator held in point X value, */
|
||||
/* scale denominator held in point Y value */
|
||||
|
||||
scalen = cps->cps_point.p_x;
|
||||
scaled = cps->cps_point.p_y;
|
||||
|
||||
DBScalePoint(&r.r_ll, scalen, scaled);
|
||||
DBScalePoint(&r.r_ur, scalen, scaled);
|
||||
|
||||
lastval = newvalue;
|
||||
lastlen = (lastval) ? strlen(lastval) : 0;
|
||||
newvalue = mallocMagic(40 + lastlen);
|
||||
|
||||
if (lastval)
|
||||
strcpy(newvalue, lastval);
|
||||
else
|
||||
*newvalue = '\0';
|
||||
|
||||
sprintf(newvalue + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
|
||||
r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
|
||||
if (lastval) freeMagic(lastval);
|
||||
|
||||
/* Parse through the four values and check if there's more */
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
while (*vptr && !isspace(*vptr)) vptr++;
|
||||
while (*vptr && isspace(*vptr)) vptr++;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
if (newvalue)
|
||||
DBPropPut(cps->cps_def, name, newvalue);
|
||||
p.p_x = proprec->prop_value.prop_integer[i];
|
||||
p.p_y = proprec->prop_value.prop_integer[i + 1];
|
||||
DBScalePoint(&p, scalen, scaled);
|
||||
proprec->prop_value.prop_integer[i] = p.p_x;
|
||||
proprec->prop_value.prop_integer[i + 1] = p.p_y;
|
||||
}
|
||||
|
||||
return 0; /* Keep enumerating through properties */
|
||||
}
|
||||
|
||||
|
|
@ -1899,33 +1863,47 @@ int dbScaleProp(name, value, cps)
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int dbMoveProp(name, value, cps)
|
||||
int dbMoveProp(name, proprec, cps)
|
||||
char *name;
|
||||
char *value;
|
||||
PropertyRecord *proprec;
|
||||
CellPropStruct *cps;
|
||||
{
|
||||
int origx, origy;
|
||||
int i, origx, origy;
|
||||
char *newvalue;
|
||||
Rect r;
|
||||
Point p;
|
||||
|
||||
if (((strlen(name) > 5) && !strncmp(name + strlen(name) - 5, "_BBOX", 5))
|
||||
|| !strncmp(name, "MASKHINTS_", 10))
|
||||
/* Only "dimension" and "plane" type properties get scaled */
|
||||
|
||||
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
|
||||
{
|
||||
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
|
||||
&r.r_xtop, &r.r_ytop) == 4)
|
||||
{
|
||||
origx = cps->cps_point.p_x;
|
||||
origy = cps->cps_point.p_y;
|
||||
Plane *newplane;
|
||||
|
||||
DBMovePoint(&r.r_ll, origx, origy);
|
||||
DBMovePoint(&r.r_ur, origx, origy);
|
||||
|
||||
newvalue = (char *)mallocMagic(40);
|
||||
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
|
||||
r.r_xtop, r.r_ytop);
|
||||
DBPropPut(cps->cps_def, name, newvalue);
|
||||
}
|
||||
newplane = DBNewPlane((ClientData) TT_SPACE);
|
||||
DBClearPaintPlane(newplane);
|
||||
/* Use plane index -1 to indicate use of CIFPaintTable */
|
||||
dbMovePlane(proprec->prop_value.prop_plane, newplane, -1, origx, origy);
|
||||
DBFreePaintPlane(proprec->prop_value.prop_plane);
|
||||
TiFreePlane(proprec->prop_value.prop_plane);
|
||||
proprec->prop_value.prop_plane = newplane;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
|
||||
|
||||
origx = cps->cps_point.p_x;
|
||||
origy = cps->cps_point.p_y;
|
||||
|
||||
for (i = 0; i < proprec->prop_len; i += 2)
|
||||
{
|
||||
if ((i + 1) >= proprec->prop_len) break;
|
||||
|
||||
p.p_x = proprec->prop_value.prop_integer[i];
|
||||
p.p_y = proprec->prop_value.prop_integer[i + 1];
|
||||
DBMovePoint(&p, origx, origy);
|
||||
proprec->prop_value.prop_integer[i] = p.p_x;
|
||||
proprec->prop_value.prop_integer[i + 1] = p.p_y;
|
||||
}
|
||||
|
||||
return 0; /* Keep enumerating through properties */
|
||||
}
|
||||
|
||||
|
|
|
|||
1053
database/DBio.c
1053
database/DBio.c
File diff suppressed because it is too large
Load Diff
|
|
@ -32,6 +32,16 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "database/database.h"
|
||||
#include "utils/malloc.h"
|
||||
|
||||
/* Global variable */
|
||||
|
||||
bool DBPropCompat = TRUE; /* If TRUE, then always save properties to
|
||||
* .mag files as type "string" for backwards
|
||||
* compatibility. If FALSE, then properties
|
||||
* are saved to the .mag file along with their
|
||||
* type. Regardless of the setting, properties
|
||||
* which are reserved keywords are converted
|
||||
* to the best internal representation on input.
|
||||
*/
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -47,16 +57,16 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
|
||||
void
|
||||
DBPropPut(cellDef, name, value)
|
||||
CellDef *cellDef; /* Pointer to definition of cell. */
|
||||
char *name; /* The name of the property desired. */
|
||||
ClientData value; /* MUST point to a malloc'ed structure, or NULL.
|
||||
* This will be freed when the CellDef is freed.
|
||||
*/
|
||||
CellDef *cellDef; /* Pointer to definition of cell. */
|
||||
char *name; /* The name of the property desired. */
|
||||
PropertyRecord *value; /* MUST point to a malloc'ed structure, or NULL.
|
||||
* This will be freed when the CellDef is freed.
|
||||
*/
|
||||
|
||||
{
|
||||
HashTable *htab;
|
||||
HashEntry *entry;
|
||||
char *oldvalue;
|
||||
PropertyRecord *oldvalue;
|
||||
|
||||
/* Honor the NOEDIT flag. Note that the caller always assumes that */
|
||||
/* the value would be saved in the hash table, so if it is not */
|
||||
|
|
@ -95,12 +105,23 @@ DBPropPut(cellDef, name, value)
|
|||
}
|
||||
|
||||
entry = HashFind(htab, name);
|
||||
oldvalue = (char *)HashGetValue(entry);
|
||||
if (oldvalue != NULL) freeMagic(oldvalue);
|
||||
if (value == (ClientData)NULL)
|
||||
oldvalue = (PropertyRecord *)HashGetValue(entry);
|
||||
/* All properties are allocated as a single block and can just be freed,
|
||||
* except for plane properties, which require freeing the plane.
|
||||
*/
|
||||
if (oldvalue != NULL)
|
||||
{
|
||||
if (oldvalue->prop_type == PROPERTY_TYPE_PLANE)
|
||||
{
|
||||
DBFreePaintPlane(oldvalue->prop_value.prop_plane);
|
||||
TiFreePlane(oldvalue->prop_value.prop_plane);
|
||||
}
|
||||
freeMagic((char *)oldvalue);
|
||||
}
|
||||
if (value == (PropertyRecord *)NULL)
|
||||
HashRemove(htab, name);
|
||||
else
|
||||
HashSetValue(entry, value);
|
||||
HashSetValue(entry, PTR2CD(value));
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
|
|
@ -110,13 +131,13 @@ DBPropPut(cellDef, name, value)
|
|||
* Get a property from a celldef.
|
||||
*
|
||||
* Results:
|
||||
* NULL if the property didn't exist, or if the property value was NULL.
|
||||
* Otherwise, ClientData that represents the property.
|
||||
* NULL if the property didn't exist, or if the property record was NULL.
|
||||
* Otherwise, returns a pointer to the property record.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
ClientData
|
||||
PropertyRecord *
|
||||
DBPropGet(cellDef, name, found)
|
||||
CellDef *cellDef; /* Pointer to definition of cell. */
|
||||
char *name; /* The name of the property desired. */
|
||||
|
|
@ -124,12 +145,12 @@ DBPropGet(cellDef, name, found)
|
|||
* exists.
|
||||
*/
|
||||
{
|
||||
ClientData result;
|
||||
PropertyRecord *result;
|
||||
bool haveit;
|
||||
HashTable *htab;
|
||||
HashEntry *entry;
|
||||
|
||||
result = (ClientData) NULL;
|
||||
result = (PropertyRecord *)NULL;
|
||||
haveit = FALSE;
|
||||
htab = (HashTable *) cellDef->cd_props;
|
||||
if (htab == (HashTable *) NULL) goto done;
|
||||
|
|
@ -138,7 +159,7 @@ DBPropGet(cellDef, name, found)
|
|||
if (entry != NULL)
|
||||
{
|
||||
haveit = TRUE;
|
||||
result = (ClientData) HashGetValue(entry);
|
||||
result = (PropertyRecord *)HashGetValue(entry);
|
||||
}
|
||||
|
||||
done:
|
||||
|
|
@ -146,6 +167,109 @@ done:
|
|||
return result;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
*
|
||||
* DBPropGetString --
|
||||
*
|
||||
* Get a string property from a celldef.
|
||||
*
|
||||
* Results:
|
||||
* NULL if the property didn't exist, or if the property record was NULL.
|
||||
* Otherwise, returns a pointer to the property's string record.
|
||||
*
|
||||
* Notes:
|
||||
* This is basically the original DBPropGet(), when properties were only
|
||||
* allowed to be strings.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
DBPropGetString(cellDef, name, found)
|
||||
CellDef *cellDef; /* Pointer to definition of cell. */
|
||||
char *name; /* The name of the property desired. */
|
||||
bool *found; /* If not NULL, filled in with TRUE iff the property
|
||||
* exists.
|
||||
*/
|
||||
{
|
||||
char *result = NULL;
|
||||
PropertyRecord *proprec;
|
||||
bool haveit;
|
||||
HashTable *htab;
|
||||
HashEntry *entry;
|
||||
|
||||
haveit = FALSE;
|
||||
htab = (HashTable *) cellDef->cd_props;
|
||||
if (htab == (HashTable *) NULL) goto pdone;
|
||||
|
||||
entry = HashLookOnly(htab, name);
|
||||
if (entry != NULL)
|
||||
{
|
||||
proprec = (PropertyRecord *)HashGetValue(entry);
|
||||
if (proprec->prop_type == PROPERTY_TYPE_STRING)
|
||||
{
|
||||
haveit = TRUE;
|
||||
result = proprec->prop_value.prop_string;
|
||||
}
|
||||
}
|
||||
|
||||
pdone:
|
||||
if (found != (bool *) NULL) *found = haveit;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
*
|
||||
* DBPropGetDouble --
|
||||
*
|
||||
* Get a single double-long integer property from a celldef.
|
||||
*
|
||||
* Results:
|
||||
* NULL if the property didn't exist, or if the property record was NULL.
|
||||
* Otherwise, returns a pointer to the property's value record.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
dlong
|
||||
DBPropGetDouble(cellDef, name, found)
|
||||
CellDef *cellDef; /* Pointer to definition of cell. */
|
||||
char *name; /* The name of the property desired. */
|
||||
bool *found; /* If not NULL, filled in with TRUE iff the property
|
||||
* exists.
|
||||
*/
|
||||
{
|
||||
dlong result = 0;
|
||||
PropertyRecord *proprec;
|
||||
bool haveit;
|
||||
HashTable *htab;
|
||||
HashEntry *entry;
|
||||
|
||||
haveit = FALSE;
|
||||
htab = (HashTable *) cellDef->cd_props;
|
||||
if (htab == (HashTable *) NULL) goto ddone;
|
||||
|
||||
entry = HashLookOnly(htab, name);
|
||||
if (entry != NULL)
|
||||
{
|
||||
proprec = (PropertyRecord *)HashGetValue(entry);
|
||||
if (proprec->prop_type == PROPERTY_TYPE_DOUBLE)
|
||||
{
|
||||
haveit = TRUE;
|
||||
result = proprec->prop_value.prop_double[0];
|
||||
}
|
||||
else if (proprec->prop_type == PROPERTY_TYPE_STRING)
|
||||
{
|
||||
haveit = TRUE;
|
||||
sscanf(proprec->prop_value.prop_string, "%"DLONG_PREFIX"d", &result);
|
||||
}
|
||||
}
|
||||
|
||||
ddone:
|
||||
if (found != (bool *) NULL) *found = haveit;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
*
|
||||
* DBPropEnum --
|
||||
|
|
@ -168,7 +292,7 @@ DBPropEnum(cellDef, func, cdata)
|
|||
*
|
||||
* int foo(name, value, cdata)
|
||||
* char *name;
|
||||
* ClientData value;
|
||||
* PropertyRecord *value;
|
||||
* ClientData cdata;
|
||||
* {
|
||||
* -- return 0 to continue,
|
||||
|
|
@ -189,7 +313,7 @@ DBPropEnum(cellDef, func, cdata)
|
|||
HashStartSearch(&hs);
|
||||
while ((entry = HashNext(htab, &hs)) != NULL)
|
||||
{
|
||||
res = (*func)(entry->h_key.h_name, (ClientData) entry->h_pointer, cdata);
|
||||
res = (*func)(entry->h_key.h_name, (PropertyRecord *)entry->h_pointer, cdata);
|
||||
if (res != 0) return res;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -303,9 +303,14 @@ typedef struct label
|
|||
#define PORT_SHAPE_RING 0x1000 /* Port is a ring shape */
|
||||
#define PORT_SHAPE_THRU 0x1800 /* Port is a feedthrough shape */
|
||||
|
||||
#define PORT_VISITED 0x2000 /* Bit for checking if a port */
|
||||
#define LABEL_STICKY 0x2000 /* Label does not change layers */
|
||||
#define LABEL_UNIQUE 0x4000 /* Temporary unique label */
|
||||
|
||||
/* The last two flags are never used at the same time and so can share
|
||||
* a flag bit.
|
||||
*/
|
||||
#define PORT_VISITED 0x8000 /* Bit for checking if a port */
|
||||
/* has been previously visited. */
|
||||
#define LABEL_STICKY 0x4000 /* Label does not change layers */
|
||||
#define LABEL_GENERATE 0x8000 /* Auto-generated label */
|
||||
|
||||
/*
|
||||
|
|
@ -699,6 +704,25 @@ struct conSrArg2
|
|||
|
||||
#define CSA2_LIST_SIZE 65536 /* Number of entries per list */
|
||||
|
||||
/* ------------------------ Properties ------------------------------ */
|
||||
|
||||
/* Note that the property record is a single allocated block large enough
|
||||
* to hold the string or integer list, and can be freed as a single block.
|
||||
* The array bounds, like those of lab_text for labels, are placeholders.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int prop_type; /* See codes below; e.g., PROPERTY_TYPE_STRING */
|
||||
int prop_len; /* String length or number of values */
|
||||
union {
|
||||
char prop_string[8]; /* For PROPERTY_TYPE_STRING */
|
||||
int prop_integer[2]; /* For PROPERTY_TYPE_INTEGER or _DIMENSION */
|
||||
dlong prop_double[1]; /* For PROPERTY_TYPE_DOUBLE */
|
||||
Plane *prop_plane; /* For PROPERTY_TYPE_PLANE */
|
||||
} prop_value;
|
||||
} PropertyRecord;
|
||||
|
||||
/* -------------- Undo information passed to DBPaintPlane ------------- */
|
||||
|
||||
typedef struct
|
||||
|
|
@ -731,6 +755,14 @@ typedef struct
|
|||
#define PAINT_MARK 1 /* Mark tiles that are painted */
|
||||
#define PAINT_XOR 2 /* Use with XOR function to prevent double-painting */
|
||||
|
||||
/* ---------------------- Codes for properties -------------------------*/
|
||||
|
||||
#define PROPERTY_TYPE_STRING 0 /* ASCII string property */
|
||||
#define PROPERTY_TYPE_INTEGER 1 /* Fixed integer property */
|
||||
#define PROPERTY_TYPE_DIMENSION 2 /* Integer property that scales with units */
|
||||
#define PROPERTY_TYPE_DOUBLE 3 /* Double-long integer (for file positions) */
|
||||
#define PROPERTY_TYPE_PLANE 4 /* A tile plane structure */
|
||||
|
||||
/* -------------------- Exported procedure headers -------------------- */
|
||||
|
||||
/* Painting/erasing */
|
||||
|
|
@ -916,7 +948,9 @@ extern void DBFreePaintPlane();
|
|||
|
||||
/* Cell properties */
|
||||
extern void DBPropPut();
|
||||
extern ClientData DBPropGet();
|
||||
extern PropertyRecord *DBPropGet();
|
||||
extern char *DBPropGetString();
|
||||
extern dlong DBPropGetDouble();
|
||||
extern int DBPropEnum();
|
||||
extern void DBPropClearAll();
|
||||
|
||||
|
|
@ -1014,6 +1048,7 @@ extern int DBLambda[2];
|
|||
/* -------------------- Exported magic file suffix -------------------- */
|
||||
|
||||
extern char *DBSuffix; /* Suffix appended to all Magic cell names */
|
||||
extern bool DBPropCompat; /* Backwards-compatible properties */
|
||||
|
||||
/* -------------------- User Interface Stuff -------------------------- */
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ extern void CmdRandom(), CmdSave(), CmdScaleGrid(), CmdSee();
|
|||
extern void CmdSelect(), CmdSetLabel(), CmdSideways();
|
||||
extern void CmdShell(), CmdSnap();
|
||||
extern void CmdStretch(), CmdStraighten();
|
||||
extern void CmdTech(), CmdTool(), CmdUnexpand();
|
||||
extern void CmdTech(), CmdTool(), CmdUnexpand(), CmdUnits();
|
||||
extern void CmdUpsidedown(), CmdWhat(), CmdWire(), CmdWriteall();
|
||||
extern void CmdGoto(), CmdFlatten(), CmdXload(), CmdXor();
|
||||
|
||||
|
|
@ -474,6 +474,9 @@ DBWInitCommands()
|
|||
WindAddCommand(DBWclientID,
|
||||
"unexpand unexpand subcells under box",
|
||||
CmdUnexpand, FALSE);
|
||||
WindAddCommand(DBWclientID,
|
||||
"units [type] set type of units parsed and displayed",
|
||||
CmdUnits, FALSE);
|
||||
WindAddCommand(DBWclientID,
|
||||
"upsidedown flip selection and box upside down",
|
||||
CmdUpsidedown, FALSE);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/main.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
|
|
@ -33,6 +34,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/hash.h"
|
||||
#include "database/database.h"
|
||||
#include "utils/main.h"
|
||||
#include "cif/cif.h"
|
||||
#include "commands/commands.h"
|
||||
#include "dbwind/dbwind.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
|
@ -653,6 +655,311 @@ DBWexit()
|
|||
return (CmdWarnWrite() == 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* dbwValueFormat ---
|
||||
*
|
||||
* Remove unnecessary trailing zeros and decimal from a floating-point
|
||||
* value formatted with "%.Nf" where N is the expected maximum number
|
||||
* of places after the decimal, matching the argument "places".
|
||||
* This makes the "%f" formatting work like "%g" formatting, but
|
||||
* works around the limitation of "%.Ng" that it operates on the number
|
||||
* of significant digits, not the number of decimal places.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* The string "buf" may be altered with a new terminating null character.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
dbwValueFormat(char *buf,
|
||||
int places)
|
||||
{
|
||||
char *p = buf + strlen(buf) - 1;
|
||||
while (p > buf && *p == '0') *p-- = '\0';
|
||||
if (p > buf && *p == '.') *p = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* dbwPrintValue0 --
|
||||
*
|
||||
* Convert a value in internal database units to a string based on
|
||||
* the chosen display units as defined by DBWUnits (which is set
|
||||
* with the "units" command). If DBWUnits has not been changed
|
||||
* since startup, then the behavior is to print the internal units
|
||||
* in string form. If DBWUnits has been set, then the units type
|
||||
* determines how the output is displayed.
|
||||
*
|
||||
* If "is_square" is TRUE, then the value is in units squared, and
|
||||
* scaling is done accordingly. In the case of DBW_UNITS_USER,
|
||||
* where values are in grid multiples, the units for X and Y may
|
||||
* differ, and "is_x" = TRUE indicates a measurement in the X direction,
|
||||
* while false indicase a measurements in the Y direction. Naturally,
|
||||
* if "is_square" is TRUE then "is_x" is ignored. "is_x" is also ignored
|
||||
* for any output units other than user/grid units.
|
||||
*
|
||||
* If "is_cif" is true, then "value" is in CIF database units
|
||||
* (centimicrons, nanometers, or angstroms, according to the
|
||||
* scalefactor line in the tech file), rather than internal units.
|
||||
*
|
||||
* This routine is generally meant to be called as one of the three
|
||||
* variants defined below it: DBWPrintValue(), DBWPrintSqValue(),
|
||||
* or DBWPrintCIFValue().
|
||||
*
|
||||
* Results:
|
||||
* A pointer to a string. To facilitate printing up to four values
|
||||
* (e.g., rectangle coordinates, such as from "box values"), a static
|
||||
* string partitioned into four parts is created in this subroutine,
|
||||
* and the result points to one position in the string, which is cycled
|
||||
* through every four calls to the subroutine. The caller does not
|
||||
* free the returned string.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* NOTE: Prior to the introduction of the "units" command, magic had the
|
||||
* inconsistent behavior that parsed input values on the command line
|
||||
* would be interpreted per the "snap" setting, but output values were
|
||||
* (almost) always given in internal units. This routine keeps the
|
||||
* original behavior backwards-compatible, as inconsistent as it is.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
dbwPrintValue0(int value, /* value to print, in internal units */
|
||||
MagWindow *w, /* current window, for use with grid */
|
||||
bool is_x, /* TRUE if value is an X dimension */
|
||||
bool is_square, /* TRUE if value is a dimension squared */
|
||||
bool is_cif) /* TRUE if value is in centimicrons */
|
||||
{
|
||||
char *result;
|
||||
float oscale, dscale, fvalue;
|
||||
DBWclientRec *crec;
|
||||
int locunits;
|
||||
|
||||
/* This routine is called often, so avoid constant use of malloc and
|
||||
* free by keeping up to four printed results in static memory.
|
||||
*/
|
||||
static char resultstr[128];
|
||||
static unsigned char resultpos = 0;
|
||||
|
||||
result = &resultstr[resultpos];
|
||||
resultpos += 32;
|
||||
resultpos &= 127; /* At 128, cycle back to zero */
|
||||
|
||||
/* CIF database units are centimicrons/nanometers/angstroms as
|
||||
* set by the "scalefactor" line in the tech file. When "is_cif"
|
||||
* is TRUE, then "value" is in these units. Find the conversion
|
||||
* factor to convert "value" to internal units, and then it can
|
||||
* be subsequently converted to lambda, microns, etc.
|
||||
*/
|
||||
if (is_cif == TRUE)
|
||||
dscale = CIFGetScale(100) / CIFGetOutputScale(1000);
|
||||
else
|
||||
dscale = 1.0;
|
||||
|
||||
/* When printing user/grid units, check for a valid window */
|
||||
|
||||
locunits = DBWUnits;
|
||||
if (locunits != DBW_UNITS_DEFAULT) locunits &= DBW_UNITS_TYPE_MASK;
|
||||
|
||||
/* The MagWindow argument is only needed for user units, since the
|
||||
* user grid values are found there. Setting MagWindow to NULL
|
||||
* effectively disables printing values in user grid units, which
|
||||
* then default to internal units.
|
||||
*/
|
||||
if (locunits == DBW_UNITS_USER)
|
||||
{
|
||||
if (w == (MagWindow *)NULL)
|
||||
{
|
||||
windCheckOnlyWindow(&w, DBWclientID);
|
||||
if (w == (MagWindow *)NULL)
|
||||
locunits = DBW_UNITS_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
switch (locunits)
|
||||
{
|
||||
case DBW_UNITS_DEFAULT:
|
||||
snprintf(result, 32, "%d", value);
|
||||
break;
|
||||
|
||||
case DBW_UNITS_INTERNAL:
|
||||
if (is_cif)
|
||||
{
|
||||
if (is_square)
|
||||
{
|
||||
snprintf(result, 32, "%.6f", value * dscale * dscale);
|
||||
dbwValueFormat(result, 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(result, 32, "%.3f", value * dscale);
|
||||
dbwValueFormat(result, 3);
|
||||
}
|
||||
}
|
||||
else
|
||||
snprintf(result, 32, "%d", value);
|
||||
if (is_square)
|
||||
{
|
||||
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 29))
|
||||
strcat(result, "i^2");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 31))
|
||||
strcat(result, "i");
|
||||
}
|
||||
break;
|
||||
|
||||
case DBW_UNITS_LAMBDA:
|
||||
|
||||
oscale = (float)DBLambda[0];
|
||||
oscale /= (float)DBLambda[1];
|
||||
if (is_square)
|
||||
{
|
||||
fvalue = (float)value * oscale * oscale * dscale * dscale;
|
||||
snprintf(result, 32, "%0.6f", (double)fvalue);
|
||||
dbwValueFormat(result, 6);
|
||||
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 29))
|
||||
strcat(result, "l^2");
|
||||
}
|
||||
else
|
||||
{
|
||||
fvalue = (float)value * oscale * dscale;
|
||||
snprintf(result, 32, "%0.3f", (double)fvalue);
|
||||
dbwValueFormat(result, 3);
|
||||
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 31))
|
||||
strcat(result, "l");
|
||||
}
|
||||
break;
|
||||
|
||||
case DBW_UNITS_MICRONS:
|
||||
oscale = CIFGetOutputScale(1000);
|
||||
if (is_square)
|
||||
{
|
||||
fvalue = (float)value * oscale * oscale * dscale * dscale;
|
||||
snprintf(result, 32, "%0.6f", (double)fvalue);
|
||||
dbwValueFormat(result, 6);
|
||||
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 28))
|
||||
strcat(result, "um^2");
|
||||
}
|
||||
else
|
||||
{
|
||||
fvalue = (float)value * oscale * dscale;
|
||||
snprintf(result, 32, "%0.3f", (double)fvalue);
|
||||
dbwValueFormat(result, 3);
|
||||
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 30))
|
||||
strcat(result, "um");
|
||||
}
|
||||
break;
|
||||
|
||||
case DBW_UNITS_USER:
|
||||
if (is_square)
|
||||
{
|
||||
oscale = (float)((crec->dbw_gridRect.r_xtop -
|
||||
crec->dbw_gridRect.r_xbot) *
|
||||
(crec->dbw_gridRect.r_ytop -
|
||||
crec->dbw_gridRect.r_ybot));
|
||||
}
|
||||
else if (is_x)
|
||||
{
|
||||
oscale = (float)(crec->dbw_gridRect.r_xtop -
|
||||
crec->dbw_gridRect.r_xbot);
|
||||
}
|
||||
else
|
||||
{
|
||||
oscale = (float)(crec->dbw_gridRect.r_ytop -
|
||||
crec->dbw_gridRect.r_ybot);
|
||||
}
|
||||
fvalue = (float)value * oscale * dscale;
|
||||
if (is_square)
|
||||
{
|
||||
fvalue *= dscale;
|
||||
snprintf(result, 32, "%0.6f", (double)fvalue);
|
||||
dbwValueFormat(result, 6);
|
||||
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 27))
|
||||
strcat(result, "gx*gy");
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(result, 32, "%0.3f", (double)fvalue);
|
||||
dbwValueFormat(result, 3);
|
||||
if (is_x)
|
||||
{
|
||||
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 30))
|
||||
strcat(result, "gx");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 30))
|
||||
strcat(result, "gy");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* DBWPrintValue --
|
||||
* DBWPrintSqValue --
|
||||
* DBWPrintCIFValue --
|
||||
* DBWPrintCIFSqValue --
|
||||
*
|
||||
* Convenience functions which call dbwPrintValue0() with specific
|
||||
* fixed arguments, so that the calls are not full of boolean values.
|
||||
* The "is_x" boolean is retained because it is used often.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
DBWPrintValue(int value, /* value to print, in internal units */
|
||||
MagWindow *w, /* current window, for use with grid */
|
||||
bool is_x) /* TRUE if value is an X dimension */
|
||||
{
|
||||
/* Call dbwPrintValue0() with is_square = FALSE and is_cif = FALSE */
|
||||
return dbwPrintValue0(value, w, is_x, FALSE, FALSE);
|
||||
}
|
||||
|
||||
char *
|
||||
DBWPrintSqValue(int value, /* value to print, in internal units */
|
||||
MagWindow *w) /* current window, for use with grid */
|
||||
{
|
||||
/* Call dbwPrintValue0() with is_square = TRUE and is_cif = FALSE */
|
||||
/* is_x is set to TRUE although it is unused. */
|
||||
return dbwPrintValue0(value, w, TRUE, TRUE, FALSE);
|
||||
}
|
||||
|
||||
char *
|
||||
DBWPrintCIFValue(int value, /* value to print, in internal units */
|
||||
MagWindow *w, /* current window, for use with grid */
|
||||
bool is_x) /* TRUE if value is an X dimension */
|
||||
{
|
||||
/* Call dbwPrintValue0() with is_square = FALSE and is_cif = TRUE */
|
||||
return dbwPrintValue0(value, w, is_x, FALSE, TRUE);
|
||||
}
|
||||
|
||||
char *
|
||||
DBWPrintCIFSqValue(int value, /* value to print, in internal units */
|
||||
MagWindow *w) /* current window, for use with grid */
|
||||
{
|
||||
/* Call dbwPrintValue0() with is_square = TRUE and is_cif = TRUE */
|
||||
/* is_x is set to TRUE although it is unused. */
|
||||
return dbwPrintValue0(value, w, TRUE, TRUE, TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
|
|||
|
|
@ -65,11 +65,21 @@ typedef struct _crosshairRec {
|
|||
static CrosshairRec curCrosshair; /* Crosshair position */
|
||||
|
||||
/*
|
||||
* If the following is DBW_SNAP_USER, the box gets snapped to the user's
|
||||
* If the following is DBW_UNITS_USER, the box gets snapped to the user's
|
||||
* grid always, instead of snapping to the usual 1x1 grid. If the value
|
||||
* is DBW_SNAP_INTERNAL, the box gets snapped to the internal grid.
|
||||
* is DBW_UNITS_INTERNAL, the box gets snapped to the internal grid.
|
||||
*/
|
||||
int DBWSnapToGrid = DBW_SNAP_LAMBDA;
|
||||
int DBWSnapToGrid = DBW_UNITS_LAMBDA;
|
||||
|
||||
/*
|
||||
* The original behavior with respect to units was that un-suffixed
|
||||
* values follow whatever the snap setting is (DBWSnapToGrid, above).
|
||||
* Current behavior is that the original behavior is followed while
|
||||
* DBWUnits is set to DBW_UNITS_DEFAULT. However, if the "units"
|
||||
* command is given, then displayed and entered units follow that
|
||||
* value independently of the snap setting.
|
||||
*/
|
||||
int DBWUnits = DBW_UNITS_DEFAULT;
|
||||
|
||||
/* Forward reference: */
|
||||
|
||||
|
|
@ -82,8 +92,8 @@ extern int DBWToolDraw();
|
|||
* toolFindPoint --
|
||||
*
|
||||
* Returns the point in root coordinates.
|
||||
* If DBWSnapToGrid is DBW_SNAP_USER, pick the nearest point that is
|
||||
* aligned with the window's grid. If DBWSnapToGrid is DBW_SNAP_LAMBDA,
|
||||
* If DBWSnapToGrid is DBW_UNITS_USER, pick the nearest point that is
|
||||
* aligned with the window's grid. If DBWSnapToGrid is DBW_UNITS_LAMBDA,
|
||||
* pick the nearest point that is an integer lambda value.
|
||||
*
|
||||
* Results:
|
||||
|
|
@ -120,7 +130,7 @@ toolFindPoint(p, rootPoint, rootArea)
|
|||
if (!GEO_ENCLOSE(p, &WindCurrentWindow->w_screenArea)) return NULL;
|
||||
|
||||
WindPointToSurface(WindCurrentWindow, p, rootPoint, rootArea);
|
||||
if (DBWSnapToGrid != DBW_SNAP_INTERNAL)
|
||||
if (DBWSnapToGrid != DBW_UNITS_INTERNAL)
|
||||
ToolSnapToGrid(WindCurrentWindow, rootPoint, rootArea);
|
||||
return WindCurrentWindow;
|
||||
|
||||
|
|
@ -844,8 +854,8 @@ DBWResetBox(CellDef *def)
|
|||
* Repositions the box by one of its corners.
|
||||
* If the point given to reposition the box is in screen coordinates,
|
||||
* the box corner is snapped to the user's grid (set with the :grid
|
||||
* command) if DBWSnapToGrid is DBW_SNAP_USER. If DBWSnapToGrid is
|
||||
* DBW_SNAP_LAMBDA, the box corner is snapped to the nearest integer
|
||||
* command) if DBWSnapToGrid is DBW_UNITS_USER. If DBWSnapToGrid is
|
||||
* DBW_UNITS_LAMBDA, the box corner is snapped to the nearest integer
|
||||
* lambda value.
|
||||
*
|
||||
* Results:
|
||||
|
|
@ -948,8 +958,8 @@ ToolMoveBox(corner, point, screenCoords, rootDef)
|
|||
*
|
||||
* If the point given to reposition the box is in screen coordinates,
|
||||
* the box corner is snapped to the user's grid (set with the :grid
|
||||
* command) if DBWSnapToGrid is DBW_SNAP_USER. If DBWSnapToGrid is
|
||||
* DBW_SNAP_LAMBDA, the box corner is snapped to the nearest integer
|
||||
* command) if DBWSnapToGrid is DBW_UNITS_USER. If DBWSnapToGrid is
|
||||
* DBW_UNITS_LAMBDA, the box corner is snapped to the nearest integer
|
||||
* lambda value.
|
||||
*
|
||||
* Results:
|
||||
|
|
@ -1092,7 +1102,7 @@ ToolSnapToGrid(w, p, rEnclose)
|
|||
if (crec == NULL || p == NULL)
|
||||
return;
|
||||
|
||||
if (DBWSnapToGrid == DBW_SNAP_LAMBDA)
|
||||
if (DBWSnapToGrid == DBW_UNITS_LAMBDA)
|
||||
{
|
||||
lr.r_xbot = lr.r_ybot = 0;
|
||||
lr.r_xtop = DBLambda[1] / DBLambda[0];
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ typedef struct DBW1 {
|
|||
|
||||
extern WindClient DBWclientID;
|
||||
extern int DBWSnapToGrid;
|
||||
extern int DBWUnits;
|
||||
|
||||
extern int DBWMaxTechStyles;
|
||||
extern int DBWMaxTileStyles;
|
||||
|
|
@ -121,13 +122,17 @@ extern int DBWNumStyles;
|
|||
extern int RtrPolyWidth, RtrMetalWidth, RtrContactWidth;
|
||||
|
||||
/*
|
||||
* Exported procedure headers for redisplay
|
||||
* Exported procedure headers for redisplay and output
|
||||
*/
|
||||
|
||||
extern int DBWWatchTiles();
|
||||
extern void DBWAreaChanged();
|
||||
extern void DBWLabelChanged();
|
||||
extern void DBWDrawLabel();
|
||||
extern char *DBWPrintValue(int value, MagWindow *w, bool is_x);
|
||||
extern char *DBWPrintSqValue(int value, MagWindow *w);
|
||||
extern char *DBWPrintCIFValue(int value, MagWindow *w, bool is_x);
|
||||
extern char *DBWPrintCIFSqValue(int value, MagWindow *w);
|
||||
|
||||
/*
|
||||
* Exported procedures and variables related to the technology file
|
||||
|
|
@ -169,14 +174,36 @@ extern void DBWBoxHandler();
|
|||
#define TOOL_ILG -1
|
||||
|
||||
/* The following defines are used to indicate which coordinate system
|
||||
* the cursor box snaps to when moved with mouse clicks (values for
|
||||
* DBWSnapToGrid).
|
||||
* is used when displaying or returning values. By default this is
|
||||
* set to DBW_UNITS_INTERNAL. From magic version 8.3.595, this is
|
||||
* independently set from "snap". For backwards compatibility,
|
||||
* the value starts as DBW_UNITS_DEFAULT which implements the original
|
||||
* behavior in which the "snap" setting dictates the dispaly units.
|
||||
* Only if set to a non-negative value do the display units operate
|
||||
* independently of the snap setting.
|
||||
*
|
||||
* NOTES:
|
||||
* Lambda units are fixed by the tech file.
|
||||
* Internal units are scalable.
|
||||
* User units are scalable; this can be used, for example, to
|
||||
* set a box position according to multiples of a track
|
||||
* pitch, but is most often used manually with the "g"
|
||||
* (for "grid") suffix; e.g., "move box e 1g"
|
||||
* Micron units are dependent on the specified cifoutput style
|
||||
* and how the tech file defines the scalefactor for it.
|
||||
*/
|
||||
|
||||
#define DBW_SNAP_INTERNAL 0 /* internal units (fine grid) */
|
||||
#define DBW_SNAP_LAMBDA 1 /* lambda units (coarse grid) */
|
||||
#define DBW_SNAP_USER 2 /* user grid units (user grid) */
|
||||
#define DBW_SNAP_MICRONS 3 /* micron units */
|
||||
#define DBW_UNITS_DEFAULT -1 /* backwards-compatible behavior */
|
||||
#define DBW_UNITS_INTERNAL 0 /* internal units */
|
||||
#define DBW_UNITS_LAMBDA 1 /* lambda units */
|
||||
#define DBW_UNITS_USER 2 /* user grid units */
|
||||
#define DBW_UNITS_MICRONS 3 /* micron units */
|
||||
#define DBW_UNITS_TYPE_MASK 3 /* everything but the flag field(s) */
|
||||
#define DBW_UNITS_PRINT_FLAG 4 /* flag used to indicate that
|
||||
* the units should be printed
|
||||
* with the value; e.g.,
|
||||
* "10um" instead of "10".
|
||||
*/
|
||||
|
||||
/* The following window mask can be used to select all database windows
|
||||
* for things like the mask parameter to DBWAreaChanged.
|
||||
|
|
|
|||
|
|
@ -334,23 +334,23 @@
|
|||
</TR>
|
||||
<TR>
|
||||
<TD> <A HREF=undo.html> <B>undo</B></A> </TD>
|
||||
<TD> <A HREF=units.html> <B>units</B></A> </TD>
|
||||
<TD> <A HREF=updatedisplay.html> <B>updatedisplay</B></A> </TD>
|
||||
<TD> <A HREF=version.html> <B>version</B></A> </TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> <A HREF=version.html> <B>version</B></A> </TD>
|
||||
<TD> <A HREF=view.html> <B>view</B></A> </TD>
|
||||
<TD> <A HREF=windowborder.html> <B>windowborder</B></A> </TD>
|
||||
<TD> <A HREF=windowcaption.html> <B>windowcaption</B></A> </TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> <A HREF=windowcaption.html> <B>windowcaption</B></A> </TD>
|
||||
<TD> <A HREF=windownames.html> <B>windownames</B></A> </TD>
|
||||
<TD> <A HREF=windowscrollbars.html> <B>windowscrollbars</B></A> </TD>
|
||||
<TD> <A HREF=xview.html> <B>xview</B></A> </TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> <A HREF=xview.html> <B>xview</B></A> </TD>
|
||||
<TD> <A HREF=zoom.html> <B>zoom</B></A> </TD>
|
||||
<TD> <A HREF=tk_path_name.html> <I>tk_path_name</I></A> </TD>
|
||||
<TD> </TD>
|
||||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ techmanager
|
|||
tool
|
||||
undo
|
||||
unexpand
|
||||
units
|
||||
updatedisplay
|
||||
upsidedown
|
||||
version
|
||||
|
|
|
|||
|
|
@ -42,9 +42,11 @@ Circuit netlist extractor
|
|||
<DL>
|
||||
<DT> <B>capacitance</B>
|
||||
<DD> Extract local parasitic capacitance values to substrate
|
||||
<DT> <B>resistance</B>
|
||||
<DD> Extract lumped resistance values. Note that this
|
||||
is <I>not</I> the same as full parasitic resistance.
|
||||
<DT> <B>coupling</B>
|
||||
<DD> Extract the parasitic coupling capacitance between
|
||||
nodes.
|
||||
<DT> <B>lumped</B>
|
||||
<DD> Extract lumped resistance values.
|
||||
The values extracted are "lumped" resistance and
|
||||
indicate the value for which the delay through the
|
||||
net can be computed with R times C, where R is the
|
||||
|
|
@ -55,9 +57,10 @@ Circuit netlist extractor
|
|||
command. Lumped resistances have no meaning in
|
||||
SPICE netlists and will only be used when running
|
||||
<B>ext2sim</B> to generate a .sim netlist.
|
||||
<DT> <B>coupling</B>
|
||||
<DD> Extract the parasitic coupling capacitance between
|
||||
nodes.
|
||||
Prior to magic version 8.3.597, this option was
|
||||
<B>resistance</B>, but as that was often confused
|
||||
with full parasitic resistance extraction, it has
|
||||
been changed.
|
||||
<DT> <B>length</B>
|
||||
<DD> Extract the length of the shortest path from a driver
|
||||
to a receiver, for computing more accurate parasitic
|
||||
|
|
@ -73,7 +76,7 @@ Circuit netlist extractor
|
|||
array instances, is guaranteed to be strictly positive.
|
||||
<DT> <B>all</B>
|
||||
<DD> Apply all standard options (does not include options
|
||||
"local", "labelcheck", or "aliases").
|
||||
"local", "labelcheck", "aliases", or "resistance").
|
||||
<DT> <B>local</B>
|
||||
<DD> Write all .ext files to the current working directory.
|
||||
If not specified, each .ext file will be placed in the
|
||||
|
|
@ -99,6 +102,28 @@ Circuit netlist extractor
|
|||
but will usually just slow down processing by commands
|
||||
like "ext2spice" that use the .ext file contents, so it
|
||||
is disabled by default.
|
||||
<DT> <B>unique</B>
|
||||
<DD> (Added in magic version 8.3.594) This setting replaces
|
||||
the use of the command option "extract unique". Instead
|
||||
of changing labels in the design, unique labels are
|
||||
generated for the duration of the extraction, and then
|
||||
reverted back to the original text. The "extract unique"
|
||||
command option is maintained for backwards compatibility.
|
||||
Note the difference: "extract unique" is a command that
|
||||
runs immediately, and cannot be undone;
|
||||
"extract do unique" is an option setting for "extract".
|
||||
<DT> <B>resistance</B>
|
||||
<DD> (Added in magic version 8.3.597) This setting replaces
|
||||
the use of the standalone command "extresist". The
|
||||
effect is the same: Magic performs full R-C extraction,
|
||||
generating a <TT>.res.ext</TT> file that annotates the
|
||||
existing <TT>.ext</TT> file (see the "extresist" command
|
||||
documentation). The "extresist" command options can
|
||||
still be used to set options such as tolerance for the
|
||||
R-C extraction.
|
||||
Note that prior to magic version 8.3.597, this option
|
||||
name would produce the lumped resistance approximation
|
||||
(see <B>lumped</B>, above).
|
||||
</DL>
|
||||
</BLOCKQUOTE>
|
||||
These options (except for "local") determine how much
|
||||
|
|
@ -213,7 +238,9 @@ Circuit netlist extractor
|
|||
<I>Warning:</I> This operation immediately modifies the
|
||||
existing layout in preparation for extraction. Label
|
||||
modifications are permanent, and cannot be undone. All
|
||||
cells in the hierarchy may potentially be modified. <BR>
|
||||
cells in the hierarchy may potentially be modified. To avoid
|
||||
this issue, use the "extract do unique" option instead (see
|
||||
above). <BR>
|
||||
<DT> <B>warn</B> [[<B>no</B>] <I>option</I>]
|
||||
<DD> Enable/disable reporting of non-fatal errors, where <I>option</I>
|
||||
may be one of the following:
|
||||
|
|
|
|||
|
|
@ -92,17 +92,25 @@ information.
|
|||
The <B>extresist</B> command provides a method for generating
|
||||
a more detailed model of resistance, in which long network
|
||||
routes and branching routes are replaced with resistor devices
|
||||
and device networks. <P>
|
||||
and device networks. This is known as "full R-C extraction". <P>
|
||||
|
||||
Using <B>extresist</B> is a multi-step process. It is first
|
||||
necessary to run both <B>extract</B> and <B>ext2sim</B> to get
|
||||
the initial netlist (with lumped, not detailed, resistances).
|
||||
After a <TT>.sim</TT> file has been generated, the
|
||||
<B>extresist all</B> command may be run. The output is
|
||||
Using <B>extresist</B> as a standalone command is a multi-step
|
||||
process. It is first necessary to run <B>extract</B> to get
|
||||
the initial netlist.
|
||||
After a <TT>.ext</TT> file has been generated, the
|
||||
<B>extresist</B> command may be run. The output is
|
||||
a file <TT>.res.ext</TT> for each cell in the hierarchy.
|
||||
Finally, with the option <B>extresist on</B> set,
|
||||
<B>ext2sim</B> or <B>ext2spice</B> will generate the final,
|
||||
detailed simulation file. <P>
|
||||
Finally, with the option <B>extresist on</B> set, <B>ext2spice</B>
|
||||
will generate the final, detailed simulation file. <P>
|
||||
|
||||
Prior to magic version 8.3.597, it was also necessary to run
|
||||
<B>ext2sim labels on</B> and <B>ext2sim</B> to write out a
|
||||
<TT>.sim</TT> and a <TT>.node</TT> file before running
|
||||
<B>extresist</B>. This is no longer necessary. There is since
|
||||
magic version 8.3.597 an option <B>extract do resistance</B>
|
||||
that runs the resistance extraction in sequence with the regular
|
||||
extraction, producing both the <TT>.ext</TT> and <TT>.res.ext</TT>
|
||||
files.
|
||||
|
||||
More details on using <B>extresist</B> can be found in
|
||||
<B>magic</B> Tutorial number 8.
|
||||
|
|
@ -117,6 +125,7 @@ information.
|
|||
<BLOCKQUOTE>
|
||||
<A HREF=extract.html><B>extract</B></A> <BR>
|
||||
<A HREF=ext2sim.html><B>ext2sim</B></A> <BR>
|
||||
<A HREF=ext2spice.html><B>ext2spice</B></A> <BR>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P><IMG SRC=graphics/line1.gif><P>
|
||||
|
|
|
|||
|
|
@ -182,6 +182,13 @@ Read GDSII input or generate GDSII output.
|
|||
than to subsplit the internal grid to such a fine value.
|
||||
The "<B>cif limit</B>" function may also be used to limit
|
||||
grid subdivision to a minimum value.
|
||||
<DT> <B>savepaths</B> [<B>yes</B>|<B>no</B>]
|
||||
<DD> When reading paths from a GDS file, record the centerline of
|
||||
the path as a property in the cell. The default behavior is
|
||||
<B>no</B>. If no argument is given, then return the status
|
||||
of the <B>savepaths</B> option. The first path property is
|
||||
named "<TT>path</TT>", followed by "<TT>path_0</TT>" and
|
||||
increasing the suffix index for each individual path read.
|
||||
<DT> <B>unique</B> [<B>yes</B>|<B>no</B>]
|
||||
<DD> When reading a GDS file, this option forces magic to rename
|
||||
cell definitions in the database when a cell of the same name
|
||||
|
|
|
|||
|
|
@ -87,6 +87,50 @@ Place a label in the layout
|
|||
to another layer. <P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<B>Attribute labels:</B> <P>
|
||||
A handful of labels are referred to as "attribute" labels. These
|
||||
label types are placed on devices and affect how the device is
|
||||
extracted. <P>
|
||||
|
||||
A label that is placed inside a device (e.g., a MOSFET gate) which
|
||||
ends with the character "<B>^</B>" is a <I>gate attribute</I>. A
|
||||
gate attribute in the form of "<I>name</I><B>=</B><I>value</I><B>^</B>"
|
||||
specifies an extra parameter to be passed to the device in addition
|
||||
to the standard parameters calculated for that device. This is used
|
||||
to capture parameters which cannot easily be inferred from the layout.
|
||||
For example, an RF device model might be distinguished from a non-RF
|
||||
device model by a parameter such as <B>rfmode=1</B>. Whether or not
|
||||
a device is intended for RF use is not easily guessed from the layout,
|
||||
and so "tagging" the gate with the parameter allows the correct model
|
||||
parameters to be used for the device. <P>
|
||||
|
||||
A gate attribute that is not in the form of a parameter will be used
|
||||
as the device's instance index in the netlist; e.g., a label of
|
||||
"<B>1^</B>" on a MOSFET gate extracted as a MOSFET device would be an
|
||||
entry "<B>M1</B>" in the netlist. This can be used to better track
|
||||
device indexes between a schematic and layout. <P>
|
||||
|
||||
A label that is placed on the <I>edge</I> a device, specificlly a
|
||||
MOSFET gate, and which ends with the character "<B>$</B>", is a
|
||||
<I>terminal attribute</I>. The only terminal attributes recognized
|
||||
by magic are <B>S$</B> and <B>D$</B>, which specify which side of the
|
||||
gate is to be considered the source and which is to be considered the
|
||||
drain. Generally, MOSFET devices are symmetric, and their use in a
|
||||
simulation does not depend on which side is in the position of the
|
||||
"source" and which is in the position of the "drain". To the extent
|
||||
that it matters, the terminal attributes can be used to ensure that
|
||||
the source and drain connections appear in the netlist in their
|
||||
intended orientation. <P>
|
||||
|
||||
Labels ending with "<B>@</B>" are <I>node attributes</I>. There is
|
||||
currently no functional application for node attributes. When one
|
||||
is applied, it will appear in the output netlist in a SPICE comment
|
||||
line indicating the node and attribute. This could be used, say,
|
||||
by a post-processing script, but as it is in a comment line, it has
|
||||
no impact on simulation or LVS.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3>Implementation Notes:</H3>
|
||||
<BLOCKQUOTE>
|
||||
<B>label</B> is implemented as a built-in command in <B>magic</B>.
|
||||
|
|
|
|||
|
|
@ -25,9 +25,13 @@ Attach a "property" (string key and value pair) to the edit cell
|
|||
|
||||
<H3>Usage:</H3>
|
||||
<BLOCKQUOTE>
|
||||
<B>property</B> [<I>key</I> [<I>value</I>]] <BR><BR>
|
||||
<B>property</B> [<I>list</I>] [<I>type</I>] [<I>key</I> [<I>value</I>]] <BR>
|
||||
or
|
||||
<B>property</B> [<B>compat</B>] [<B>true</B>|<B>false</B>] <BR><BR>
|
||||
<BLOCKQUOTE>
|
||||
where <I>key</I> and <I>value</I> are any text strings.
|
||||
where <I>key</I> and <I>value</I> are any text strings. <BR>
|
||||
<I>type</I> may be one of <B>string</B>, <B>integer</B>,
|
||||
<B>dimension</B>, or <B>double</B>.
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
|
@ -45,11 +49,64 @@ Attach a "property" (string key and value pair) to the edit cell
|
|||
with the key is returned. With both arguments, the string
|
||||
<I>value</I> is associated with the string <I>key</I> as a
|
||||
property of the cell. If <I>key</I> is an existing key, then
|
||||
its original value will be overwritten.
|
||||
its original value will be overwritten. <P>
|
||||
|
||||
By default, properties are interpreted as verbatim string values,
|
||||
with exceptions for the reserved types (see below). To force the
|
||||
values of the property to be interpreted as a specific type, use
|
||||
the <I>type</I> option. <P>
|
||||
|
||||
The <B>property compat</B> setting determines how properties are
|
||||
written out to a .mag file. The default setting is <B>true</B>
|
||||
(backwards compatibility mode), which writes all properties as
|
||||
type "<TT>string</TT>". Properties which are reserved names
|
||||
(see below) will be converted to the best type when reading the
|
||||
.mag file. However, if the user wants to create a property that
|
||||
is handled differently than a string (namely, to be a dimensional
|
||||
value that scales), then comptability mode should be turned off. <P>
|
||||
|
||||
If the argument <I>list</I> is given as the first argument, and
|
||||
<I>value</I> is not present, then if the property <I>key</I>
|
||||
does not exist, then the command will return a NULL object to the
|
||||
interpreter instead of printing an error message. This is the
|
||||
"quiet" version of the command preferred for scripts that want to
|
||||
query whether or not a specific property exists.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Property names reserved by and used by magic:
|
||||
Types are interpreted as follows:
|
||||
<DL>
|
||||
<DT> <B>string</B> type:
|
||||
<DD> The property value is a character string. Character strings
|
||||
may contain spaces, but if so, then the string should be quoted
|
||||
or in braces, per Tcl syntax.
|
||||
<DT> <B>integer</I> type:
|
||||
<DD> The property value is an integer value or a list of integer
|
||||
values. The values are not considered to be measurements and
|
||||
do not scale. Multiple values may be passed on the command
|
||||
line as additional arguments, or the set of values may be
|
||||
given as a list.
|
||||
<DT> <B>dimension</I> type:
|
||||
<DD> The property value is an integer value or a list of integer
|
||||
values. The values are considered to be (linear) dimensional
|
||||
measurements and therefore scale with the database internal
|
||||
units. They are interpreted as having the values currently
|
||||
specified for <B>units</B>, and display back in the same
|
||||
units. Multiple values may be passed on the command line as
|
||||
additional arguments, or the set of values may be given as a
|
||||
list.
|
||||
<DT> <B>double</I> type:
|
||||
<DD> The property value is a double-wide (64-bit) integer value or
|
||||
a list of double-wide integer values. The values are not
|
||||
considered to be measurements and do not scale. Multiple
|
||||
values may be passed on the command line as additional arguments,
|
||||
or the set of values may be given as a list.
|
||||
</DL>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Property names reserved by and used by magic (types are <B>string</B>
|
||||
unless otherwise noted):
|
||||
<DL>
|
||||
<DT> <B>GDS_FILE</B>
|
||||
<DD> The value is the name of a GDS file which contains the mask
|
||||
|
|
@ -60,12 +117,14 @@ Attach a "property" (string key and value pair) to the edit cell
|
|||
<DD> If a <B>GDS_FILE</B> is defined, then this value indicates the
|
||||
byte position of the start of mask data for this cell definition
|
||||
in the file. If set to value <B>0</B>, then the file will be
|
||||
searched for the data bounds.
|
||||
searched for the data bounds. This property is always of type
|
||||
<B>double</B>.
|
||||
<DT> <B>GDS_END</B>
|
||||
<DD> If a <B>GDS_FILE</B> is defined, then this value indicates the
|
||||
byte position of the end of mask data for this cell definition
|
||||
in the file. If <B>GDS_START</B> is set to <B>0</B>, then this
|
||||
property may be omitted.
|
||||
property may be omitted. This property is always of type
|
||||
<B>double</B>.
|
||||
<DT> <B>LEFview</B>
|
||||
<DD> If set to <B>TRUE</B>, this cell is an abstract view such as that
|
||||
obtained from a LEF macro, and should not be used for extraction
|
||||
|
|
@ -97,6 +156,8 @@ Attach a "property" (string key and value pair) to the edit cell
|
|||
corresponding to the abutment box of the cell, in magic's internal
|
||||
units. The abutment box is automatically read from LEF files, but
|
||||
may be defined for any file and can be used for placement alignment.
|
||||
This property is always of type <B>dimension</B> and must contain
|
||||
exactly four values.
|
||||
<DT> <B>OBS_BBOX</B>
|
||||
<DD> This property value is a space-sparated list of four integer values
|
||||
corresponding to a bounding box to be used when generating a LEF
|
||||
|
|
@ -104,7 +165,8 @@ Attach a "property" (string key and value pair) to the edit cell
|
|||
will be entirely covered in obstruction layers (unless cut-outs
|
||||
are required to accommodate pins). Any set-back applied by the
|
||||
"lef write -hide <value>" option will be applied to this obstruction
|
||||
box.
|
||||
box. This property is always of type <B>dimension</B> and must
|
||||
contain exactly four values.
|
||||
<DT> <B>flatten</B>
|
||||
<DD> This property is used in conjunction with the "flatten -doproperty"
|
||||
command option and marks the cell for flattening. Cells without
|
||||
|
|
@ -146,7 +208,8 @@ Attach a "property" (string key and value pair) to the edit cell
|
|||
always generate mask layer <I>type</I> in the specified rectangle
|
||||
area when writing GDS or CIF output. <I>type</I> may be a templayer,
|
||||
such that <I>type</I> could be defined as the absence of a mask layer,
|
||||
for example.
|
||||
for example. This property is always of type <B>dimension</B> and
|
||||
must have a multiple of four values.
|
||||
</DL>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
|
@ -157,6 +220,11 @@ Attach a "property" (string key and value pair) to the edit cell
|
|||
the cell definition structure.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3>See Also:</H3>
|
||||
<BLOCKQUOTE>
|
||||
<A HREF=units.html><B>units</B></A> <BR>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P><IMG SRC=graphics/line1.gif><P>
|
||||
<TABLE BORDER=0>
|
||||
<TR>
|
||||
|
|
|
|||
|
|
@ -39,21 +39,15 @@ in the selected grid.
|
|||
feature size, and <B>user</B>, based on the value given by the
|
||||
user to the <B>grid</B> command. <P>
|
||||
|
||||
In addition to changing the behavior of the box to mouse
|
||||
button events, the <B>snap</B> command also changes the way
|
||||
that <A HREF=distance.html>distance measurements</A> are
|
||||
interpreted in commands that take distance arguments, such
|
||||
as <B>move</B>, <B>copy</B>, and <B>stretch</B>. An integer
|
||||
number with no other identifying units is interpreted as a
|
||||
measurement in the current snap grid. All other measurements
|
||||
must have an identifying unit: <B>i</B> for internal units,
|
||||
<B>l</B> for lambda units, and <B>g</B> for user grid units
|
||||
(as well as the usual metric units). Even when <B>snap</B>
|
||||
is set to the larger lambda or user grids, it is possible to
|
||||
move the cursor box to finer grid positions from the command
|
||||
line. See the reference page on
|
||||
<A HREF=distance.html>distance measures</A> for a complete
|
||||
description of distance values. <P>
|
||||
Historically, in addition to changing the behavior of the box
|
||||
to mouse button events, the <B>snap</B> command also changed
|
||||
the way that <A HREF=distance.html>distance measurements</A>
|
||||
are interpreted in commands that take distance arguments.
|
||||
This behavior remains the default for backwards compatibility.
|
||||
The <B>units</B> command overrides this behavior and allows
|
||||
<B>snap</B> to control only the box positioning behavior,
|
||||
independently of how unsuffixed values are parsed by the
|
||||
interpreter. <P>
|
||||
|
||||
<B>snap</B> with no arguments returns the current snap grid
|
||||
type. <P>
|
||||
|
|
@ -80,6 +74,7 @@ in the selected grid.
|
|||
|
||||
<H3>See Also:</H3>
|
||||
<BLOCKQUOTE>
|
||||
<A HREF=units.html><B>units</B></A> <BR>
|
||||
<A HREF=grid.html><B>grid</B></A> <BR>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<STYLE type="text/css">
|
||||
H1 {color: black }
|
||||
H2 {color: maroon }
|
||||
H3 {color: #007090 }
|
||||
A.head:link {color: #0060a0 }
|
||||
A.head:visited {color: #3040c0 }
|
||||
A.head:active {color: white }
|
||||
A.head:hover {color: yellow }
|
||||
A.red:link {color: red }
|
||||
A.red:visited {color: maroon }
|
||||
A.red:active {color: yellow }
|
||||
</STYLE>
|
||||
</HEAD>
|
||||
<TITLE>Magic-8.3 Command Reference</TITLE>
|
||||
<BODY BACKGROUND=graphics/blpaper.gif>
|
||||
<H1> <IMG SRC=graphics/magic_title8_3.png ALT="Magic VLSI Layout Tool Version 8.3">
|
||||
<IMG SRC=graphics/magic_OGL_sm.gif ALIGN="top" ALT="*"> </H1>
|
||||
|
||||
<H2>units</H2>
|
||||
<HR>
|
||||
Cause distance measurements to be interpreted by default (with no
|
||||
suffix provied) as measurments of the selected units, and also cause
|
||||
distance measurements to be printed in the selected units.
|
||||
<HR>
|
||||
|
||||
<H3>Usage:</H3>
|
||||
<BLOCKQUOTE>
|
||||
<B>units</B> [<B>internal</B>|<B>lambda</B>|<B>user</B>|<B>grid</B>|<B>microns</B>|<B>default</B>] [<B>print</B>|</B>noprint</B>] <BR>
|
||||
or <BR>
|
||||
<B>units</B> [<B>list</B>] <BR><BR>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3>Summary:</H3>
|
||||
<BLOCKQUOTE>
|
||||
The <B>units</B> command causes printed measurements to be
|
||||
given in the selected units. The possible unit types are
|
||||
<B>internal</B>, the size of the internal database units,
|
||||
<B>lambda</B>, the lambda grid based on the technology minimum
|
||||
feature size, <B>user</B> (or <B>grid</B>), based on the
|
||||
value given by the user to the <B>grid</B> command, or
|
||||
<B>microns</B>, which are physical units dependent on the
|
||||
CIF or GDS output scaling as defined in the technology file. <P>
|
||||
|
||||
The <B>units</B> command also changes the way
|
||||
that <A HREF=distance.html>distance measurements</A> are
|
||||
interpreted in commands that take distance arguments, such
|
||||
as <B>move</B>, <B>copy</B>, and <B>stretch</B>. An integer
|
||||
number with no other identifying units is interpreted as a
|
||||
measurement in the current units type. All other measurements
|
||||
must have an identifying unit: <B>i</B> for internal units,
|
||||
<B>l</B> for lambda units, and <B>g</B> for user grid units,
|
||||
as well as the usual metric units such as <B>um</B> for
|
||||
microns, <B>nm</B> for nanometers, and so forth. See the
|
||||
reference page on <A HREF=distance.html>distance measures</A>
|
||||
for a complete description of distance values. <P>
|
||||
|
||||
For printed units, the additional argument <B>print</B>
|
||||
causes the units to be printed along with the value; e.g.,
|
||||
"<B>1.0um</B>." This is the usual setting for interactive
|
||||
use. The argument <B>noprint</B> suppresses the unit name,
|
||||
which is appropriate for scripted use, when the value may
|
||||
be passed to arithmetic expressions to be evaluated by the
|
||||
interpreter. <P>
|
||||
|
||||
<B>units</B> with no arguments returns the current units type.
|
||||
<B>units list</B> returns the current units type as a Tcl list
|
||||
of two items; the first item is the units type, and the second
|
||||
item is <B>print</B> or <B>noprint</B>, indicating whether units
|
||||
suffixes are printed with the values. <P>
|
||||
|
||||
Historically, values parsed from the command line were interpreted
|
||||
according to the <B>snap</B> setting. On startup, this behavior
|
||||
remains in effect for backwards compatibility until overridden
|
||||
with a <B>units</B> command. The command <B>units default</B>
|
||||
reverts back to the original behavior. Once the <B>units</B>
|
||||
default type is overridden, the <B>snap</B> behavior is controlled
|
||||
independently of <B>units</B>. <P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3>Implementation Notes:</H3>
|
||||
<BLOCKQUOTE>
|
||||
<B>units</B> is implemented as a built-in command in <B>magic</B>.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3>See Also:</H3>
|
||||
<BLOCKQUOTE>
|
||||
<A HREF=grid.html><B>grid</B></A> <BR>
|
||||
<A HREF=snap.html><B>snap</B></A> <BR>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P><IMG SRC=graphics/line1.gif><P>
|
||||
<TABLE BORDER=0>
|
||||
<TR>
|
||||
<TD> <A HREF=commands.html>Return to command index</A>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<P><I>Last updated:</I> March 7, 2020 at 1:06pm <P>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
|
@ -45,10 +45,12 @@ view [get|bbox|llx lly urx ury]
|
|||
center and scale the screen view of the layout window to fit the layout. <P>
|
||||
|
||||
<B>view bbox</B> returns the bounding box dimensions of the layout,
|
||||
in the coordinate system of the layout. <P>
|
||||
in the coordinate system of the layout (according to the units
|
||||
set by the "units" command). <P>
|
||||
|
||||
<B>view get</B> returns the coordinates of the screen limits in
|
||||
the coordinate system of the layout (internal database units). <P>
|
||||
the coordinate system of the layout (according to the units set
|
||||
by the "units" command). <P>
|
||||
|
||||
<B>view</B> <I>llx lly urx ury</I> sets the view so that the
|
||||
corners of the screen are at the indicated positions in the
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ extern int drcArrayYankFunc(), drcArrayOverlapFunc();
|
|||
static DRCCookie drcArrayCookie = {
|
||||
0, 0, 0, 0,
|
||||
{ {0} }, { {0} },
|
||||
0, 0, 0,
|
||||
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||
DRC_ARRAY_OVERLAP_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
|
|
|||
121
drc/DRCbasic.c
121
drc/DRCbasic.c
|
|
@ -27,6 +27,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <stdio.h>
|
||||
#include <string.h> // for memcpy()
|
||||
#include <math.h> // for sqrt() for diagonal check
|
||||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "tiles/tile.h"
|
||||
|
|
@ -36,7 +38,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/signals.h"
|
||||
#include "utils/maxrect.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "utils/undo.h"
|
||||
#include "textio/textio.h"
|
||||
#include "cif/CIFint.h"
|
||||
|
||||
int dbDRCDebug = 0;
|
||||
|
||||
|
|
@ -48,7 +52,7 @@ int dbDRCDebug = 0;
|
|||
static DRCCookie drcOverlapCookie = {
|
||||
0, 0, 0, 0,
|
||||
{ {0} }, { {0} },
|
||||
0, 0, 0,
|
||||
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||
DRC_OVERLAP_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
|
@ -62,7 +66,33 @@ extern MaxRectsData *drcCanonicalMaxwidth();
|
|||
/*
|
||||
*-----------------------------------------------------------------------
|
||||
*
|
||||
* drcCifPointToSegment
|
||||
* drcFoundOneFunc --
|
||||
*
|
||||
* Simple callback for a plane search on a mask-hint plane inside
|
||||
* a DRC check area.
|
||||
*
|
||||
* Results:
|
||||
* Return 1 always, indicating that a tile has been found in the
|
||||
* DRC search area, and the search can end.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
drcFoundOneFunc(Tile *tile,
|
||||
TileType dinfo,
|
||||
ClientData cdata)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------
|
||||
*
|
||||
* drcCifPointToSegment --
|
||||
*
|
||||
* Euclidean-distance point-to-segment distance (squared)
|
||||
* calculation (borrowed from XCircuit)
|
||||
|
|
@ -468,6 +498,13 @@ DRCBasicCheck (celldef, checkRect, clipRect, function, cdata)
|
|||
DBResetTilePlane(celldef->cd_planes[planeNum], DRC_UNPROCESSED);
|
||||
(void) DBSrPaintArea ((Tile *) NULL, celldef->cd_planes[planeNum],
|
||||
checkRect, &DBAllTypeBits, drcTile, (ClientData) &arg);
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
/* Execute pending Tcl events, so the DRC process doesn't block. */
|
||||
UndoEnable();
|
||||
while (Tcl_DoOneEvent(TCL_DONT_WAIT));
|
||||
UndoDisable();
|
||||
#endif
|
||||
}
|
||||
drcCifCheck(&arg);
|
||||
if (arg.dCD_rlist != NULL) freeMagic(arg.dCD_rlist);
|
||||
|
|
@ -727,6 +764,43 @@ drcTile (tile, dinfo, arg)
|
|||
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
||||
cptr = cptr->drcc_next)
|
||||
{
|
||||
/* Handle rule exceptions and exemptions */
|
||||
if (cptr->drcc_exception != (char)DRC_EXCEPTION_NONE)
|
||||
{
|
||||
PropertyRecord *proprec;
|
||||
bool propfound, isinside = FALSE;
|
||||
char *name;
|
||||
char idx = cptr->drcc_exception;
|
||||
if (idx < 0) idx = -idx - 1;
|
||||
name = DRCCurStyle->DRCExceptionList[idx];
|
||||
|
||||
/* Is there any exception area defined? */
|
||||
proprec = DBPropGet(arg->dCD_celldef, name, &propfound);
|
||||
|
||||
/* If an exception area exists, is the error edge inside? */
|
||||
if (propfound)
|
||||
{
|
||||
Rect redge;
|
||||
|
||||
redge.r_xbot = redge.r_xtop = edgeX;
|
||||
redge.r_ybot = edgeBot;
|
||||
redge.r_ytop = edgeTop;
|
||||
|
||||
if (DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||
proprec->prop_value.prop_plane,
|
||||
&redge, &CIFSolidBits, drcFoundOneFunc,
|
||||
(ClientData)NULL) == 1)
|
||||
isinside = TRUE;
|
||||
}
|
||||
|
||||
/* Exemption rules are ignored if the edge is inside
|
||||
* an exception area. Exception rules are ignored if
|
||||
* the edge is outside an exception area.
|
||||
*/
|
||||
if (!isinside && (cptr->drcc_exception >= 0)) continue;
|
||||
if (isinside && (cptr->drcc_exception < 0)) continue;
|
||||
}
|
||||
|
||||
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
|
||||
/* the code above for non-Manhattan shapes and do not */
|
||||
/* need to be processed again. */
|
||||
|
|
@ -1136,6 +1210,49 @@ drcTile (tile, dinfo, arg)
|
|||
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
||||
cptr = cptr->drcc_next)
|
||||
{
|
||||
/* Handle rule exceptions and exemptions */
|
||||
if (cptr->drcc_exception != (char)DRC_EXCEPTION_NONE)
|
||||
{
|
||||
PropertyRecord *proprec;
|
||||
bool propfound, isinside = FALSE;
|
||||
char *name;
|
||||
char idx = cptr->drcc_exception;
|
||||
if (idx < 0) idx = -idx - 1;
|
||||
name = DRCCurStyle->DRCExceptionList[idx];
|
||||
|
||||
/* Is there any exception area defined? */
|
||||
proprec = DBPropGet(arg->dCD_celldef, name, &propfound);
|
||||
|
||||
/* Quickest case: Rule is an exception but there are no
|
||||
* exception areas.
|
||||
*/
|
||||
if ((!propfound) && (cptr->drcc_exception >= 0))
|
||||
continue;
|
||||
|
||||
/* If an exception area exists, is the error edge inside? */
|
||||
if (propfound)
|
||||
{
|
||||
Rect redge;
|
||||
|
||||
redge.r_ybot = redge.r_ytop = edgeY;
|
||||
redge.r_xbot = edgeLeft;
|
||||
redge.r_xtop = edgeRight;
|
||||
|
||||
if (DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||
proprec->prop_value.prop_plane,
|
||||
&redge, &CIFSolidBits, drcFoundOneFunc,
|
||||
(ClientData)NULL) == 1)
|
||||
isinside = TRUE;
|
||||
}
|
||||
|
||||
/* Exemption rules are ignored if the edge is inside
|
||||
* an exception area. Exception rules are ignored if
|
||||
* the edge is outside an exception area.
|
||||
*/
|
||||
if (isinside && (cptr->drcc_exception < 0)) continue;
|
||||
if (!isinside && (cptr->drcc_exception >= 0)) continue;
|
||||
}
|
||||
|
||||
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
|
||||
/* the code above for non-Manhattan shapes and do not */
|
||||
/* need to be processed again. */
|
||||
|
|
|
|||
|
|
@ -184,9 +184,9 @@ drcSubstitute (cptr)
|
|||
DRCCookie * cptr; /* Design rule violated */
|
||||
{
|
||||
static char *why_out = NULL;
|
||||
char *whyptr, *sptr, *wptr;
|
||||
int subscnt = 0, whylen;
|
||||
float oscale, value;
|
||||
char *whyptr, *sptr, *wptr, *vptr;
|
||||
int subscnt = 0, whylen, saveunits;
|
||||
float value;
|
||||
extern float CIFGetOutputScale();
|
||||
|
||||
whyptr = DRCCurStyle->DRCWhyList[cptr->drcc_tag];
|
||||
|
|
@ -203,10 +203,14 @@ drcSubstitute (cptr)
|
|||
why_out = (char *)mallocMagic(whylen * sizeof(char));
|
||||
strcpy(why_out, whyptr);
|
||||
|
||||
if (cptr->drcc_flags & DRC_CIFRULE)
|
||||
oscale = CIFGetScale(100); /* 100 = microns to centimicrons */
|
||||
else
|
||||
oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */
|
||||
/* For backwards compatibility: If the units are set to "default",
|
||||
* then print the DRC value in microns, with units, which is how
|
||||
* the output was previously presented.
|
||||
*/
|
||||
saveunits = DBWUnits;
|
||||
if (saveunits == DBW_UNITS_DEFAULT)
|
||||
DBWUnits = DBW_UNITS_MICRONS | DBW_UNITS_PRINT_FLAG;
|
||||
|
||||
wptr = why_out;
|
||||
|
||||
while ((sptr = strchr(whyptr, '%')) != NULL)
|
||||
|
|
@ -218,21 +222,29 @@ drcSubstitute (cptr)
|
|||
switch (*(sptr + 1))
|
||||
{
|
||||
case 'd':
|
||||
/* Replace with "dist" value in microns */
|
||||
value = (float)cptr->drcc_dist * oscale;
|
||||
snprintf(wptr, 20, "%01.3gum", value);
|
||||
if (cptr->drcc_flags & DRC_CIFRULE)
|
||||
vptr = DBWPrintCIFValue(cptr->drcc_dist, (MagWindow *)NULL, TRUE);
|
||||
else
|
||||
vptr = DBWPrintValue(cptr->drcc_dist, (MagWindow *)NULL, TRUE);
|
||||
snprintf(wptr, 20, "%s", vptr);
|
||||
wptr += strlen(wptr);
|
||||
break;
|
||||
case 'c':
|
||||
/* Replace with "cdist" value in microns */
|
||||
value = (float)cptr->drcc_cdist * oscale;
|
||||
snprintf(wptr, 20, "%01.3gum", value);
|
||||
if (cptr->drcc_flags & DRC_CIFRULE)
|
||||
vptr = DBWPrintCIFValue(cptr->drcc_cdist, (MagWindow *)NULL, TRUE);
|
||||
else
|
||||
vptr = DBWPrintValue(cptr->drcc_cdist, (MagWindow *)NULL, TRUE);
|
||||
snprintf(wptr, 20, "%s", vptr);
|
||||
wptr += strlen(wptr);
|
||||
break;
|
||||
case 'a':
|
||||
/* Replace with "cdist" value in microns squared */
|
||||
value = (float)cptr->drcc_cdist * oscale * oscale;
|
||||
snprintf(wptr, 20, "%01.4gum^2", value);
|
||||
if (cptr->drcc_flags & DRC_CIFRULE)
|
||||
vptr = DBWPrintCIFSqValue(cptr->drcc_cdist, (MagWindow *)NULL);
|
||||
else
|
||||
vptr = DBWPrintSqValue(cptr->drcc_cdist, (MagWindow *)NULL);
|
||||
snprintf(wptr, 20, "%s", vptr);
|
||||
wptr += strlen(wptr);
|
||||
break;
|
||||
default:
|
||||
|
|
@ -245,6 +257,7 @@ drcSubstitute (cptr)
|
|||
/* copy remainder of string (including trailing null) */
|
||||
strncpy(wptr, whyptr, strlen(whyptr) + 1);
|
||||
|
||||
DBWUnits = saveunits;
|
||||
return why_out;
|
||||
}
|
||||
|
||||
|
|
@ -425,6 +438,8 @@ drcListallError (celldef, rect, cptr, scx)
|
|||
}
|
||||
if (drcsave == DRCErrorCount)
|
||||
{
|
||||
char *rllx, *rlly, *rurx, *rury;
|
||||
|
||||
DRCErrorCount += 1;
|
||||
h = HashFind(&DRCErrorTable, drcSubstitute(cptr));
|
||||
lobj = (Tcl_Obj *) HashGetValue(h);
|
||||
|
|
@ -433,10 +448,15 @@ drcListallError (celldef, rect, cptr, scx)
|
|||
|
||||
pobj = Tcl_NewListObj(0, NULL);
|
||||
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_xbot));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_ybot));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_xtop));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_ytop));
|
||||
rllx = DBWPrintValue(r.r_xbot, (MagWindow *)NULL, TRUE);
|
||||
rlly = DBWPrintValue(r.r_ybot, (MagWindow *)NULL, FALSE);
|
||||
rurx = DBWPrintValue(r.r_xtop, (MagWindow *)NULL, TRUE);
|
||||
rury = DBWPrintValue(r.r_ytop, (MagWindow *)NULL, FALSE);
|
||||
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rllx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rlly, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rurx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rury, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
|
||||
|
||||
HashSetValue(h, lobj);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ static ClientData drcSubClientData; /* To be passed to error function. */
|
|||
static DRCCookie drcSubcellCookie = {
|
||||
0, 0, 0, 0,
|
||||
{ {0} }, { {0} },
|
||||
0, 0, 0,
|
||||
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||
DRC_SUBCELL_OVERLAP_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
|
@ -65,7 +65,7 @@ static DRCCookie drcSubcellCookie = {
|
|||
static DRCCookie drcInSubCookie = {
|
||||
0, 0, 0, 0,
|
||||
{ {0} }, { {0} },
|
||||
0, 0, 0,
|
||||
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||
DRC_IN_SUBCELL_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
|
@ -79,7 +79,7 @@ static DRCCookie drcInSubCookie = {
|
|||
static DRCCookie drcOffGridCookie = {
|
||||
0, 0, 0, 0,
|
||||
{ {0} }, { {0} },
|
||||
0, 0, 0,
|
||||
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||
DRC_OFFGRID_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
|
@ -826,6 +826,7 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
*/
|
||||
subArea = *erasebox;
|
||||
GeoClip(&subArea, &cliparea);
|
||||
if (GEO_RECTNULL(&subArea)) continue;
|
||||
GEO_EXPAND(&subArea, DRCTechHalo, &intArea);
|
||||
|
||||
errorSaveType = DRCErrorType;
|
||||
|
|
|
|||
198
drc/DRCtech.c
198
drc/DRCtech.c
|
|
@ -72,6 +72,12 @@ static int drcRulesOptimized = 0;
|
|||
|
||||
static int DRCtag = 0;
|
||||
|
||||
/* Keep track of what rule exemption or exception is in effect
|
||||
* while reading the DRC tech file section.
|
||||
*/
|
||||
|
||||
static char drcCurException = (char)DRC_EXCEPTION_NONE;
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
|
|
@ -79,6 +85,7 @@ int drcWidth(), drcSpacing(), drcEdge(), drcNoOverlap();
|
|||
int drcExactOverlap(), drcExtend();
|
||||
int drcSurround(), drcRectOnly(), drcOverhang();
|
||||
int drcStepSize(), drcOption(), drcOffGrid();
|
||||
int drcException(), drcExemption();
|
||||
int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles();
|
||||
int drcCifSetStyle(), drcCifWidth(), drcCifSpacing();
|
||||
int drcCifMaxwidth(), drcCifArea();
|
||||
|
|
@ -301,6 +308,12 @@ drcTechFreeStyle()
|
|||
/* Clear the Why string list */
|
||||
freeMagic(DRCCurStyle->DRCWhyList);
|
||||
|
||||
/* Clear the exception list */
|
||||
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
|
||||
freeMagic(DRCCurStyle->DRCExceptionList[i]);
|
||||
if (DRCCurStyle->DRCExceptionList != (char **)NULL)
|
||||
freeMagic(DRCCurStyle->DRCExceptionList);
|
||||
|
||||
freeMagic(DRCCurStyle);
|
||||
DRCCurStyle = NULL;
|
||||
}
|
||||
|
|
@ -384,6 +397,60 @@ drcWhyCreate(whystring)
|
|||
return DRCCurStyle->DRCWhySize;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* drcExceptionCreate --
|
||||
*
|
||||
* Create an entry for a DRC rule exception/exemption type, if it does
|
||||
* not already exist.
|
||||
*
|
||||
* Results:
|
||||
* The index of the exception (which is a signed character).
|
||||
*
|
||||
* Side effects:
|
||||
* Adds to the DRCExceptionList if "name" has not been used before.
|
||||
* Calls StrDup() and increments DRCExceptionSize.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char
|
||||
drcExceptionCreate(name)
|
||||
char *name;
|
||||
{
|
||||
int i;
|
||||
char **newlist;
|
||||
|
||||
/* NOTE: DRCExceptionList has "MASKHINTS_" prepended to the names */
|
||||
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
|
||||
if (!strcmp(name, DRCCurStyle->DRCExceptionList[i] + 10))
|
||||
return (char)i;
|
||||
|
||||
if (i > 127)
|
||||
{
|
||||
/* I would be shocked if this code ever got executed. */
|
||||
TxError("Error: Too many rule exceptions! Limit is 127.\n");
|
||||
return (char)DRC_EXCEPTION_NONE;
|
||||
}
|
||||
|
||||
/* Create a new list that is one entry longer than the old list.
|
||||
* This is not elegant but there will never be more than a handful
|
||||
* of exceptions in a rule deck.
|
||||
*/
|
||||
newlist = (char **)mallocMagic((i + 1) * sizeof(char *));
|
||||
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
|
||||
newlist[i] = DRCCurStyle->DRCExceptionList[i];
|
||||
|
||||
/* The rule deck does not have the "MASKHINTS_" prefix on the name */
|
||||
newlist[i] = (char *)mallocMagic(strlen(name) + 11);
|
||||
sprintf(newlist[i], "MASKHINTS_%s", name);
|
||||
DRCCurStyle->DRCExceptionSize++;
|
||||
if (DRCCurStyle->DRCExceptionList != (char **)NULL)
|
||||
freeMagic(DRCCurStyle->DRCExceptionList);
|
||||
DRCCurStyle->DRCExceptionList = newlist;
|
||||
return (char)i;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -571,6 +638,8 @@ DRCTechStyleInit()
|
|||
DRCCurStyle->DRCStepSize = 0;
|
||||
DRCCurStyle->DRCFlags = (char)0;
|
||||
DRCCurStyle->DRCWhySize = 0;
|
||||
DRCCurStyle->DRCExceptionList = (char **)NULL;
|
||||
DRCCurStyle->DRCExceptionSize = 0;
|
||||
|
||||
HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS);
|
||||
|
||||
|
|
@ -663,6 +732,7 @@ DRCTechStyleInit()
|
|||
}
|
||||
|
||||
drcCifInit();
|
||||
drcCurException = (char)DRC_EXCEPTION_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -955,6 +1025,7 @@ drcCifAssign(cookie, dist, next, mask, corner, tag, cdist, flags, planeto, plane
|
|||
(cookie)->drcc_plane = planeto;
|
||||
(cookie)->drcc_mod = 0;
|
||||
(cookie)->drcc_cmod = 0;
|
||||
(cookie)->drcc_exception = drcCurException;
|
||||
}
|
||||
|
||||
// This is like drcCifAssign, but checks for bad plane numbers in planeto and
|
||||
|
|
@ -1031,50 +1102,37 @@ DRCTechAddRule(sectionName, argc, argv)
|
|||
int (*rk_proc)(); /* Procedure implementing this keyword */
|
||||
const char *rk_err; /* Error message */
|
||||
} ruleKeys[] = {
|
||||
{"angles", 4, 4, drcAngles,
|
||||
"layers 45|90 why"},
|
||||
{"angles", 4, 4, drcAngles, "layers 45|90 why"},
|
||||
{"edge", 8, 10, drcEdge,
|
||||
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
|
||||
{"edge4way", 8, 10, drcEdge,
|
||||
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
|
||||
{"exact_overlap", 2, 2, drcExactOverlap,
|
||||
"layers"},
|
||||
{"exact_overlap", 2, 2, drcExactOverlap, "layers"},
|
||||
{"exception", 2, 2, drcException, "name"},
|
||||
{"exemption", 2, 2, drcExemption, "name"},
|
||||
{"extend", 5, 6, drcExtend,
|
||||
"layers1 layers2 distance [option] why"},
|
||||
{"no_overlap", 3, 3, drcNoOverlap,
|
||||
"layers1 layers2"},
|
||||
{"option", 2, 2, drcOption,
|
||||
"option_name option_value"},
|
||||
{"overhang", 5, 5, drcOverhang,
|
||||
"layers1 layers2 distance why"},
|
||||
{"rect_only", 3, 3, drcRectOnly,
|
||||
"layers why"},
|
||||
{"no_overlap", 3, 3, drcNoOverlap, "layers1 layers2"},
|
||||
{"option", 2, 2, drcOption, "option_name option_value"},
|
||||
{"overhang", 5, 5, drcOverhang, "layers1 layers2 distance why"},
|
||||
{"rect_only", 3, 3, drcRectOnly, "layers why"},
|
||||
{"spacing", 6, 7, drcSpacing,
|
||||
"layers1 layers2 separation [layers3] adjacency why"},
|
||||
{"stepsize", 2, 2, drcStepSize,
|
||||
"step_size"},
|
||||
{"stepsize", 2, 2, drcStepSize, "step_size"},
|
||||
{"surround", 6, 7, drcSurround,
|
||||
"layers1 layers2 distance presence why"},
|
||||
{"width", 4, 5, drcWidth,
|
||||
"layers width why"},
|
||||
{"width", 4, 5, drcWidth, "layers width why"},
|
||||
{"widespacing", 7, 8, drcSpacing,
|
||||
"layers1 width layers2 separation adjacency why"},
|
||||
{"area", 5, 5, drcArea,
|
||||
"layers area horizon why"},
|
||||
{"off_grid", 4, 4, drcOffGrid,
|
||||
"layers pitch why"},
|
||||
{"maxwidth", 4, 6, drcMaxwidth,
|
||||
"layers maxwidth bends why"},
|
||||
{"cifstyle", 2, 2, drcCifSetStyle,
|
||||
"cif_style"},
|
||||
{"cifwidth", 4, 4, drcCifWidth,
|
||||
"layers width why"},
|
||||
{"area", 5, 5, drcArea, "layers area horizon why"},
|
||||
{"off_grid", 4, 4, drcOffGrid, "layers pitch why"},
|
||||
{"maxwidth", 4, 6, drcMaxwidth, "layers maxwidth bends why"},
|
||||
{"cifstyle", 2, 2, drcCifSetStyle, "cif_style"},
|
||||
{"cifwidth", 4, 4, drcCifWidth, "layers width why"},
|
||||
{"cifspacing", 6, 6, drcCifSpacing,
|
||||
"layers1 layers2 separation adjacency why"},
|
||||
{"cifarea", 5, 5, drcCifArea,
|
||||
"layers area horizon why"},
|
||||
{"cifmaxwidth", 5, 5, drcCifMaxwidth,
|
||||
"layers maxwidth bends why"},
|
||||
{"cifarea", 5, 5, drcCifArea, "layers area horizon why"},
|
||||
{"cifmaxwidth", 5, 5, drcCifMaxwidth, "layers maxwidth bends why"},
|
||||
{"rectangle", 5, 5, drcRectangle,
|
||||
"layers maxwidth [even|odd|any] why"},
|
||||
{0}
|
||||
|
|
@ -1695,7 +1753,7 @@ drcMaxwidth(argc, argv)
|
|||
if (PlaneMaskHasPlane(pmask2, plane2))
|
||||
break;
|
||||
|
||||
if (plane2 == plane)
|
||||
if (PlaneMaskHasPlane(pmask, plane2))
|
||||
TechError("Warning: Exclude types for \"maxwidth\" are on the "
|
||||
"same plane and so cannot be checked.\n");
|
||||
}
|
||||
|
|
@ -3634,6 +3692,83 @@ drcRectangle(argc, argv)
|
|||
return maxwidth;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* drcException, drcExemption --
|
||||
*
|
||||
* Process a DRC exception declaration
|
||||
* This is of the form:
|
||||
*
|
||||
* exception exception_name|none
|
||||
* or
|
||||
* exemption exemption_name|none
|
||||
*
|
||||
* e.g,
|
||||
*
|
||||
* exception SRAM
|
||||
* exemption SRAM
|
||||
*
|
||||
* The exception_name or exemption_name is the suffix part of a MASKHINTS_*
|
||||
* property name; e.g., the name SRAM corresponds to a property called
|
||||
* MASKHINTS_SRAM. This declaration is followed by a block of DRC rules
|
||||
* that are subject to the exception or the exemption. An exception is the
|
||||
* opposite of an exemption: If a rule is excepted, then the rule applies
|
||||
* within areas delineated by bounding boxes defined by the
|
||||
* MASKHINTS_<exception_name> property. If a rule is exempted, then the
|
||||
* rule applies only outside of areas delineated by bounding boxes defined
|
||||
* by the MASKHINTS_<exemption_name> property. The block of rules subject
|
||||
* to the exemption or exception ends with another exception or exemption
|
||||
* declaration. If the following rules are not to be excepted or exempted
|
||||
* at all, then use "exception none" or "exemption none".
|
||||
*
|
||||
* Results:
|
||||
* Returns 0.
|
||||
*
|
||||
* Side effects:
|
||||
* Updates drcCurException. drcCurException is zero or positive for
|
||||
* exceptions and negative for exemptions. The index can be
|
||||
* recovered from a negative value by negating it and subtracting 1.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
drcException(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int i;
|
||||
|
||||
if (DRCCurStyle == NULL) return 0;
|
||||
|
||||
/* Assume that argc must be 2 because the parser insists upon it */
|
||||
|
||||
if (!strcmp(argv[1], "none"))
|
||||
drcCurException = (char)DRC_EXCEPTION_NONE;
|
||||
else
|
||||
drcCurException = drcExceptionCreate(argv[1]);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
drcExemption(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int i;
|
||||
|
||||
if (DRCCurStyle == NULL) return 0;
|
||||
|
||||
/* Assume that argc must be 2 because the parser insists upon it */
|
||||
|
||||
if (!strcmp(argv[1], "none"))
|
||||
drcCurException = (char)DRC_EXCEPTION_NONE;
|
||||
else
|
||||
drcCurException = -(drcExceptionCreate(argv[1])) - 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -4119,6 +4254,7 @@ drcTechFinalStyle(style)
|
|||
if (dp->drcc_dist > next->drcc_dist) continue;
|
||||
if (dp->drcc_cdist > next->drcc_cdist) continue;
|
||||
if (dp->drcc_plane != next->drcc_plane) continue;
|
||||
if (dp->drcc_exception != next->drcc_exception) continue;
|
||||
if (dp->drcc_flags & DRC_REVERSE)
|
||||
{
|
||||
if (!(next->drcc_flags & DRC_REVERSE)) continue;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ typedef struct drccookie
|
|||
TileTypeBitMask drcc_mask; /* Legal types on RHS */
|
||||
TileTypeBitMask drcc_corner; /* Types that trigger corner check */
|
||||
unsigned short drcc_flags; /* Miscellaneous flags, see below. */
|
||||
char drcc_exception; /* Index to list of exceptions */
|
||||
int drcc_edgeplane; /* Plane of edge */
|
||||
int drcc_plane; /* Index of plane on which to check
|
||||
* legal types. */
|
||||
|
|
@ -91,6 +92,9 @@ typedef struct drccookie
|
|||
#define DRC_UNPROCESSED CLIENTDEFAULT
|
||||
#define DRC_PROCESSED 1
|
||||
|
||||
/* drcc_exception defaults to -128 (0x80) meaning no exceptions/exemptions */
|
||||
#define DRC_EXCEPTION_NONE (char)0x80
|
||||
|
||||
/*
|
||||
* Background DRC (DRC Idle proc) for Tcl-based Magic
|
||||
*/
|
||||
|
|
@ -177,6 +181,8 @@ typedef struct drcstyle
|
|||
unsigned short DRCFlags; /* Option flags */
|
||||
char **DRCWhyList; /* Indexed list of "why" text strings */
|
||||
int DRCWhySize; /* Length of DRCWhyList */
|
||||
char **DRCExceptionList; /* Indexed list of DRC exceptions */
|
||||
int DRCExceptionSize; /* Length of DRCExceptionList */
|
||||
PaintResultType DRCPaintTable[NP][NT][NT];
|
||||
} DRCStyle;
|
||||
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
|
|||
#include "dbwind/dbwind.h" /* for DBWclientID */
|
||||
#include "commands/commands.h" /* for module auto-load */
|
||||
#include "textio/txcommands.h"
|
||||
#include "extract/extract.h" /* for extDevTable */
|
||||
#include "extflat/extflat.h"
|
||||
#include "extflat/EFint.h"
|
||||
#include "extract/extract.h" /* for extDevTable */
|
||||
#include "utils/runstats.h"
|
||||
#include "utils/malloc.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -41,14 +41,11 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
|
|||
#include "commands/commands.h" /* for module auto-load */
|
||||
#include "textio/txcommands.h"
|
||||
#include "extflat/extflat.h"
|
||||
#include "extflat/EFint.h"
|
||||
#include "extract/extract.h" /* for extDevTable */
|
||||
#include "extflat/EFint.h"
|
||||
#include "utils/runstats.h"
|
||||
#include "ext2spice/ext2spice.h"
|
||||
|
||||
/* C99 compat */
|
||||
#include "extflat/extflat.h"
|
||||
|
||||
/* These global values are defined in ext2spice.c */
|
||||
extern HashTable subcktNameTable;
|
||||
extern DQueue subcktNameQueue;
|
||||
|
|
@ -637,7 +634,7 @@ subcktHierVisit(
|
|||
|
||||
if (hasports || is_top)
|
||||
return subcktVisit(use, hierName, is_top);
|
||||
else if (def->def_flags & DEF_NODEVICES)
|
||||
else if ((def->def_flags & DEF_NODEVICES) && (!isStub))
|
||||
return 0;
|
||||
else
|
||||
return subcktVisit(use, hierName, is_top);
|
||||
|
|
@ -1091,6 +1088,7 @@ spcdevHierVisit(
|
|||
|
||||
if (!has_model)
|
||||
{
|
||||
fprintf(esSpiceF, " ");
|
||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
||||
}
|
||||
|
|
@ -1141,6 +1139,7 @@ spcdevHierVisit(
|
|||
|
||||
if (!has_model)
|
||||
{
|
||||
fprintf(esSpiceF, " ");
|
||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
|
|||
#include "dbwind/dbwind.h" /* for DBWclientID */
|
||||
#include "commands/commands.h" /* for module auto-load */
|
||||
#include "textio/txcommands.h"
|
||||
#include "extract/extract.h" /* for extDevTable */
|
||||
#include "extflat/extflat.h"
|
||||
#include "extflat/EFint.h"
|
||||
#include "extract/extract.h" /* for extDevTable */
|
||||
#include "utils/runstats.h"
|
||||
|
||||
#include "ext2spice/ext2spice.h"
|
||||
|
|
@ -1689,23 +1689,43 @@ subcktVisit(
|
|||
HashStartSearch(&hs);
|
||||
while ((he = HashNext(&def->def_nodes, &hs)))
|
||||
{
|
||||
bool found = FALSE;
|
||||
|
||||
sname = (EFNodeName *) HashGetValue(he);
|
||||
if (sname == NULL) continue;
|
||||
snode = sname->efnn_node;
|
||||
|
||||
if ((snode == NULL) || !(snode->efnode_flags & EF_PORT)) continue;
|
||||
|
||||
portidx = snode->efnode_name->efnn_port;
|
||||
|
||||
if (portidx >= 0)
|
||||
{
|
||||
if (nodeList[portidx] == NULL)
|
||||
{
|
||||
nodeList[portidx] = snode->efnode_name;
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Normally there should be a port associated with snode, but
|
||||
* if not, go looking for one in the node name aliases.
|
||||
*/
|
||||
for (nodeName = sname; nodeName != NULL; nodeName = nodeName->efnn_next)
|
||||
{
|
||||
if (found == TRUE) break;
|
||||
|
||||
portidx = nodeName->efnn_port;
|
||||
if (portidx < 0) continue;
|
||||
if (nodeList[portidx] == NULL)
|
||||
{
|
||||
nodeList[portidx] = nodeName;
|
||||
found = TRUE;
|
||||
}
|
||||
else if (EFHNBest(nodeName->efnn_hier, nodeList[portidx]->efnn_hier))
|
||||
{
|
||||
nodeList[portidx] = nodeName;
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1932,6 +1952,7 @@ topVisit(
|
|||
{
|
||||
char stmp[MAX_STR_SIZE];
|
||||
int portidx;
|
||||
bool found = FALSE;
|
||||
|
||||
sname = (EFNodeName *) HashGetValue(he);
|
||||
if (sname == NULL) continue; /* Should not happen */
|
||||
|
|
@ -1939,33 +1960,68 @@ topVisit(
|
|||
snode = sname->efnn_node;
|
||||
if ((!snode) || (!(snode->efnode_flags & EF_PORT))) continue;
|
||||
|
||||
/* Found a node which is also a port */
|
||||
|
||||
portidx = snode->efnode_name->efnn_port;
|
||||
if (portidx >= 0)
|
||||
{
|
||||
if (sorted_ports[portidx] == NULL)
|
||||
{
|
||||
if ((def->def_flags & DEF_ABSTRACT))
|
||||
{
|
||||
EFHNSprintf(stmp, sname->efnn_hier);
|
||||
pname = stmp;
|
||||
}
|
||||
else
|
||||
pname = nodeSpiceName(snode->efnode_name->efnn_hier, NULL);
|
||||
|
||||
hep = HashLookOnly(&portNameTable, pname);
|
||||
if (hep == (HashEntry *)NULL)
|
||||
{
|
||||
hep = HashFind(&portNameTable, pname);
|
||||
HashSetValue(hep, (ClientData)(pointertype)portidx);
|
||||
sorted_ports[portidx] = StrDup((char **)NULL, pname);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Node that was unassigned has been found to be
|
||||
* a repeat (see NOTE at top), so make sure its
|
||||
* port number is set correctly.
|
||||
*/
|
||||
snode->efnode_name->efnn_port = (int)(pointertype)HashGetValue(hep);
|
||||
}
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(def->def_flags & DEF_ABSTRACT))
|
||||
heh = HashLookOnly(&efNodeHashTable, (char *)snode->efnode_name->efnn_hier);
|
||||
|
||||
/* Might need to check here for a port that was optimized out? */
|
||||
|
||||
/* If snode is flagged as a port but no port number was found, then
|
||||
* check the all of the node's name entries to see if any of them has
|
||||
* a port number.
|
||||
*/
|
||||
|
||||
for (nodeName = sname; nodeName != NULL; nodeName = nodeName->efnn_next)
|
||||
{
|
||||
if (found == TRUE) break;
|
||||
portidx = nodeName->efnn_port;
|
||||
if (portidx < 0) continue;
|
||||
|
||||
/* Check if the same hierName is recorded in the flattened/optimized
|
||||
* def's efNodeHashTable. If not, then it has been optimized out
|
||||
* and should be removed from the port list.
|
||||
*/
|
||||
if (def->def_flags & DEF_ABSTRACT)
|
||||
heh = HashLookOnly(&efNodeHashTable, (char *)nodeName->efnn_hier);
|
||||
else
|
||||
heh = HashLookOnly(&efNodeHashTable,
|
||||
(char *)snode->efnode_name->efnn_hier);
|
||||
|
||||
/* If view is abstract, rely on the given port name, not
|
||||
* the node. Otherwise, artifacts of the abstract view
|
||||
* may cause nodes to be merged and the names lost.
|
||||
*/
|
||||
|
||||
if (def->def_flags & DEF_ABSTRACT)
|
||||
{
|
||||
heh = HashLookOnly(&efNodeHashTable, (char *)nodeName->efnn_hier);
|
||||
|
||||
/* If view is abstract, rely on the given port name, not
|
||||
* the node. Otherwise, artifacts of the abstract view
|
||||
* may cause nodes to be merged and the names lost.
|
||||
*/
|
||||
EFHNSprintf(stmp, nodeName->efnn_hier);
|
||||
pname = stmp;
|
||||
}
|
||||
else
|
||||
// pname = nodeSpiceName(snode->efnode_name->efnn_hier, NULL);
|
||||
pname = nodeSpiceName(nodeName->efnn_hier, NULL);
|
||||
|
||||
if (heh == (HashEntry *)NULL) /* pname now resolved for log output */
|
||||
|
|
@ -1983,7 +2039,10 @@ topVisit(
|
|||
hep = HashFind(&portNameTable, pname);
|
||||
HashSetValue(hep, (ClientData)(pointertype)nodeName->efnn_port);
|
||||
if (sorted_ports[portidx] == NULL)
|
||||
{
|
||||
sorted_ports[portidx] = StrDup((char **)NULL, pname);
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3081,6 +3140,7 @@ spcdevVisit(
|
|||
|
||||
if (!has_model)
|
||||
{
|
||||
fprintf(esSpiceF, " ");
|
||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
|
||||
}
|
||||
|
|
@ -3127,6 +3187,7 @@ spcdevVisit(
|
|||
|
||||
if (!has_model)
|
||||
{
|
||||
fprintf(esSpiceF, " ");
|
||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header$";
|
|||
#include "tiles/tile.h"
|
||||
#include "database/database.h" /* for TileType definition */
|
||||
#include "extflat/extflat.h"
|
||||
#include "extflat/extparse.h"
|
||||
#include "extflat/EFint.h"
|
||||
#include "extract/extract.h" /* for device class list */
|
||||
#include "extract/extract.h"
|
||||
#include "extract/extractInt.h" /* for extGetDevType() */
|
||||
|
||||
/* C99 compat */
|
||||
|
|
@ -647,8 +648,21 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
|
|||
return;
|
||||
}
|
||||
else if (!resist)
|
||||
TxError("Warning: Ports \"%s\" and \"%s\" are electrically "
|
||||
{
|
||||
char *uptr1, *uptr2;
|
||||
|
||||
/* Do not generate an error message if one or both node names
|
||||
* is made by "extract unique".
|
||||
*/
|
||||
if ((uptr1 = strstr(nodeName1, "_uq")) != 0) *uptr1 = '\0';
|
||||
if ((uptr2 = strstr(nodeName2, "_uq")) != 0) *uptr2 = '\0';
|
||||
if ((uptr1 == NULL && uptr2 == NULL) ||
|
||||
strcmp(nodeName1, nodeName2))
|
||||
TxError("Warning: Ports \"%s\" and \"%s\" are electrically "
|
||||
"shorted.\n", nodeName1, nodeName2);
|
||||
if (uptr1) *uptr1 = '_';
|
||||
if (uptr2) *uptr2 = '_';
|
||||
}
|
||||
else
|
||||
/* Do not merge the nodes when folding in extresist parasitics */
|
||||
return;
|
||||
|
|
@ -907,6 +921,9 @@ efBuildDevice(
|
|||
case DEV_FET:
|
||||
case DEV_MOSFET:
|
||||
case DEV_ASYMMETRIC:
|
||||
/* Terminals start after L and W values, substrate, and parameters */
|
||||
termstart = 3;
|
||||
break;
|
||||
case DEV_BJT:
|
||||
/* Terminals start after L and W values, plus parameters */
|
||||
termstart = 2;
|
||||
|
|
@ -2099,7 +2116,7 @@ efNodeMerge(node1ptr, node2ptr)
|
|||
/* Make all EFNodeNames point to "keeping" */
|
||||
if (removing->efnode_name)
|
||||
{
|
||||
bool topportk, topportr, bestname;
|
||||
bool topportk, topportr, bestname, swapnames;
|
||||
|
||||
for (nn = removing->efnode_name; nn; nn = nn->efnn_next)
|
||||
{
|
||||
|
|
@ -2110,10 +2127,31 @@ efNodeMerge(node1ptr, node2ptr)
|
|||
topportk = (keeping->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
|
||||
topportr = (removing->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
|
||||
|
||||
/* Concatenate list of EFNodeNames, taking into account precedence */
|
||||
if ((!keeping->efnode_name) || (!topportk && topportr)
|
||||
|| EFHNBest(removing->efnode_name->efnn_hier,
|
||||
keeping->efnode_name->efnn_hier))
|
||||
/* The node "keeping" is being kept, but we need to decide which
|
||||
* node name of the two will be the node name of "keeping". If
|
||||
* "keeping" has the best node name, then we're good; otherwise,
|
||||
* we need to copy the name from "removing" to "keeping".
|
||||
*
|
||||
* Order of precedence:
|
||||
* 1) If one node does not have a name, then use the name of the other.
|
||||
* 2) If one node is a port and the other isn't, then use the port name.
|
||||
* 3) Use the one with the preferred lexigraphical order according to
|
||||
* EFHNBest().
|
||||
*/
|
||||
if ((!keeping->efnode_name) && (removing->efnode_name))
|
||||
swapnames = TRUE;
|
||||
else if ((keeping->efnode_name) && (!removing->efnode_name))
|
||||
swapnames = FALSE;
|
||||
else if (!topportk && topportr)
|
||||
swapnames = TRUE;
|
||||
else if (topportk && !topportr)
|
||||
swapnames = FALSE;
|
||||
else
|
||||
swapnames = EFHNBest(removing->efnode_name->efnn_hier,
|
||||
keeping->efnode_name->efnn_hier);
|
||||
|
||||
/* Concatenate list of EFNodeNames */
|
||||
if (swapnames)
|
||||
{
|
||||
/*
|
||||
* New official name is that of "removing".
|
||||
|
|
@ -2200,6 +2238,14 @@ efNodeMerge(node1ptr, node2ptr)
|
|||
if (removing->efnode_flags & EF_SUBS_NODE)
|
||||
keeping->efnode_flags |= EF_SUBS_NODE;
|
||||
|
||||
/*
|
||||
* If "removing" has the EF_GLOB_SUBS_NODE flag set, then copy the
|
||||
* port record in the flags to "keeping".
|
||||
*/
|
||||
if (removing->efnode_flags & EF_GLOB_SUBS_NODE)
|
||||
keeping->efnode_flags |= EF_GLOB_SUBS_NODE;
|
||||
|
||||
/* If EFSaveLocs is set, then merge any disjoint segments from
|
||||
/* If EFSaveLocs is set, then merge any disjoint segments from
|
||||
* removing to keeping.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -36,9 +36,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "textio/textio.h"
|
||||
|
||||
extern char *efReadFileName;
|
||||
extern int efReadLineNum;
|
||||
#include "extflat/extparse.h"
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
extern int Tcl_printf();
|
||||
|
|
|
|||
|
|
@ -61,15 +61,17 @@ int efFlatGlobHash(HierName *);
|
|||
bool efFlatGlobCmp(HierName *, HierName *);
|
||||
char *efFlatGlobCopy(HierName *);
|
||||
void efFlatGlobError(EFNodeName *nameGlob, EFNodeName *nameFlat);
|
||||
int efAddNodes(HierContext *hc, bool stdcell);
|
||||
int efAddConns(HierContext *hc, bool doWarn);
|
||||
int efAddOneConn(HierContext *hc, char *name1, char *name2, Connection *conn, bool doWarn);
|
||||
int efAddNodes(HierContext *hc, int flags);
|
||||
int efAddConns(HierContext *hc, int flags);
|
||||
int efAddOneConn(HierContext *hc, char *name1, char *name2, Connection *conn, int flags);
|
||||
|
||||
/* Flags passed to efFlatNode() */
|
||||
|
||||
#define FLATNODE_STDCELL 0x01
|
||||
#define FLATNODE_DOWARN 0x02
|
||||
#define FLATNODE_NOABSTRACT 0x04
|
||||
#define FLATNODE_HIER 0x08
|
||||
#define FLATNODE_CHILD 0x10
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -216,7 +218,7 @@ EFFlatBuildOneLevel(def, flags)
|
|||
efFlatRootUse.use_def = efFlatRootDef;
|
||||
|
||||
/* Record all nodes down the hierarchy from here */
|
||||
flatnodeflags = 0; /* No FLATNODE_DOWARN */
|
||||
flatnodeflags = FLATNODE_HIER; /* No FLATNODE_DOWARN */
|
||||
efFlatNodes(&efFlatContext, INT2CD(flatnodeflags));
|
||||
|
||||
/* Expand all subcells that contain connectivity information but */
|
||||
|
|
@ -320,9 +322,7 @@ efFlatNodes(hc, clientData)
|
|||
ClientData clientData;
|
||||
{
|
||||
int flags = (int)CD2INT(clientData);
|
||||
|
||||
bool stdcell = (flags & FLATNODE_STDCELL) ? TRUE : FALSE;
|
||||
bool doWarn = (flags & FLATNODE_DOWARN) ? TRUE : FALSE;
|
||||
int hierflags = 0;
|
||||
|
||||
if (flags & FLATNODE_NOABSTRACT)
|
||||
{
|
||||
|
|
@ -332,13 +332,19 @@ efFlatNodes(hc, clientData)
|
|||
def->def_name);
|
||||
}
|
||||
|
||||
(void) efHierSrUses(hc, efFlatNodes, clientData);
|
||||
/* If called with FLATNODE_HIER set, then set the FLATNODE_CHILD
|
||||
* flag while calling efHierSrUses(), to prevent efAddNodes() from
|
||||
* duplicating the capacitance of nodes in child cells.
|
||||
*/
|
||||
|
||||
hierflags = flags | ((flags & FLATNODE_HIER) ? FLATNODE_CHILD : 0);
|
||||
(void) efHierSrUses(hc, efFlatNodes, INT2CD(hierflags));
|
||||
|
||||
/* Add all our own nodes to the table */
|
||||
efAddNodes(hc, stdcell);
|
||||
efAddNodes(hc, flags);
|
||||
|
||||
/* Process our own connections and adjustments */
|
||||
(void) efAddConns(hc, doWarn);
|
||||
(void) efAddConns(hc, flags);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -386,11 +392,11 @@ efFlatNodesStdCell(hc)
|
|||
}
|
||||
|
||||
/* Add all our own nodes to the table */
|
||||
efAddNodes(hc, TRUE);
|
||||
efAddNodes(hc, (int)FLATNODE_STDCELL);
|
||||
|
||||
/* Process our own connections and adjustments */
|
||||
if (!(hc->hc_use->use_def->def_flags & DEF_SUBCIRCUIT))
|
||||
(void) efAddConns(hc, TRUE);
|
||||
(void) efAddConns(hc, (int)FLATNODE_DOWARN);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -413,10 +419,10 @@ efFlatNodesDeviceless(hc, cdata)
|
|||
if ((HashGetNumEntries(&hc->hc_use->use_def->def_devs) == 0) && (newcount == 0))
|
||||
{
|
||||
/* Add all our own nodes to the table */
|
||||
efAddNodes(hc, TRUE);
|
||||
efAddNodes(hc, (int)FLATNODE_STDCELL);
|
||||
|
||||
/* Process our own connections and adjustments */
|
||||
efAddConns(hc, TRUE);
|
||||
efAddConns(hc, (int)FLATNODE_DOWARN);
|
||||
|
||||
/* Mark this definition as having no devices, so it will not be visited */
|
||||
hc->hc_use->use_def->def_flags |= DEF_NODEVICES;
|
||||
|
|
@ -455,7 +461,7 @@ efFlatNodesDeviceless(hc, cdata)
|
|||
int
|
||||
efAddNodes(
|
||||
HierContext *hc,
|
||||
bool stdcell)
|
||||
int flags)
|
||||
{
|
||||
Def *def = hc->hc_use->use_def;
|
||||
EFNodeName *nn, *newname, *oldname;
|
||||
|
|
@ -465,6 +471,8 @@ efAddNodes(
|
|||
HierName *hierName;
|
||||
int size, asize;
|
||||
HashEntry *he;
|
||||
bool stdcell = (flags & FLATNODE_STDCELL) ? TRUE : FALSE;
|
||||
bool is_child = (flags & FLATNODE_CHILD) ? TRUE : FALSE;
|
||||
bool is_subcircuit = (def->def_flags & DEF_SUBCIRCUIT) ? TRUE : FALSE;
|
||||
|
||||
size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (EFPerimArea);
|
||||
|
|
@ -503,12 +511,15 @@ efAddNodes(
|
|||
// If called with "hierarchy on", all local node caps and adjustments
|
||||
// have been output and should be ignored.
|
||||
|
||||
newnode->efnode_cap = (!stdcell) ? node->efnode_cap : (EFCapValue)0.0;
|
||||
if (!stdcell && !is_child)
|
||||
newnode->efnode_cap = node->efnode_cap;
|
||||
else
|
||||
newnode->efnode_cap = (EFCapValue)0.0;
|
||||
newnode->efnode_client = (ClientData) NULL;
|
||||
newnode->efnode_flags = node->efnode_flags;
|
||||
newnode->efnode_type = node->efnode_type;
|
||||
newnode->efnode_num = 1;
|
||||
if (!stdcell)
|
||||
if (!stdcell && !is_child)
|
||||
bcopy((char *) node->efnode_pa, (char *) newnode->efnode_pa,
|
||||
efNumResistClasses * sizeof (EFPerimArea));
|
||||
else
|
||||
|
|
@ -601,7 +612,7 @@ efAddNodes(
|
|||
int
|
||||
efAddConns(
|
||||
HierContext *hc,
|
||||
bool doWarn)
|
||||
int flags)
|
||||
{
|
||||
Connection *conn;
|
||||
|
||||
|
|
@ -614,9 +625,9 @@ efAddConns(
|
|||
{
|
||||
/* Special case for speed when no array info is present */
|
||||
if (conn->conn_1.cn_nsubs == 0)
|
||||
efAddOneConn(hc, conn->conn_name1, conn->conn_name2, conn, doWarn);
|
||||
efAddOneConn(hc, conn->conn_name1, conn->conn_name2, conn, flags);
|
||||
else
|
||||
efHierSrArray(hc, conn, efAddOneConn, INT2CD(doWarn));
|
||||
efHierSrArray(hc, conn, efAddOneConn, INT2CD(flags));
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
|
@ -648,18 +659,23 @@ efAddOneConn(
|
|||
char *name1, /* These are strings, not HierNames */
|
||||
char *name2,
|
||||
Connection *conn,
|
||||
bool doWarn)
|
||||
int flags)
|
||||
{
|
||||
HashEntry *he1, *he2;
|
||||
EFNode *node, *newnode;
|
||||
int n;
|
||||
|
||||
bool doWarn = (flags & FLATNODE_DOWARN) ? TRUE : FALSE;
|
||||
bool doHier = (flags & FLATNODE_HIER) ? TRUE : FALSE;
|
||||
|
||||
he1 = EFHNLook(hc->hc_hierName, name1, (doWarn) ? "connect(1)" : NULL);
|
||||
if (he1 == NULL)
|
||||
return 0;
|
||||
|
||||
/* Adjust the resistance and capacitance of its corresponding node */
|
||||
node = ((EFNodeName *) HashGetValue(he1))->efnn_node;
|
||||
|
||||
/* Adjust the resistance and capacitance of its corresponding node */
|
||||
|
||||
node->efnode_cap += conn->conn_cap;
|
||||
for (n = 0; n < efNumResistClasses; n++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -82,6 +82,12 @@ extern void efHNRecord();
|
|||
* variables cause nets named VDD and GND to become globals, which was
|
||||
* not intended.
|
||||
*
|
||||
* Updated 1/2026: Also seems like a bad idea to treat the suffix "!"
|
||||
* automatically as a global. By removing this, a global pin must be
|
||||
* manually declared by putting it in the "globals" array variable.
|
||||
* When not compiled with Tcl/Tk support, the original behavior is
|
||||
* implemented.
|
||||
*
|
||||
* Results:
|
||||
* TRUE if the name is a global.
|
||||
*
|
||||
|
|
@ -99,12 +105,10 @@ EFHNIsGlob(hierName)
|
|||
char *retstr;
|
||||
retstr = (char *)Tcl_GetVar2(magicinterp, "globals", hierName->hn_name,
|
||||
TCL_GLOBAL_ONLY);
|
||||
if (retstr != NULL) return TRUE;
|
||||
|
||||
// retstr = (char *)Tcl_GetVar(magicinterp, hierName->hn_name, TCL_GLOBAL_ONLY);
|
||||
// if (retstr != NULL) return TRUE;
|
||||
#endif
|
||||
return (retstr != NULL) ? TRUE : FALSE;
|
||||
#else
|
||||
return hierName->hn_name[strlen(hierName->hn_name) - 1] == '!';
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -520,13 +524,22 @@ EFHNBest(hierName1, hierName2)
|
|||
|
||||
last1 = hierName1->hn_name[strlen(hierName1->hn_name) - 1];
|
||||
last2 = hierName2->hn_name[strlen(hierName2->hn_name) - 1];
|
||||
|
||||
if (last1 != '!' || last2 != '!')
|
||||
{
|
||||
#if 0
|
||||
/* NOTE (Jan. 31, 2026): The handling of trailing "!" as a global
|
||||
* is at best incorrect; the node output should not consider the
|
||||
* ancestor hierarchy, but it does. I am disabling the check here,
|
||||
* and treating all names as local. It could be reinstated, but
|
||||
* I think global names are just a bad idea altogether.
|
||||
*/
|
||||
/* Prefer global over local names */
|
||||
if (last1 == '!') return TRUE;
|
||||
if (last2 == '!') return FALSE;
|
||||
#endif
|
||||
|
||||
/* Neither name is global, so chose label over generated name */
|
||||
/* Neither name is global, so choose label over generated name */
|
||||
if (last1 != '#' && last2 == '#') return TRUE;
|
||||
if (last1 == '#' && last2 != '#') return FALSE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "commands/commands.h"
|
||||
#include "database/database.h"
|
||||
#include "extflat/extflat.h"
|
||||
#include "extflat/extparse.h"
|
||||
#include "extflat/EFint.h"
|
||||
#include "extract/extract.h"
|
||||
#include "extract/extractInt.h"
|
||||
|
|
@ -48,58 +49,11 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#ifndef MAGIC_WRAPPER
|
||||
/* This must match the definition for extDevTable in extract/ExtBasic.c */
|
||||
const char * const extDevTable[] = {"fet", "mosfet", "asymmetric", "bjt", "devres",
|
||||
"devcap", "devcaprev", "vsource", "diode", "pdiode",
|
||||
"ndiode", "subckt", "rsubckt", "msubckt", "csubckt",
|
||||
"dsubckt", "veriloga", NULL};
|
||||
"devcap", "devcaprev", "vsource", "diode", "pdiode",
|
||||
"ndiode", "subckt", "rsubckt", "msubckt", "csubckt",
|
||||
"dsubckt", "veriloga", NULL};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following table describes the kinds of lines
|
||||
* that may be read in a .ext file.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
ABSTRACT, ADJUST, ATTR, CAP, DEVICE, DIST, EQUIV, FET, KILLNODE, MERGE,
|
||||
NODE, PARAMETERS, PORT, PRIMITIVE, RESISTOR, RESISTCLASS, RNODE, SCALE,
|
||||
SUBCAP, SUBSTRATE, TECH, TIMESTAMP, USE, VERSION, EXT_STYLE
|
||||
} Key;
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *k_name; /* Name of first token on line */
|
||||
Key k_key; /* Internal name for token of this type */
|
||||
int k_mintokens; /* Min total # of tokens on line of this type */
|
||||
}
|
||||
keyTable[] =
|
||||
{
|
||||
{"abstract", ABSTRACT, 0}, /* defines a LEF-like view */
|
||||
{"adjust", ADJUST, 4},
|
||||
{"attr", ATTR, 8},
|
||||
{"cap", CAP, 4},
|
||||
{"device", DEVICE, 11}, /* effectively replaces "fet" */
|
||||
{"distance", DIST, 4},
|
||||
{"equiv", EQUIV, 3},
|
||||
{"fet", FET, 12}, /* for backwards compatibility */
|
||||
{"killnode", KILLNODE, 2},
|
||||
{"merge", MERGE, 3},
|
||||
{"node", NODE, 7},
|
||||
{"parameters", PARAMETERS, 3},
|
||||
{"port", PORT, 8},
|
||||
{"primitive", PRIMITIVE, 0}, /* defines a primitive device */
|
||||
{"resist", RESISTOR, 4},
|
||||
{"resistclasses", RESISTCLASS, 1},
|
||||
{"rnode", RNODE, 5},
|
||||
{"scale", SCALE, 4},
|
||||
{"subcap", SUBCAP, 3},
|
||||
{"substrate", SUBSTRATE, 3},
|
||||
{"tech", TECH, 2},
|
||||
{"timestamp", TIMESTAMP, 2},
|
||||
{"use", USE, 9},
|
||||
{"version", VERSION, 2},
|
||||
{"style", EXT_STYLE, 2},
|
||||
{0}
|
||||
};
|
||||
|
||||
/* Data shared with EFerror.c */
|
||||
char *efReadFileName; /* Name of file currently being read */
|
||||
int efReadLineNum; /* Current line number in above file */
|
||||
|
|
@ -109,10 +63,6 @@ bool EFSaveLocs; /* If TRUE, save location of merged top-level nodes */
|
|||
/* Data local to this file */
|
||||
static bool efReadDef(Def *def, bool dosubckt, bool resist, bool noscale, bool toplevel, bool isspice);
|
||||
|
||||
/* atoCap - convert a string to a EFCapValue */
|
||||
#define atoCap(s) ((EFCapValue)atof(s))
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
#include "extflat/EFtypes.h" /* EFCapValue, HierName, EFPerimArea, EFNode */
|
||||
#include "extflat/EFint.h" /* Def, HierContext, Connection, Distance, CallArg */
|
||||
|
||||
|
||||
extern float EFScale; /* Scale factor to multiply all coords by */
|
||||
extern char *EFTech; /* Technology of extracted circuit */
|
||||
extern char *EFStyle; /* Extraction style of extracted circuit */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* extparse.h
|
||||
*
|
||||
* Definitions for the .ext file parser. Relocated from EFread.c.
|
||||
*
|
||||
* *********************************************************************
|
||||
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
||||
* * Permission to use, copy, modify, and distribute this *
|
||||
* * software and its documentation for any purpose and without *
|
||||
* * fee is hereby granted, provided that the above copyright *
|
||||
* * notice appear in all copies. The University of California *
|
||||
* * makes no representations about the suitability of this *
|
||||
* * software for any purpose. It is provided "as is" without *
|
||||
* * express or implied warranty. Export of this software outside *
|
||||
* * of the United States of America may require an export license. *
|
||||
* *********************************************************************
|
||||
*/
|
||||
|
||||
#ifndef _MAGIC__EXTFLAT__EXTPARSE_H
|
||||
#define _MAGIC__EXTFLAT__EXTPARSE_H
|
||||
|
||||
/*
|
||||
* The following table describes the kinds of lines
|
||||
* that may be read in a .ext file.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
ABSTRACT, ADJUST, ATTR, CAP, DEVICE, DIST, EQUIV, FET, KILLNODE, MERGE,
|
||||
NODE, PARAMETERS, PORT, PRIMITIVE, RESISTOR, RESISTCLASS, RNODE, SCALE,
|
||||
SUBCAP, SUBSTRATE, TECH, TIMESTAMP, USE, VERSION, EXT_STYLE
|
||||
} Key;
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *k_name; /* Name of first token on line */
|
||||
Key k_key; /* Internal name for token of this type */
|
||||
int k_mintokens; /* Min total # of tokens on line of this type */
|
||||
}
|
||||
keyTable[] =
|
||||
{
|
||||
{"abstract", ABSTRACT, 0}, /* defines a LEF-like view */
|
||||
{"adjust", ADJUST, 4},
|
||||
{"attr", ATTR, 8},
|
||||
{"cap", CAP, 4},
|
||||
{"device", DEVICE, 11}, /* effectively replaces "fet" */
|
||||
{"distance", DIST, 4},
|
||||
{"equiv", EQUIV, 3},
|
||||
{"fet", FET, 12}, /* for backwards compatibility */
|
||||
{"killnode", KILLNODE, 2},
|
||||
{"merge", MERGE, 3},
|
||||
{"node", NODE, 7},
|
||||
{"parameters", PARAMETERS, 3},
|
||||
{"port", PORT, 8},
|
||||
{"primitive", PRIMITIVE, 0}, /* defines a primitive device */
|
||||
{"resist", RESISTOR, 4},
|
||||
{"resistclasses", RESISTCLASS, 1},
|
||||
{"rnode", RNODE, 5},
|
||||
{"scale", SCALE, 4},
|
||||
{"subcap", SUBCAP, 3},
|
||||
{"substrate", SUBSTRATE, 3},
|
||||
{"tech", TECH, 2},
|
||||
{"timestamp", TIMESTAMP, 2},
|
||||
{"use", USE, 9},
|
||||
{"version", VERSION, 2},
|
||||
{"style", EXT_STYLE, 2},
|
||||
{0}
|
||||
};
|
||||
|
||||
/* atoCap - convert a string to a EFCapValue */
|
||||
#define atoCap(s) ((EFCapValue)atof(s))
|
||||
|
||||
extern int efReadLineNum; /* Current line number in the .ext file */
|
||||
extern char *efReadFileName; /* Name of current .ext file being read */
|
||||
|
||||
#endif /* _MAGIC__EXTFLAT__EXTPARSE_H */
|
||||
|
|
@ -37,6 +37,7 @@ static char sccsid[] = "@(#)ExtBasic.c 4.13 MAGIC (Berkeley) 12/5/85";
|
|||
#include "utils/malloc.h"
|
||||
#include "textio/textio.h"
|
||||
#include "debug/debug.h"
|
||||
#include "extflat/extparse.h"
|
||||
#include "extract/extract.h"
|
||||
#include "extract/extractInt.h"
|
||||
#include "utils/signals.h"
|
||||
|
|
@ -85,6 +86,8 @@ typedef struct /* Position of each terminal (below) tile position */
|
|||
{
|
||||
int pnum;
|
||||
Point pt;
|
||||
Tile *tile; /* Any tile beloging to the terminal */
|
||||
TileType type; /* Type of "tile", including split information */
|
||||
} TermTilePos;
|
||||
|
||||
/* Field definitions for tr_devmatch */
|
||||
|
|
@ -147,6 +150,7 @@ int extTransTileFunc();
|
|||
int extTransPerimFunc();
|
||||
int extTransFindSubs();
|
||||
int extTransFindId();
|
||||
void extTermAPFunc();
|
||||
|
||||
int extAnnularTileFunc();
|
||||
int extResistorTileFunc();
|
||||
|
|
@ -322,7 +326,7 @@ extBasic(def, outFile)
|
|||
}
|
||||
|
||||
/* Check for "device", as it modifies handling of parasitics */
|
||||
propptr = (char *)DBPropGet(def, "device", &propfound);
|
||||
propptr = DBPropGetString(def, "device", &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
/* Remove parasitics from local nodes */
|
||||
|
|
@ -798,14 +802,34 @@ extOutputNodes(nodeList, outFile)
|
|||
lastname = ll->ll_label->lab_text;
|
||||
}
|
||||
/* Don't print a warning unless both labels are
|
||||
* really ports.
|
||||
* really ports. Also, don't print a warning for
|
||||
* names generated by "extract unique" vs. real
|
||||
* pin names or another unique name---"extract
|
||||
* unique" does not observe where nets pass through
|
||||
* subcircuits, so it tends to over-generated
|
||||
* unique names, which "ext2spice" will filter out.
|
||||
* For a net to be shorted to itself is not an error.
|
||||
* NOTE: Potentially the unique name could be removed
|
||||
* here and save ext2spice the trouble.
|
||||
*/
|
||||
if ((portname != NULL) &&
|
||||
(ll->ll_attr == LL_PORTATTR) &&
|
||||
(strcmp(ll->ll_label->lab_text, portname)))
|
||||
TxError("Warning: Ports \"%s\" and \"%s\" are"
|
||||
" electrically shorted.\n",
|
||||
text, ll->ll_label->lab_text);
|
||||
{
|
||||
char *uptr1, *uptr2;
|
||||
uptr1 = strstr(text, "_uq");
|
||||
uptr2 = strstr(ll->ll_label->lab_text, "_uq");
|
||||
if (uptr1) *uptr1 = '\0';
|
||||
if (uptr2) *uptr2 = '\0';
|
||||
if (strcmp(text, ll->ll_label->lab_text))
|
||||
{
|
||||
TxError("Warning: Ports \"%s\" and \"%s\" are"
|
||||
" electrically shorted.\n",
|
||||
text, ll->ll_label->lab_text);
|
||||
}
|
||||
if (uptr1) *uptr1 = '_';
|
||||
if (uptr2) *uptr2 = '_';
|
||||
}
|
||||
if (!isPort && (ll->ll_attr == LL_PORTATTR))
|
||||
portname = ll->ll_label->lab_text;
|
||||
}
|
||||
|
|
@ -1678,7 +1702,7 @@ extOutputParameters(def, transList, outFile)
|
|||
* and device name, and if detected, add the type corresponding to the
|
||||
* device name to the mask so it gets handled, too.
|
||||
*/
|
||||
propptr = DBPropGet(def, "device", &propfound);
|
||||
propptr = DBPropGetString(def, "device", &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
char *devname;
|
||||
|
|
@ -1811,6 +1835,8 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
|
|||
ParamList *chkParam;
|
||||
HashEntry *he;
|
||||
ResValue resvalue;
|
||||
LabRegion *node; /* Node connected to gate terminal */
|
||||
LabelList *ll; /* Gate's label list */
|
||||
|
||||
for (chkParam = devptr->exts_deviceParams; chkParam
|
||||
!= NULL; chkParam = chkParam->pl_next)
|
||||
|
|
@ -1942,6 +1968,34 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there are device attribute labels (labels attached to the device
|
||||
* type ending with "^") with "=" in them, then treat them as extra
|
||||
* parameters. Output each one and remove the gate attribute property
|
||||
* from the label.
|
||||
*/
|
||||
|
||||
node = (LabRegion *)ExtGetRegion(reg->treg_tile, reg->treg_dinfo);
|
||||
for (ll = node->lreg_labels; ll; ll = ll->ll_next)
|
||||
{
|
||||
if (ll->ll_attr == LL_GATEATTR)
|
||||
{
|
||||
char cs, *ct, *cp = ll->ll_label->lab_text;
|
||||
if (strchr(cp, '=') != NULL)
|
||||
{
|
||||
/* Since this is an attribute label, it has a special character
|
||||
* at the end, which needs to be stripped off while printing
|
||||
* and then put back again.
|
||||
*/
|
||||
ct = ll->ll_label->lab_text + strlen(ll->ll_label->lab_text) - 1;
|
||||
cs = *ct;
|
||||
*ct = '\0';
|
||||
fprintf(outFile, " %s", ll->ll_label->lab_text);
|
||||
ll->ll_attr = LL_NOATTR;
|
||||
*ct = cs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Structures used by extTermAPFunc() for storing area and perimeter data */
|
||||
|
|
@ -2168,8 +2222,6 @@ extTransFindTermArea(tile, dinfo, eapd)
|
|||
TileType dinfo;
|
||||
ExtAreaPerimData *eapd;
|
||||
{
|
||||
void extTermAPFunc(); /* Forward declaration */
|
||||
|
||||
extEnumTerminal(tile, dinfo, DBConnectTbl, extTermAPFunc, (ClientData)eapd);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -2257,6 +2309,8 @@ extOutputDevices(def, transList, outFile)
|
|||
extTransRec.tr_termpos[i].pnum = 0;
|
||||
extTransRec.tr_termpos[i].pt.p_x = 0;
|
||||
extTransRec.tr_termpos[i].pt.p_y = 0;
|
||||
extTransRec.tr_termpos[i].tile = NULL;
|
||||
extTransRec.tr_termpos[i].type = TT_SPACE;
|
||||
}
|
||||
|
||||
arg.fra_def = def;
|
||||
|
|
@ -2281,6 +2335,58 @@ extOutputDevices(def, transList, outFile)
|
|||
arg.fra_each = extTransTileFunc;
|
||||
ntiles = ExtFindNeighbors(reg->treg_tile, reg->treg_dinfo, arg.fra_pNum, &arg);
|
||||
|
||||
/* Once the entire device has been marked with the device region,
|
||||
* replacing the node region, search each terminal to determine
|
||||
* if the terminal is shared by multiple devices. Note that this
|
||||
* algorithm is not foolproof: In the rare case that three or more
|
||||
* devices share the same terminal, and more than one of them have
|
||||
* the same gate, then those gates will have the same node record and
|
||||
* will not be seen as individual devices.
|
||||
*/
|
||||
|
||||
for (i = 0; i < MAXSD; i++)
|
||||
{
|
||||
Tile *termtile = extTransRec.tr_termpos[i].tile;
|
||||
if (termtile != NULL)
|
||||
{
|
||||
/* Find the area and perimeter of the terminal area (connected
|
||||
* area outside the boundary on a single plane). Note that
|
||||
* this does not consider terminal area outside of the cell
|
||||
* or how area or perimeter may be shared or overlap between
|
||||
* devices.
|
||||
*/
|
||||
|
||||
int shared;
|
||||
ExtAreaPerimData eapd;
|
||||
TileType termtype = extTransRec.tr_termpos[i].type;
|
||||
|
||||
eapd.eapd_area = eapd.eapd_perim = 0;
|
||||
TTMaskCom2(&eapd.eapd_mask, &DBConnectTbl[termtype & TT_LEFTMASK]);
|
||||
eapd.eapd_gatemask = &ExtCurStyle->exts_deviceMask;
|
||||
eapd.eapd_gatenode = (NodeRegion *)reg;
|
||||
eapd.eapd_shared = NULL;
|
||||
|
||||
extEnumTerminal(termtile,
|
||||
termtype & (TT_DIAGONAL | TT_SIDE | TT_DIRECTION),
|
||||
DBConnectTbl, extTermAPFunc,
|
||||
(ClientData)&eapd);
|
||||
|
||||
shared = 1; /* Count self since we divide by "shared" */
|
||||
free_magic1_t mm1 = freeMagic1_init();
|
||||
while (eapd.eapd_shared)
|
||||
{
|
||||
shared++;
|
||||
freeMagic1(&mm1, eapd.eapd_shared);
|
||||
eapd.eapd_shared = eapd.eapd_shared->nl_next;
|
||||
}
|
||||
freeMagic1_end(&mm1);
|
||||
|
||||
extTransRec.tr_termarea[i] = eapd.eapd_area;
|
||||
extTransRec.tr_termperim[i] = eapd.eapd_perim;
|
||||
extTransRec.tr_termshared[i] = shared;
|
||||
}
|
||||
}
|
||||
|
||||
/* Re-mark with extTransRec.tr_gatenode */
|
||||
arg.fra_uninit = (ClientData) reg;
|
||||
arg.fra_region = (ExtRegion *) extTransRec.tr_gatenode;
|
||||
|
|
@ -3911,8 +4017,11 @@ extTransPerimFunc(bp)
|
|||
extTransRec.tr_termvector[thisterm].p_y = 0;
|
||||
extTransRec.tr_termpos[thisterm].pnum = DBPlane(toutside);
|
||||
extTransRec.tr_termpos[thisterm].pt = bp->b_outside->ti_ll;
|
||||
|
||||
/* Find the total area of this terminal */
|
||||
/* tile and dinfo need only be one valid terminal tile,
|
||||
* and do not need to be updated.
|
||||
*/
|
||||
extTransRec.tr_termpos[thisterm].tile = bp->b_outside;
|
||||
extTransRec.tr_termpos[thisterm].type = dinfo | toutside;
|
||||
}
|
||||
else if (extTransRec.tr_termnode[thisterm] == termNode)
|
||||
{
|
||||
|
|
@ -3944,42 +4053,6 @@ extTransPerimFunc(bp)
|
|||
/* Add the length to this terminal's perimeter */
|
||||
extTransRec.tr_termlen[thisterm] += len;
|
||||
|
||||
if (extTransRec.tr_termarea[thisterm] == 0)
|
||||
{
|
||||
/* Find the area and perimeter of the terminal area (connected
|
||||
* area outside the boundary on a single plane). Note that
|
||||
* this does not consider terminal area outside of the cell
|
||||
* or how area or perimeter may be shared or overlap between
|
||||
* devices.
|
||||
*/
|
||||
|
||||
ExtAreaPerimData eapd;
|
||||
int shared;
|
||||
|
||||
eapd.eapd_area = eapd.eapd_perim = 0;
|
||||
TTMaskCom2(&eapd.eapd_mask, &DBConnectTbl[toutside]);
|
||||
eapd.eapd_gatemask = &ExtCurStyle->exts_deviceMask;
|
||||
eapd.eapd_gatenode = extTransRec.tr_gatenode;
|
||||
eapd.eapd_shared = NULL;
|
||||
|
||||
extEnumTerminal(bp->b_outside, dinfo, DBConnectTbl,
|
||||
extTermAPFunc, (ClientData)&eapd);
|
||||
|
||||
shared = 0;
|
||||
free_magic1_t mm1 = freeMagic1_init();
|
||||
while (eapd.eapd_shared)
|
||||
{
|
||||
shared++;
|
||||
freeMagic1(&mm1, eapd.eapd_shared);
|
||||
eapd.eapd_shared = eapd.eapd_shared->nl_next;
|
||||
}
|
||||
freeMagic1_end(&mm1);
|
||||
|
||||
extTransRec.tr_termarea[thisterm] = eapd.eapd_area;
|
||||
extTransRec.tr_termperim[thisterm] = eapd.eapd_perim;
|
||||
extTransRec.tr_termshared[thisterm] = shared;
|
||||
}
|
||||
|
||||
/* Update the boundary traversal vector */
|
||||
switch(bp->b_direction) {
|
||||
case BD_LEFT:
|
||||
|
|
@ -4994,9 +5067,12 @@ extFindNodes(def, clipArea, subonly)
|
|||
/* If the default substrate type is set, it is used *only* for */
|
||||
/* isolated substrate regions and does not mark the default */
|
||||
/* substrate, so remove it from the list of substrate types. */
|
||||
/* Note that this is not the case when doing full R-C */
|
||||
/* extraction. */
|
||||
|
||||
if (ExtCurStyle->exts_globSubstrateDefaultType != -1)
|
||||
TTMaskClearType(&subsTypesNonSpace,
|
||||
if (!(ExtOptions & EXT_DOEXTRESIST))
|
||||
if (ExtCurStyle->exts_globSubstrateDefaultType != -1)
|
||||
TTMaskClearType(&subsTypesNonSpace,
|
||||
ExtCurStyle->exts_globSubstrateDefaultType);
|
||||
|
||||
pNum = ExtCurStyle->exts_globSubstratePlane;
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
|
||||
/* Forward declarations */
|
||||
int extOutputUsesFunc();
|
||||
FILE *extFileOpen();
|
||||
|
||||
Plane* extCellFile();
|
||||
void extHeader();
|
||||
|
|
@ -96,7 +95,7 @@ ExtCell(def, outName, doLength)
|
|||
if (def->cd_flags & CDNOEXTRACT)
|
||||
return extPrepSubstrate(def);
|
||||
|
||||
f = extFileOpen(def, outName, "w", &filename);
|
||||
f = ExtFileOpen(def, outName, "w", &filename);
|
||||
|
||||
TxPrintf("Extracting %s into %s:\n", def->cd_name, filename);
|
||||
|
||||
|
|
@ -132,7 +131,7 @@ ExtCell(def, outName, doLength)
|
|||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* extFileOpen --
|
||||
* ExtFileOpen --
|
||||
*
|
||||
* Open the .ext file corresponding to a .mag file.
|
||||
* If def->cd_file is non-NULL, the .ext file is just def->cd_file with
|
||||
|
|
@ -150,7 +149,7 @@ ExtCell(def, outName, doLength)
|
|||
*/
|
||||
|
||||
FILE *
|
||||
extFileOpen(def, file, mode, prealfile)
|
||||
ExtFileOpen(def, file, mode, prealfile)
|
||||
CellDef *def; /* Cell whose .ext file is to be written */
|
||||
char *file; /* If non-NULL, open 'name'.ext; otherwise,
|
||||
* derive filename from 'def' as described
|
||||
|
|
@ -486,8 +485,17 @@ extCellFile(def, f, doLength)
|
|||
|
||||
UndoDisable();
|
||||
|
||||
/* If "extract do unique" was specified, then make labels in the
|
||||
* cell unique.
|
||||
*/
|
||||
if (ExtOptions & EXT_DOUNIQUE)
|
||||
extUniqueCell(def, EXT_UNIQ_TEMP);
|
||||
|
||||
/* Prep any isolated substrate areas */
|
||||
saveSub = extPrepSubstrate(def);
|
||||
if (ExtOptions & EXT_DOEXTRESIST)
|
||||
saveSub = extResPrepSubstrate(def);
|
||||
else
|
||||
saveSub = extPrepSubstrate(def);
|
||||
|
||||
/* Remove any label markers that were made by a previous extraction */
|
||||
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
||||
|
|
@ -586,7 +594,7 @@ extHeader(def, f)
|
|||
/* are to be passed to instances of the cell */
|
||||
/* (created by defining property "parameter") */
|
||||
|
||||
propvalue = (char *)DBPropGet(def, "parameter", &propfound);
|
||||
propvalue = DBPropGetString(def, "parameter", &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
// Use device parameter table to store the cell def parameters,
|
||||
|
|
|
|||
|
|
@ -1289,6 +1289,14 @@ extFindOverlap(tp, area, esws)
|
|||
TileType tin = TiGetType(bp->b_inside);
|
||||
TileType tout = TiGetType(bp->b_outside);
|
||||
|
||||
/* Get residues
|
||||
* (Note: Isn't it better to include contacts in the tables?)
|
||||
*/
|
||||
if (DBIsContact(tin))
|
||||
tin = DBPlaneToResidue(tin, esws->plane_of_boundary);
|
||||
if (DBIsContact(tout))
|
||||
tout = DBPlaneToResidue(tout, esws->plane_of_boundary);
|
||||
|
||||
pMask = ExtCurStyle->exts_sideOverlapOtherPlanes[tin][tout];
|
||||
extOverlapDef = esws->def;
|
||||
|
||||
|
|
|
|||
|
|
@ -354,8 +354,8 @@ extHierConnections(ha, cumFlat, oneFlat)
|
|||
if (!(lab->lab_flags & LABEL_STICKY)) continue;
|
||||
|
||||
r = lab->lab_rect;
|
||||
if (!GEO_TOUCH(&r, &ha->ha_subArea)) continue;
|
||||
GEOCLIP(&r, &ha->ha_subArea);
|
||||
if (GEO_RECTNULL(&r)) continue;
|
||||
|
||||
cumDef = cumFlat->et_use->cu_def;
|
||||
connected = &DBConnectTbl[lab->lab_type];
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "debug/debug.h"
|
||||
#include "extract/extract.h"
|
||||
#include "extract/extractInt.h"
|
||||
#include "resis/resis.h"
|
||||
#include "utils/signals.h"
|
||||
#include "utils/stack.h"
|
||||
#include "utils/utils.h"
|
||||
|
|
@ -43,9 +44,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/main.h"
|
||||
#include "utils/undo.h"
|
||||
|
||||
/* Imports from elsewhere in this module */
|
||||
extern FILE *extFileOpen();
|
||||
|
||||
/* ------------------------ Exported variables ------------------------ */
|
||||
|
||||
/*
|
||||
|
|
@ -83,16 +81,6 @@ typedef struct _linkedDef {
|
|||
struct _linkedDef *ld_next;
|
||||
} LinkedDef;
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
/* Stack of defs pending extraction */
|
||||
Stack *extDefStack;
|
||||
|
||||
|
|
@ -606,7 +594,7 @@ extParents(use, doExtract)
|
|||
extDefParentFunc(use->cu_def);
|
||||
|
||||
/* Now extract all the cells we just found */
|
||||
extExtractStack(extDefStack, doExtract, (CellDef *) NULL);
|
||||
extExtractStack(extDefStack, doExtract, (CellDef *)NULL);
|
||||
StackFree(extDefStack);
|
||||
|
||||
/* Replace any modified substrate planes in use->cu_def's children */
|
||||
|
|
@ -688,7 +676,7 @@ ExtParentArea(use, changedArea, doExtract)
|
|||
extDefParentAreaFunc(use->cu_def, use->cu_def, (CellUse *) NULL, &area);
|
||||
|
||||
/* Now extract all the cells we just found */
|
||||
extExtractStack(extDefStack, doExtract, (CellDef *) NULL);
|
||||
extExtractStack(extDefStack, doExtract, (CellDef *)NULL);
|
||||
StackFree(extDefStack);
|
||||
}
|
||||
|
||||
|
|
@ -806,12 +794,30 @@ ExtractOneCell(def, outName, doLength)
|
|||
|
||||
savePlane = ExtCell(def, outName, doLength);
|
||||
|
||||
/* Restore all modified substrate planes */
|
||||
/* Run full R-C extraction if specified in options */
|
||||
|
||||
if (ExtOptions & EXT_DOEXTRESIST)
|
||||
{
|
||||
ResisData *resisdata = ResInit();
|
||||
|
||||
UndoDisable();
|
||||
|
||||
ResOptionsFlags |= ResOpt_Signal;
|
||||
resisdata->mainDef = def;
|
||||
resisdata->savePlanes = (struct saveList *)NULL; /* unused */
|
||||
|
||||
ExtResisForDef(def, resisdata);
|
||||
|
||||
UndoEnable();
|
||||
}
|
||||
|
||||
/* Restore all modified substrate planes and modified labels */
|
||||
|
||||
if (savePlane != NULL) ExtRevertSubstrate(def, savePlane);
|
||||
free_magic1_t mm1 = freeMagic1_init();
|
||||
for (; sl; sl = sl->sl_next)
|
||||
{
|
||||
if (EXT_DOUNIQUE) ExtRevertUniqueCell(sl->sl_def);
|
||||
ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
|
||||
freeMagic1(&mm1, sl);
|
||||
}
|
||||
|
|
@ -944,7 +950,7 @@ extTimestampMisMatch(def)
|
|||
|
||||
doLocal = (ExtLocalPath == NULL) ? FALSE : TRUE;
|
||||
|
||||
extFile = extFileOpen(def, (char *) NULL, "r", (char **) NULL);
|
||||
extFile = ExtFileOpen(def, (char *) NULL, "r", (char **) NULL);
|
||||
if (extFile == NULL)
|
||||
return (TRUE);
|
||||
|
||||
|
|
@ -990,10 +996,18 @@ extExtractStack(stack, doExtract, rootDef)
|
|||
bool first = TRUE;
|
||||
Plane *savePlane;
|
||||
CellDef *def;
|
||||
LinkedDef *savelist = NULL, *revlist = NULL, *newld;
|
||||
struct saveList *newsl, *sl = (struct saveList *)NULL;
|
||||
|
||||
while ((def = (CellDef *) StackPop(stack)))
|
||||
{
|
||||
if (ExtOptions & EXT_DOEXTRESIST)
|
||||
{
|
||||
newld = (LinkedDef *)mallocMagic(sizeof(LinkedDef));
|
||||
newld->ld_def = def;
|
||||
newld->ld_next = savelist;
|
||||
savelist = newld;
|
||||
}
|
||||
def->cd_client = (ClientData) 0;
|
||||
if (!SigInterruptPending)
|
||||
{
|
||||
|
|
@ -1026,10 +1040,50 @@ extExtractStack(stack, doExtract, rootDef)
|
|||
}
|
||||
}
|
||||
|
||||
/* Replace any modified substrate planes */
|
||||
/* Now that all cells have been processed, run full R-C extraction */
|
||||
if (ExtOptions & EXT_DOEXTRESIST)
|
||||
{
|
||||
ResisData *resisdata = ResInit();
|
||||
LinkedDef *srchld, *nextld;
|
||||
|
||||
UndoDisable();
|
||||
|
||||
/* Reverse the linked list from top-down to bottom-up */
|
||||
srchld = savelist;
|
||||
while (srchld != NULL)
|
||||
{
|
||||
nextld = srchld->ld_next;
|
||||
srchld->ld_next = revlist;
|
||||
revlist = srchld;
|
||||
srchld = nextld;
|
||||
}
|
||||
|
||||
/* Reprocess the list and call "extresist" for each cell def */
|
||||
srchld = revlist;
|
||||
while (srchld != NULL)
|
||||
{
|
||||
nextld = srchld->ld_next;
|
||||
def = srchld->ld_def;
|
||||
|
||||
ResOptionsFlags |= ResOpt_Signal;
|
||||
resisdata->mainDef = def;
|
||||
resisdata->savePlanes = (struct saveList *)NULL; /* unused */
|
||||
|
||||
TxPrintf("Processing cell %s for resistance extraction.\n", def->cd_name);
|
||||
ExtResisForDef(def, resisdata);
|
||||
|
||||
freeMagic(srchld);
|
||||
srchld = nextld;
|
||||
}
|
||||
UndoEnable();
|
||||
}
|
||||
|
||||
/* Replace any modified substrate planes and modified labels */
|
||||
free_magic1_t mm1 = freeMagic1_init();
|
||||
for (; sl; sl = sl->sl_next)
|
||||
{
|
||||
if (EXT_DOUNIQUE) ExtRevertUniqueCell(sl->sl_def);
|
||||
|
||||
ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
|
||||
sl->sl_def->cd_flags &= ~CDNOEXTRACT;
|
||||
freeMagic1(&mm1, sl);
|
||||
|
|
|
|||
|
|
@ -251,6 +251,17 @@ extSubtree(parentUse, reg, f)
|
|||
if (result == 0) {
|
||||
/* If result == FALSE then ha.ha_interArea is invalid. */
|
||||
ha.ha_interArea = rlab;
|
||||
/* Ensure that the interaction area is not zero */
|
||||
if (ha.ha_interArea.r_xtop - ha.ha_interArea.r_xbot == 0)
|
||||
{
|
||||
ha.ha_interArea.r_xtop++;
|
||||
ha.ha_interArea.r_xbot--;
|
||||
}
|
||||
if (ha.ha_interArea.r_ytop - ha.ha_interArea.r_ybot == 0)
|
||||
{
|
||||
ha.ha_interArea.r_ytop++;
|
||||
ha.ha_interArea.r_ybot--;
|
||||
}
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
|
|
@ -779,6 +790,7 @@ extSubtreeFunc(scx, ha)
|
|||
*/
|
||||
ha->ha_subArea = use->cu_bbox;
|
||||
GEOCLIP(&ha->ha_subArea, &ha->ha_interArea);
|
||||
|
||||
hy.hy_area = &ha->ha_subArea;
|
||||
hy.hy_target = oneFlat->et_use;
|
||||
hy.hy_prefix = TRUE;
|
||||
|
|
|
|||
|
|
@ -1368,7 +1368,7 @@ ExtTechSimplePerimCap(argc, argv)
|
|||
|
||||
if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder)
|
||||
{
|
||||
TechError("Cannot parse area cap line without plane ordering!\n");
|
||||
TechError("Cannot parse perimeter cap line without plane ordering!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1376,9 +1376,14 @@ ExtTechSimplePerimCap(argc, argv)
|
|||
TTMaskSetMask(allExtractTypes, &types);
|
||||
plane1 = DBTechNoisyNamePlane(argv[2]);
|
||||
|
||||
TTMaskCom2(¬types, &types);
|
||||
/* As part of the "simple perimeter" simplifications, "nottypes" can
|
||||
* only be space. This prevents perimeter edges from being seen
|
||||
* between, e.g., poly and transistor gates, or metal and metal
|
||||
* resistors.
|
||||
*/
|
||||
TTMaskSetOnlyType(¬types, TT_SPACE);
|
||||
|
||||
TTMaskAndMask(&types, &DBPlaneTypes[plane1]);
|
||||
TTMaskAndMask(¬types, &DBPlaneTypes[plane1]);
|
||||
|
||||
capVal = aToCap(argv[argc - 1]);
|
||||
|
||||
|
|
@ -1632,7 +1637,7 @@ ExtTechSimpleOverlapCap(argv)
|
|||
|
||||
if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder)
|
||||
{
|
||||
TechError("Cannot parse area cap line without plane ordering!\n");
|
||||
TechError("Cannot parse overlap cap line without plane ordering!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1732,7 +1737,7 @@ ExtTechSimpleSideOverlapCap(argv)
|
|||
|
||||
if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder)
|
||||
{
|
||||
TechError("Cannot parse area cap line without plane ordering!\n");
|
||||
TechError("Cannot parse side overlap cap line without plane ordering!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1740,9 +1745,14 @@ ExtTechSimpleSideOverlapCap(argv)
|
|||
TTMaskSetMask(allExtractTypes, &types);
|
||||
plane1 = DBTechNoisyNamePlane(argv[2]);
|
||||
|
||||
TTMaskCom2(¬types, &types);
|
||||
/* As part of the "simple sideoverlap" simplifications, "nottypes"
|
||||
* can only be space. This prevents perimeter edges from being
|
||||
* seen between, e.g., poly and transistor gates, or metal and
|
||||
* metal resistors.
|
||||
*/
|
||||
TTMaskSetOnlyType(¬types, TT_SPACE);
|
||||
|
||||
TTMaskAndMask(&types, &DBPlaneTypes[plane1]);
|
||||
TTMaskAndMask(¬types, &DBPlaneTypes[plane1]);
|
||||
|
||||
DBTechNoisyNameMask(argv[3], &ov);
|
||||
TTMaskSetMask(allExtractTypes, &ov);
|
||||
|
|
@ -2747,24 +2757,34 @@ ExtTechLine(sectionName, argc, argv)
|
|||
DBTechNoisyNameMask(argv[4], &termtypes[0]); /* bottom */
|
||||
TTMaskSetMask(allExtractTypes, &termtypes[0]);
|
||||
termtypes[1] = DBZeroTypeBits;
|
||||
|
||||
if (argc > 5)
|
||||
gccap = aToCap(argv[argc - 1]); /* area cap */
|
||||
if ((argc > 6) && StrIsNumeric(argv[argc - 2]))
|
||||
{
|
||||
gscap = aToCap(argv[argc - 2]); /* perimeter cap */
|
||||
argc--;
|
||||
}
|
||||
nterm = 1;
|
||||
|
||||
if ((argc > 6) && strcmp(argv[5], "None"))
|
||||
/* If argv[argc - 1] is a numerical value, then it is
|
||||
* an area cap value and may be followed by another
|
||||
* numerical value, the perimeter cap.
|
||||
*/
|
||||
|
||||
if ((argc > 5) && StrIsNumeric(argv[argc - 1]))
|
||||
{
|
||||
DBTechNoisyNameMask(argv[5], &subsTypes); /* substrate */
|
||||
gccap = aToCap(argv[argc - 1]); /* area cap */
|
||||
argc--;
|
||||
|
||||
if ((argc > 5) && StrIsNumeric(argv[argc - 1]))
|
||||
{
|
||||
gscap = aToCap(argv[argc - 1]); /* perimeter cap */
|
||||
argc--;
|
||||
}
|
||||
}
|
||||
|
||||
if ((argc > 5) && strcmp(argv[5], "None"))
|
||||
{
|
||||
/* substrate */
|
||||
DBTechNoisyNameMask(argv[5], &subsTypes);
|
||||
TTMaskSetMask(allExtractTypes, &subsTypes);
|
||||
}
|
||||
else
|
||||
subsTypes = DBZeroTypeBits;
|
||||
if (argc > 7) subsName = argv[6];
|
||||
if (argc > 6) subsName = argv[6];
|
||||
break;
|
||||
|
||||
case DEV_SUBCKT:
|
||||
|
|
|
|||
|
|
@ -61,6 +61,11 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
* names that don't end in '!'.
|
||||
* If option is EXT_UNIQ_NOPORTS, then generate unique names as for
|
||||
* option 0 only if the label is not a port.
|
||||
* If option is EXT_UNIQ_TEMP, then generate unique names as for
|
||||
* EXT_UNIQ_ALL, but also set the LABEL_UNIQUE flag for the
|
||||
* label. This way, the unique label form can be used by the
|
||||
* extraction code but labels (and port indexes) can be reverted
|
||||
* afterward, and no permanent change is made to the circuit.
|
||||
*
|
||||
* Results:
|
||||
* Returns the number of warnings generated.
|
||||
|
|
@ -219,7 +224,7 @@ extMakeUnique(def, ll, lreg, lregList, labelHash, option)
|
|||
* changes a label to make it unique.
|
||||
*/
|
||||
text = ll->ll_label->lab_text;
|
||||
if (option == EXT_UNIQ_ALL)
|
||||
if (option == EXT_UNIQ_ALL || option == EXT_UNIQ_TEMP)
|
||||
goto makeUnique;
|
||||
else if ((option == EXT_UNIQ_NOPORTS || option == EXT_UNIQ_NOTOPPORTS)
|
||||
&& !(ll->ll_label->lab_flags & PORT_DIR_MASK))
|
||||
|
|
@ -320,8 +325,11 @@ makeUnique:
|
|||
lab = ll2->ll_label;
|
||||
saveLab = *lab;
|
||||
|
||||
/* Flag this label as having been modified */
|
||||
if (option == EXT_UNIQ_TEMP) flags |= LABEL_UNIQUE;
|
||||
|
||||
DBRemoveLabel(def, lab);
|
||||
(void) DBPutFontLabel(def, &saveLab.lab_rect,
|
||||
DBPutFontLabel(def, &saveLab.lab_rect,
|
||||
saveLab.lab_font, saveLab.lab_size, saveLab.lab_rotate,
|
||||
&saveLab.lab_offset, saveLab.lab_just, name2,
|
||||
saveLab.lab_type, flags, (unsigned int)portno);
|
||||
|
|
@ -334,3 +342,64 @@ makeUnique:
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* extRevertUniqueCell --
|
||||
*
|
||||
* For the cell 'def', look for labels marked with LABEL_UNIQUE and
|
||||
* remove the unique suffix. If the label is a port, then revert
|
||||
* the port index back to the original port number.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Changes the label records in the cell def.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
ExtRevertUniqueCell(CellDef *def)
|
||||
{
|
||||
Label *lab, *tlab;
|
||||
char *uptr;
|
||||
|
||||
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
||||
{
|
||||
if (lab->lab_flags & LABEL_UNIQUE)
|
||||
{
|
||||
/* There is no need to regenerate the label. We are
|
||||
* only reducing the string length, so just drop a null
|
||||
* at the last underscore and leave it at that.
|
||||
*/
|
||||
|
||||
lab->lab_flags &= ~LABEL_UNIQUE; /* Clear the flag */
|
||||
|
||||
/* Place a null at the last underscore */
|
||||
uptr = strrchr(lab->lab_text, '_');
|
||||
if (uptr != NULL) /* should always be true */
|
||||
*uptr = '\0';
|
||||
|
||||
/* If the label is a port, then find the first unmodified
|
||||
* version of the label and change the port back to its
|
||||
* port number
|
||||
*/
|
||||
if (lab->lab_flags & PORT_DIR_MASK)
|
||||
{
|
||||
for (tlab = def->cd_labels; tlab; tlab = tlab->lab_next)
|
||||
{
|
||||
if (tlab == lab) continue;
|
||||
else if (!strcmp(tlab->lab_text, lab->lab_text))
|
||||
{
|
||||
lab->lab_port = tlab->lab_port;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,12 +68,14 @@ extern const char * const extDevTable[];
|
|||
#define EXT_DOADJUST 0x001 /* Extract hierarchical adjustments */
|
||||
#define EXT_DOCAPACITANCE 0x002 /* Extract capacitance */
|
||||
#define EXT_DOCOUPLING 0x004 /* Extract coupling capacitance */
|
||||
#define EXT_DORESISTANCE 0x008 /* Extract resistance */
|
||||
#define EXT_DORESISTANCE 0x008 /* Extract lumped resistance */
|
||||
#define EXT_DOLENGTH 0x010 /* Extract pathlengths */
|
||||
#define EXT_DOFRINGEHALO 0x020 /* Distributed fringe capacitance */
|
||||
#define EXT_DOALL 0x03f /* ALL OF THE ABOVE */
|
||||
#define EXT_DOLABELCHECK 0x040 /* Check for connections by label */
|
||||
#define EXT_DOALIASES 0x080 /* Output all node aliases */
|
||||
#define EXT_DOUNIQUE 0x100 /* Force unique nodes during extraction */
|
||||
#define EXT_DOEXTRESIST 0x200 /* Do full R-C extraction */
|
||||
|
||||
extern int ExtOptions; /* Bitmask of above */
|
||||
extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */
|
||||
|
|
@ -83,6 +85,7 @@ extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */
|
|||
#define EXT_UNIQ_TAGGED 1
|
||||
#define EXT_UNIQ_NOPORTS 2
|
||||
#define EXT_UNIQ_NOTOPPORTS 3
|
||||
#define EXT_UNIQ_TEMP 4 /* Used only with "EXT_DOUNIQUE" */
|
||||
|
||||
extern bool ExtTechLine();
|
||||
extern void ExtTechInit();
|
||||
|
|
@ -110,6 +113,8 @@ extern void ExtDumpCaps();
|
|||
|
||||
extern int extEnumTilePerim(Tile *tpIn, TileType dinfo, const TileTypeBitMask *maskp, int pNum, int (*func)(), ClientData cdata);
|
||||
extern Plane *extPrepSubstrate();
|
||||
extern FILE *ExtFileOpen(CellDef *def, char *file, char *mode, char **prealfile);
|
||||
|
||||
|
||||
/* C99 compat */
|
||||
extern void ExtAll();
|
||||
|
|
|
|||
|
|
@ -209,6 +209,7 @@ typedef struct nreg
|
|||
* in X, then in Y.
|
||||
*/
|
||||
LabelList *nreg_labels; /* See LabRegion for description */
|
||||
ClientData nreg_subnet; /* Subnet record generated by extresist */
|
||||
CapValue nreg_cap; /* Capacitance to ground */
|
||||
ResValue nreg_resist; /* Resistance estimate */
|
||||
PerimArea nreg_pa[1]; /* Dummy; each node actually has
|
||||
|
|
@ -1126,6 +1127,7 @@ extern int extMakeUnique();
|
|||
extern void extEnumTerminal();
|
||||
extern void extEnumTerminal(Tile *tile, TileType dinfo,
|
||||
TileTypeBitMask *connect, void (*func)(), ClientData clientData);
|
||||
extern void ExtRevertUniqueCell(CellDef *def);
|
||||
|
||||
|
||||
/* ------------------ Connectivity table management ------------------- */
|
||||
|
|
|
|||
|
|
@ -694,15 +694,22 @@ w3dCutBox(w, cmd)
|
|||
{
|
||||
if (crec->clipped)
|
||||
{
|
||||
char *cllx, *clly, *curx, *cury;
|
||||
|
||||
cllx = DBWPrintValue(crec->cutbox.r_xbot, w, TRUE);
|
||||
clly = DBWPrintValue(crec->cutbox.r_ybot, w, TRUE);
|
||||
curx = DBWPrintValue(crec->cutbox.r_xtop, w, TRUE);
|
||||
cury = DBWPrintValue(crec->cutbox.r_ytop, w, TRUE);
|
||||
|
||||
Tcl_Obj *rlist = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, rlist,
|
||||
Tcl_NewIntObj((int)(crec->cutbox.r_xbot)));
|
||||
Tcl_NewStringObj(cllx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, rlist,
|
||||
Tcl_NewIntObj((int)(crec->cutbox.r_ybot)));
|
||||
Tcl_NewStringObj(clly, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, rlist,
|
||||
Tcl_NewIntObj((int)(crec->cutbox.r_xtop)));
|
||||
Tcl_NewStringObj(curx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, rlist,
|
||||
Tcl_NewIntObj((int)(crec->cutbox.r_ytop)));
|
||||
Tcl_NewStringObj(cury, -1));
|
||||
|
||||
Tcl_SetObjResult(magicinterp, rlist);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1359,15 +1359,21 @@ DefReadLocation(
|
|||
|
||||
if (use->cu_def->cd_flags & CDFIXEDBBOX)
|
||||
{
|
||||
char *propval;
|
||||
PropertyRecord *proprec;
|
||||
bool found;
|
||||
|
||||
propval = (char *)DBPropGet(use->cu_def, "FIXED_BBOX", &found);
|
||||
proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
|
||||
if (found)
|
||||
{
|
||||
if (sscanf(propval, "%d %d %d %d", &rect.r_xbot, &rect.r_ybot,
|
||||
&rect.r_xtop, &rect.r_ytop) == 4)
|
||||
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||
(proprec->prop_len == 4))
|
||||
{
|
||||
rect.r_xbot = proprec->prop_value.prop_integer[0];
|
||||
rect.r_ybot = proprec->prop_value.prop_integer[1];
|
||||
rect.r_xtop = proprec->prop_value.prop_integer[2];
|
||||
rect.r_ytop = proprec->prop_value.prop_integer[3];
|
||||
r = ▭
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2453,7 +2459,7 @@ DefRead(
|
|||
FILE *f;
|
||||
char *filename;
|
||||
const char *token;
|
||||
char *bboxstr;
|
||||
PropertyRecord *proprec;
|
||||
int keyword, dscale, total;
|
||||
float oscale;
|
||||
Rect *dierect;
|
||||
|
|
@ -2605,14 +2611,17 @@ DefRead(
|
|||
break;
|
||||
case DEF_DIEAREA:
|
||||
dierect = LefReadRect(f, 0, oscale);
|
||||
bboxstr = mallocMagic(40);
|
||||
sprintf(bboxstr, "%d %d %d %d",
|
||||
dierect->r_xbot,
|
||||
dierect->r_ybot,
|
||||
dierect->r_xtop,
|
||||
dierect->r_ytop);
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
2 * sizeof(int));
|
||||
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||
proprec->prop_len = 4;
|
||||
proprec->prop_value.prop_integer[0] = dierect->r_xbot;
|
||||
proprec->prop_value.prop_integer[1] = dierect->r_ybot;
|
||||
proprec->prop_value.prop_integer[2] = dierect->r_xtop;
|
||||
proprec->prop_value.prop_integer[3] = dierect->r_ytop;
|
||||
if (rootDef == NULL) rootDef = DefNewCell(inName);
|
||||
DBPropPut(rootDef, "FIXED_BBOX", bboxstr);
|
||||
DBPropPut(rootDef, "FIXED_BBOX", proprec);
|
||||
|
||||
LefEndStatement(f);
|
||||
break;
|
||||
case DEF_PROPERTYDEFINITIONS:
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ defWriteHeader(
|
|||
float oscale,
|
||||
int units) /* Units for UNITS; could be derived from oscale */
|
||||
{
|
||||
char *propvalue;
|
||||
PropertyRecord *proprec;
|
||||
bool propfound;
|
||||
|
||||
TxPrintf("Diagnostic: Write DEF header for cell %s\n", def->cd_name);
|
||||
|
|
@ -141,15 +141,20 @@ defWriteHeader(
|
|||
/* For DIEAREA, use the FIXED_BBOX property if present. Otherwise, */
|
||||
/* use the extents of geometry (CellDef bounding box) */
|
||||
|
||||
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
|
||||
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
Rect bbox;
|
||||
|
||||
/* Die area, taken from the declared FIXED_BBOX. */
|
||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
||||
&bbox.r_xtop, &bbox.r_ytop) == 4)
|
||||
{
|
||||
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||
(proprec->prop_len == 4))
|
||||
{
|
||||
bbox.r_xbot = proprec->prop_value.prop_integer[0];
|
||||
bbox.r_ybot = proprec->prop_value.prop_integer[1];
|
||||
bbox.r_xtop = proprec->prop_value.prop_integer[2];
|
||||
bbox.r_ytop = proprec->prop_value.prop_integer[3];
|
||||
|
||||
fprintf(f, " DIEAREA ( %.10g %.10g ) ( %.10g %.10g ) ;\n",
|
||||
(float)bbox.r_xbot * oscale,
|
||||
(float)bbox.r_ybot * oscale,
|
||||
|
|
@ -2786,15 +2791,21 @@ arrayDefFunc(
|
|||
|
||||
if (use->cu_def->cd_flags & CDFIXEDBBOX)
|
||||
{
|
||||
char *propval;
|
||||
PropertyRecord *proprec;
|
||||
bool found;
|
||||
|
||||
propval = (char *)DBPropGet(use->cu_def, "FIXED_BBOX", &found);
|
||||
proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
|
||||
if (found)
|
||||
{
|
||||
if (sscanf(propval, "%d %d %d %d", &rect.r_xbot, &rect.r_ybot,
|
||||
&rect.r_xtop, &rect.r_ytop) == 4)
|
||||
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||
(proprec->prop_len == 4))
|
||||
{
|
||||
rect.r_xbot = proprec->prop_value.prop_integer[0];
|
||||
rect.r_ybot = proprec->prop_value.prop_integer[1];
|
||||
rect.r_xtop = proprec->prop_value.prop_integer[2];
|
||||
rect.r_ytop = proprec->prop_value.prop_integer[3];
|
||||
r = ▭
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2844,15 +2855,20 @@ defComponentFunc(
|
|||
xoff = yoff = 0;
|
||||
if (cellUse->cu_def->cd_flags & CDFIXEDBBOX)
|
||||
{
|
||||
char *propval;
|
||||
PropertyRecord *proprec;
|
||||
bool found;
|
||||
|
||||
propval = (char *)DBPropGet(cellUse->cu_def, "FIXED_BBOX", &found);
|
||||
proprec = DBPropGet(cellUse->cu_def, "FIXED_BBOX", &found);
|
||||
if (found)
|
||||
{
|
||||
if (sscanf(propval, "%d %d %d %d", &rect.r_xbot, &rect.r_ybot,
|
||||
&rect.r_xtop, &rect.r_ytop) == 4)
|
||||
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||
(proprec->prop_len == 4))
|
||||
{
|
||||
rect.r_xbot = proprec->prop_value.prop_integer[0];
|
||||
rect.r_ybot = proprec->prop_value.prop_integer[1];
|
||||
rect.r_xtop = proprec->prop_value.prop_integer[2];
|
||||
rect.r_ytop = proprec->prop_value.prop_integer[3];
|
||||
|
||||
r = ▭
|
||||
GeoTransRect(&cellUse->cu_transform, &rect, &bbrect);
|
||||
GeoTransRect(&cellUse->cu_transform, &cellUse->cu_def->cd_bbox, &defrect);
|
||||
|
|
|
|||
101
lef/lefRead.c
101
lef/lefRead.c
|
|
@ -2150,6 +2150,7 @@ LefReadMacro(
|
|||
int keyword, pinNum, propsize, result;
|
||||
float x, y;
|
||||
bool has_size, is_imported = FALSE, propfound;
|
||||
PropertyRecord *proprec;
|
||||
Rect lefBBox;
|
||||
Point gdsOffset; /* Difference between GDS and LEF coordinates */
|
||||
|
||||
|
|
@ -2250,7 +2251,12 @@ LefReadMacro(
|
|||
sprintf(tsave + strlen(tsave), " %s", token);
|
||||
token = LefNextToken(f, TRUE);
|
||||
}
|
||||
DBPropPut(lefMacro, "LEFclass", StrDup((char **)NULL, tsave + 1));
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
strlen(tsave + 1) - 7);
|
||||
proprec->prop_type = PROPERTY_TYPE_STRING;
|
||||
proprec->prop_len = strlen(tsave + 1);
|
||||
strcpy(proprec->prop_value.prop_string, tsave + 1);
|
||||
DBPropPut(lefMacro, "LEFclass", proprec);
|
||||
break;
|
||||
case LEF_SIZE:
|
||||
token = LefNextToken(f, TRUE);
|
||||
|
|
@ -2294,7 +2300,12 @@ origin_error:
|
|||
sprintf(tsave + strlen(tsave), " %s", token);
|
||||
token = LefNextToken(f, TRUE);
|
||||
}
|
||||
DBPropPut(lefMacro, "LEFsymmetry", StrDup((char **)NULL, tsave + 1));
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
strlen(tsave + 1) - 7);
|
||||
proprec->prop_type = PROPERTY_TYPE_STRING;
|
||||
proprec->prop_len = strlen(tsave + 1);
|
||||
strcpy(proprec->prop_value.prop_string, tsave + 1);
|
||||
DBPropPut(lefMacro, "LEFsymmetry", proprec);
|
||||
break;
|
||||
case LEF_SOURCE:
|
||||
token = LefNextToken(f, TRUE);
|
||||
|
|
@ -2305,12 +2316,19 @@ origin_error:
|
|||
case LEF_SITE:
|
||||
token = LefNextToken(f, TRUE);
|
||||
if (*token != '\n')
|
||||
DBPropPut(lefMacro, "LEFsite", StrDup((char **)NULL, token));
|
||||
{
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
strlen(token) - 7);
|
||||
proprec->prop_type = PROPERTY_TYPE_STRING;
|
||||
proprec->prop_len = strlen(token);
|
||||
strcpy(proprec->prop_value.prop_string, token);
|
||||
DBPropPut(lefMacro, "LEFsite", proprec);
|
||||
}
|
||||
LefEndStatement(f);
|
||||
break;
|
||||
case LEF_PROPERTY:
|
||||
/* Append property key:value pairs to the cell property LEFproperties */
|
||||
propval = (char *)DBPropGet(lefMacro, "LEFproperties", &propfound);
|
||||
propval = DBPropGetString(lefMacro, "LEFproperties", &propfound);
|
||||
if (propfound)
|
||||
propsize = strlen(propval);
|
||||
else
|
||||
|
|
@ -2322,14 +2340,19 @@ origin_error:
|
|||
char *propext;
|
||||
sprintf(tsave, "%.127s", token);
|
||||
token = LefNextToken(f, TRUE);
|
||||
propext = (char *)mallocMagic(propsize + strlen(tsave) +
|
||||
strlen(token) + 4);
|
||||
if (propsize > 0)
|
||||
sprintf(propext, "%s %s %s", propval, tsave, token);
|
||||
else
|
||||
sprintf(propext, "%s %s", tsave, token);
|
||||
|
||||
DBPropPut(lefMacro, "LEFproperties", StrDup((char **)NULL, propext));
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
propsize + strlen(tsave) + strlen(token) - 3);
|
||||
proprec->prop_type = PROPERTY_TYPE_STRING;
|
||||
proprec->prop_len = propsize + strlen(tsave) + strlen(token) + 4;
|
||||
|
||||
if (propsize > 0)
|
||||
sprintf(proprec->prop_value.prop_string, "%s %s %s",
|
||||
propval, tsave, token);
|
||||
else
|
||||
sprintf(proprec->prop_value.prop_string, "%s %s", tsave, token);
|
||||
|
||||
DBPropPut(lefMacro, "LEFproperties", proprec);
|
||||
}
|
||||
LefEndStatement(f);
|
||||
break;
|
||||
|
|
@ -2405,11 +2428,16 @@ foreign_error:
|
|||
if (has_size)
|
||||
{
|
||||
lefMacro->cd_flags |= CDFIXEDBBOX;
|
||||
propval = (char *)mallocMagic(40);
|
||||
sprintf(propval, "%d %d %d %d",
|
||||
lefBBox.r_xbot, lefBBox.r_ybot,
|
||||
lefBBox.r_xtop, lefBBox.r_ytop);
|
||||
DBPropPut(lefMacro, "FIXED_BBOX", propval);
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
(2 * sizeof(int)));
|
||||
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||
proprec->prop_len = 4;
|
||||
proprec->prop_value.prop_integer[0] = lefBBox.r_xbot;
|
||||
proprec->prop_value.prop_integer[1] = lefBBox.r_ybot;
|
||||
proprec->prop_value.prop_integer[2] = lefBBox.r_xtop;
|
||||
proprec->prop_value.prop_integer[3] = lefBBox.r_ytop;
|
||||
|
||||
DBPropPut(lefMacro, "FIXED_BBOX", proprec);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -2419,11 +2447,16 @@ foreign_error:
|
|||
if (has_size)
|
||||
{
|
||||
lefMacro->cd_flags |= CDFIXEDBBOX;
|
||||
propval = (char *)mallocMagic(40);
|
||||
sprintf(propval, "%d %d %d %d",
|
||||
lefBBox.r_xbot, lefBBox.r_ybot,
|
||||
lefBBox.r_xtop, lefBBox.r_ytop);
|
||||
DBPropPut(lefMacro, "FIXED_BBOX", propval);
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
(2 * sizeof(int)));
|
||||
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||
proprec->prop_len = 4;
|
||||
proprec->prop_value.prop_integer[0] = lefBBox.r_xbot;
|
||||
proprec->prop_value.prop_integer[1] = lefBBox.r_ybot;
|
||||
proprec->prop_value.prop_integer[2] = lefBBox.r_xtop;
|
||||
proprec->prop_value.prop_integer[3] = lefBBox.r_ytop;
|
||||
|
||||
DBPropPut(lefMacro, "FIXED_BBOX", proprec);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2432,13 +2465,17 @@ foreign_error:
|
|||
|
||||
/* Set the placement bounding box property to the current bounding box */
|
||||
lefMacro->cd_flags |= CDFIXEDBBOX;
|
||||
propval = (char *)mallocMagic(40);
|
||||
sprintf(propval, "%d %d %d %d",
|
||||
lefMacro->cd_bbox.r_xbot,
|
||||
lefMacro->cd_bbox.r_ybot,
|
||||
lefMacro->cd_bbox.r_xtop,
|
||||
lefMacro->cd_bbox.r_ytop);
|
||||
DBPropPut(lefMacro, "FIXED_BBOX", propval);
|
||||
lefMacro->cd_flags |= CDFIXEDBBOX;
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
(2 * sizeof(int)));
|
||||
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||
proprec->prop_len = 4;
|
||||
proprec->prop_value.prop_integer[0] = lefMacro->cd_bbox.r_xbot;
|
||||
proprec->prop_value.prop_integer[1] = lefMacro->cd_bbox.r_ybot;
|
||||
proprec->prop_value.prop_integer[2] = lefMacro->cd_bbox.r_xtop;
|
||||
proprec->prop_value.prop_integer[3] = lefMacro->cd_bbox.r_ytop;
|
||||
|
||||
DBPropPut(lefMacro, "FIXED_BBOX", proprec);
|
||||
DRCCheckThis(lefMacro, TT_CHECKPAINT, &lefMacro->cd_bbox);
|
||||
}
|
||||
}
|
||||
|
|
@ -2453,7 +2490,13 @@ foreign_error:
|
|||
/* i.e., setting it to "FALSE" would be ineffective. */
|
||||
|
||||
if (!is_imported)
|
||||
DBPropPut(lefMacro, "LEFview", StrDup((char **)NULL, "TRUE"));
|
||||
{
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||
proprec->prop_type = PROPERTY_TYPE_STRING;
|
||||
proprec->prop_len = 4;
|
||||
strcpy(proprec->prop_value.prop_string, "TRUE");
|
||||
DBPropPut(lefMacro, "LEFview", proprec);
|
||||
}
|
||||
|
||||
DBWAreaChanged(lefMacro, &lefMacro->cd_bbox, DBW_ALLWINDOWS,
|
||||
&DBAllButSpaceBits);
|
||||
|
|
|
|||
|
|
@ -328,14 +328,14 @@ lefWriteHeader(
|
|||
{
|
||||
fprintf(f, "SITE %s\n", siteDef->cd_name);
|
||||
|
||||
propvalue = (char *)DBPropGet(siteDef, "LEFsymmetry", &propfound);
|
||||
propvalue = DBPropGetString(siteDef, "LEFsymmetry", &propfound);
|
||||
if (propfound)
|
||||
fprintf(f, IN0 "SYMMETRY %s ;\n", propvalue);
|
||||
else
|
||||
/* Usually core cells have symmetry Y only. */
|
||||
fprintf(f, IN0 "SYMMETRY Y ;\n");
|
||||
|
||||
propvalue = (char *)DBPropGet(siteDef, "LEFclass", &propfound);
|
||||
propvalue = DBPropGetString(siteDef, "LEFclass", &propfound);
|
||||
if (propfound)
|
||||
fprintf(f, IN0 "CLASS %s ;\n", propvalue);
|
||||
else
|
||||
|
|
@ -345,10 +345,20 @@ lefWriteHeader(
|
|||
boundary = siteDef->cd_bbox;
|
||||
if (siteDef->cd_flags & CDFIXEDBBOX)
|
||||
{
|
||||
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
|
||||
PropertyRecord *proprec;
|
||||
|
||||
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
|
||||
if (propfound)
|
||||
sscanf(propvalue, "%d %d %d %d", &boundary.r_xbot,
|
||||
&boundary.r_ybot, &boundary.r_xtop, &boundary.r_ytop);
|
||||
{
|
||||
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||
(proprec->prop_len == 4))
|
||||
{
|
||||
boundary.r_xbot = proprec->prop_value.prop_integer[0];
|
||||
boundary.r_ybot = proprec->prop_value.prop_integer[1];
|
||||
boundary.r_xtop = proprec->prop_value.prop_integer[2];
|
||||
boundary.r_ytop = proprec->prop_value.prop_integer[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scale = CIFGetOutputScale(1000); /* conversion to microns */
|
||||
|
|
@ -1288,7 +1298,7 @@ lefWriteMacro(
|
|||
/* default values are optional, so in this case we will leave those */
|
||||
/* entries blank. */
|
||||
|
||||
propvalue = (char *)DBPropGet(def, "LEFclass", &propfound);
|
||||
propvalue = DBPropGetString(def, "LEFclass", &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
fprintf(f, IN0 "CLASS %s ;\n", propvalue);
|
||||
|
|
@ -1324,13 +1334,21 @@ lefWriteMacro(
|
|||
|
||||
if (def->cd_flags & CDFIXEDBBOX)
|
||||
{
|
||||
char *propvalue;
|
||||
PropertyRecord *proprec;
|
||||
bool found;
|
||||
|
||||
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &found);
|
||||
proprec = DBPropGet(def, "FIXED_BBOX", &found);
|
||||
if (found)
|
||||
sscanf(propvalue, "%d %d %d %d", &boundary.r_xbot,
|
||||
&boundary.r_ybot, &boundary.r_xtop, &boundary.r_ytop);
|
||||
{
|
||||
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||
(proprec->prop_len == 4))
|
||||
{
|
||||
boundary.r_xbot = proprec->prop_value.prop_integer[0];
|
||||
boundary.r_ybot = proprec->prop_value.prop_integer[1];
|
||||
boundary.r_xtop = proprec->prop_value.prop_integer[2];
|
||||
boundary.r_ytop = proprec->prop_value.prop_integer[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if (boundry less setback) is degenerate. If so, then */
|
||||
|
|
@ -1358,11 +1376,11 @@ lefWriteMacro(
|
|||
lc.origin.p_x = 0;
|
||||
lc.origin.p_y = 0;
|
||||
|
||||
propvalue = (char *)DBPropGet(def, "LEFsymmetry", &propfound);
|
||||
propvalue = DBPropGetString(def, "LEFsymmetry", &propfound);
|
||||
if (propfound)
|
||||
fprintf(f, IN0 "SYMMETRY %s ;\n", propvalue);
|
||||
|
||||
propvalue = (char *)DBPropGet(def, "LEFsite", &propfound);
|
||||
propvalue = DBPropGetString(def, "LEFsite", &propfound);
|
||||
if (propfound)
|
||||
fprintf(f, IN0 "SITE %s ;\n", propvalue);
|
||||
|
||||
|
|
@ -1821,20 +1839,24 @@ lefWriteMacro(
|
|||
Rect layerBound, manualBound;
|
||||
labelLinkedList *thislll;
|
||||
bool propfound;
|
||||
char *propvalue;
|
||||
PropertyRecord *proprec;
|
||||
|
||||
/* If there is a property OBS_BBOX, then use the value of the */
|
||||
/* defined box to set the minimum hidden area. This will still */
|
||||
/* get clipped to the setback. */
|
||||
|
||||
propvalue = (char *)DBPropGet(def, "OBS_BBOX", &propfound);
|
||||
proprec = DBPropGet(def, "OBS_BBOX", &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
if (sscanf(propvalue, "%d %d %d %d",
|
||||
&(manualBound.r_xbot),
|
||||
&(manualBound.r_ybot),
|
||||
&(manualBound.r_xtop),
|
||||
&(manualBound.r_ytop)) != 4)
|
||||
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||
(proprec->prop_len == 4))
|
||||
{
|
||||
manualBound.r_xbot = proprec->prop_value.prop_integer[0];
|
||||
manualBound.r_ybot = proprec->prop_value.prop_integer[1];
|
||||
manualBound.r_xtop = proprec->prop_value.prop_integer[2];
|
||||
manualBound.r_ytop = proprec->prop_value.prop_integer[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
TxError("Improper values for obstruction bounding box "
|
||||
"OBS_BBOX property");
|
||||
|
|
@ -2016,7 +2038,7 @@ lefWriteMacro(
|
|||
|
||||
/* If there are any properties saved in LEFproperties, write them out */
|
||||
|
||||
propvalue = (char *)DBPropGet(def, "LEFproperties", &propfound);
|
||||
propvalue = DBPropGetString(def, "LEFproperties", &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
char *delim;
|
||||
|
|
@ -2094,7 +2116,7 @@ lefGetSites(
|
|||
bool propfound;
|
||||
char *propvalue;
|
||||
|
||||
propvalue = (char *)DBPropGet(def, "LEFsite", &propfound);
|
||||
propvalue = DBPropGetString(def, "LEFsite", &propfound);
|
||||
if (propfound)
|
||||
he = HashFind(lefSiteTbl, propvalue); /* FIXME return value not used from call to function with no side-effects (reevaluate this entire func purpose?) */
|
||||
|
||||
|
|
@ -2124,7 +2146,7 @@ lefGetProperties(
|
|||
bool propfound;
|
||||
char *propvalue;
|
||||
|
||||
propvalue = (char *)DBPropGet(def, "LEFproperties", &propfound);
|
||||
propvalue = DBPropGetString(def, "LEFproperties", &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
char *key;
|
||||
|
|
|
|||
|
|
@ -120,61 +120,61 @@ macro Control_XK_space "tool wiring"
|
|||
# Arrow keys (X11 versions only)
|
||||
macro XK_Left "scroll l .1 w"
|
||||
macro Shift_XK_Left "scroll l 1 w"
|
||||
macro Control_XK_Left "box grow w 1"
|
||||
macro Control_Shift_XK_Left "box shrink e 1"
|
||||
macro Control_XK_Left "box grow w 1i"
|
||||
macro Control_Shift_XK_Left "box shrink e 1i"
|
||||
macro XK_Right "scroll r .1 w"
|
||||
macro Shift_XK_Right "scroll r 1 w"
|
||||
macro Control_XK_Right "box grow e 1"
|
||||
macro Control_Shift_XK_Right "box shrink w 1"
|
||||
macro Control_XK_Right "box grow e 1i"
|
||||
macro Control_Shift_XK_Right "box shrink w 1i"
|
||||
macro XK_Up "scroll u .1 w"
|
||||
macro Shift_XK_Up "scroll u 1 w"
|
||||
macro Control_XK_Up "box grow n 1"
|
||||
macro Control_Shift_XK_Up "box shrink s 1"
|
||||
macro Control_XK_Up "box grow n 1i"
|
||||
macro Control_Shift_XK_Up "box shrink s 1i"
|
||||
macro XK_Down "scroll d .1 w"
|
||||
macro Shift_XK_Down "scroll d 1 w"
|
||||
macro Control_XK_Down "box grow s 1"
|
||||
macro Control_Shift_XK_Down "box shrink n 1"
|
||||
macro Control_XK_Down "box grow s 1i"
|
||||
macro Control_Shift_XK_Down "box shrink n 1i"
|
||||
# Keypad keys (X11 versions only)
|
||||
# Functions duplicated for use both with Num_Lock ON and OFF
|
||||
macro XK_KP_Delete "box size 0 0"
|
||||
macro XK_KP_Insert "box size 4 4"
|
||||
macro XK_KP_0 "box size 7 2"
|
||||
macro Shift_XK_KP_0 "box size 7 2"
|
||||
macro XK_0 "box size 7 2"
|
||||
macro Control_XK_KP_0 "box size 2 7"
|
||||
macro Control_XK_KP_Insert "box size 2 7"
|
||||
macro XK_KP_End "move sw 1"
|
||||
macro XK_KP_Down "move d 1"
|
||||
macro XK_KP_2 "stretch d 1"
|
||||
macro XK_KP_Insert "box size 4l 4l"
|
||||
macro XK_KP_0 "box size 7l 2l"
|
||||
macro Shift_XK_KP_0 "box size 7l 2l"
|
||||
macro XK_0 "box size 7l 2l"
|
||||
macro Control_XK_KP_0 "box size 2l 7l"
|
||||
macro Control_XK_KP_Insert "box size 2l 7l"
|
||||
macro XK_KP_End "move sw 1i"
|
||||
macro XK_KP_Down "move d 1i"
|
||||
macro XK_KP_2 "stretch d 1i"
|
||||
macro Shift_XK_KP_2 "stretch d 1"
|
||||
macro Shift_XK_KP_Down "stretch d 1"
|
||||
macro Shift_XK_KP_Down "move d 1"
|
||||
macro Control_XK_KP_Down "stretch d 1i"
|
||||
macro XK_2 "stretch d 1"
|
||||
macro XK_KP_Next "move se 1"
|
||||
macro XK_KP_Left "move l 1"
|
||||
macro XK_KP_4 "stretch l 1"
|
||||
macro XK_2 "stretch d 1i"
|
||||
macro XK_KP_Next "move se 1i"
|
||||
macro XK_KP_Left "move l 1i"
|
||||
macro XK_KP_4 "stretch l 1i"
|
||||
macro Shift_XK_KP_4 "stretch l 1"
|
||||
macro Shift_XK_KP_Left "stretch l 1"
|
||||
macro Shift_XK_KP_Left "move l 1"
|
||||
macro Control_XK_KP_Left "stretch l 1i"
|
||||
macro XK_4 "stretch l 1"
|
||||
macro XK_4 "stretch l 1i"
|
||||
macro XK_KP_Begin "findbox zoom"
|
||||
macro XK_KP_5 "findbox"
|
||||
macro Shift_XK_KP_5 "findbox"
|
||||
macro XK_5 "findbox"
|
||||
macro XK_KP_Right "move r 1"
|
||||
macro XK_KP_6 "stretch r 1"
|
||||
macro XK_KP_Right "move r 1i"
|
||||
macro XK_KP_6 "stretch r 1i"
|
||||
macro Shift_XK_KP_6 "stretch r 1"
|
||||
macro Shift_XK_KP_Right "stretch r 1"
|
||||
macro Shift_XK_KP_Right "move r 1"
|
||||
macro Control_XK_KP_Right "stretch r 1i"
|
||||
macro XK_6 "stretch r 1"
|
||||
macro XK_KP_Home "move nw 1"
|
||||
macro XK_KP_Up "move u 1"
|
||||
macro XK_KP_8 "stretch u 1"
|
||||
macro XK_6 "stretch r 1i"
|
||||
macro XK_KP_Home "move nw 1i"
|
||||
macro XK_KP_Up "move u 1i"
|
||||
macro XK_KP_8 "stretch u 1i"
|
||||
macro Shift_XK_KP_8 "stretch u 1"
|
||||
macro Shift_XK_KP_Up "stretch u 1"
|
||||
macro Shift_XK_KP_Up "move u 1"
|
||||
macro Control_XK_KP_Up "stretch u 1i"
|
||||
macro XK_8 "stretch u 1"
|
||||
macro XK_KP_Prior "move ne 1"
|
||||
macro XK_8 "stretch u 1i"
|
||||
macro XK_KP_Prior "move ne 1i"
|
||||
# Scroll wheel bindings
|
||||
macro XK_Pointer_Button4 "scroll u .05 w"
|
||||
macro XK_Pointer_Button5 "scroll d .05 w"
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ MAGIC_8.0 {
|
|||
DBPlaneTypes;
|
||||
DBPrintUseId;
|
||||
DBPropGet;
|
||||
DBPropGetString;
|
||||
DBPropGetDouble;
|
||||
DBPutLabel;
|
||||
DBReComputeBbox;
|
||||
DBSeeTypesAll;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
MODULE = resis
|
||||
MAGICDIR = ..
|
||||
SRCS = ResMain.c ResJunct.c ResMakeRes.c ResSimple.c ResPrint.c \
|
||||
ResReadSim.c ResRex.c ResBasic.c ResMerge.c ResChecks.c \
|
||||
ResReadExt.c ResRex.c ResBasic.c ResMerge.c ResChecks.c \
|
||||
ResFract.c ResUtils.c ResDebug.c
|
||||
|
||||
include ${MAGICDIR}/defs.mak
|
||||
|
|
|
|||
|
|
@ -46,22 +46,22 @@ resNodeIsPort(node, x, y, tile)
|
|||
Rect *rect;
|
||||
Point p;
|
||||
resPort *pl, *lp;
|
||||
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
|
||||
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||
|
||||
p.p_x = x;
|
||||
p.p_y = y;
|
||||
|
||||
for (pl = junk->portList; pl; pl = pl->rp_nextPort)
|
||||
for (pl = info->portList; pl; pl = pl->rp_nextPort)
|
||||
{
|
||||
rect = &(pl->rp_bbox);
|
||||
if (GEO_ENCLOSE(&p, rect))
|
||||
{
|
||||
node->rn_name = pl->rp_nodename;
|
||||
if (junk->portList == pl)
|
||||
junk->portList = pl->rp_nextPort;
|
||||
if (info->portList == pl)
|
||||
info->portList = pl->rp_nextPort;
|
||||
else
|
||||
{
|
||||
for (lp = junk->portList; lp && (lp->rp_nextPort != pl);
|
||||
for (lp = info->portList; lp && (lp->rp_nextPort != pl);
|
||||
lp = lp->rp_nextPort);
|
||||
lp->rp_nextPort = pl->rp_nextPort;
|
||||
}
|
||||
|
|
@ -77,7 +77,8 @@ resNodeIsPort(node, x, y, tile)
|
|||
* resAllPortNodes --
|
||||
*
|
||||
* Generate new nodes and breakpoints for every unused port declared
|
||||
* on a tile.
|
||||
* on a tile. However, if "startpoint" is inside the port position,
|
||||
* then it has already been processed, so ignore it.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -90,15 +91,15 @@ resAllPortNodes(tile, list)
|
|||
int x, y;
|
||||
resNode *resptr;
|
||||
resPort *pl;
|
||||
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
|
||||
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||
|
||||
free_magic1_t mm1 = freeMagic1_init();
|
||||
for (pl = junk->portList; pl; pl = pl->rp_nextPort)
|
||||
for (pl = info->portList; pl; pl = pl->rp_nextPort)
|
||||
{
|
||||
x = pl->rp_loc.p_x;
|
||||
y = pl->rp_loc.p_y;
|
||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
||||
InitializeNode(resptr, x, y, RES_NODE_ORIGIN);
|
||||
InitializeResNode(resptr, x, y, RES_NODE_ORIGIN);
|
||||
resptr->rn_status = TRUE;
|
||||
resptr->rn_noderes = 0;
|
||||
resptr->rn_name = pl->rp_nodename;
|
||||
|
|
@ -225,7 +226,7 @@ ResEachTile(tile, startpoint)
|
|||
int xj, yj, i;
|
||||
bool merged;
|
||||
tElement *tcell;
|
||||
tileJunk *tstructs= (tileJunk *)TiGetClientPTR(tile);
|
||||
resInfo *tstructs= (resInfo *)TiGetClientPTR(tile);
|
||||
ExtDevice *devptr;
|
||||
int sides;
|
||||
|
||||
|
|
@ -262,7 +263,7 @@ ResEachTile(tile, startpoint)
|
|||
int x = startpoint->p_x;
|
||||
int y = startpoint->p_y;
|
||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
||||
InitializeNode(resptr, x, y, RES_NODE_ORIGIN);
|
||||
InitializeResNode(resptr, x, y, RES_NODE_ORIGIN);
|
||||
resptr->rn_status = TRUE;
|
||||
resptr->rn_noderes = 0;
|
||||
ResAddToQueue(resptr, &ResNodeQueue);
|
||||
|
|
@ -278,7 +279,7 @@ ResEachTile(tile, startpoint)
|
|||
* for single tile device, but not as good for multiple ones.
|
||||
*/
|
||||
|
||||
if (tstructs->tj_status & RES_TILE_DEV)
|
||||
if (tstructs->ri_status & RES_TILE_DEV)
|
||||
{
|
||||
if (tstructs->deviceList->rd_fet_gate == NULL)
|
||||
{
|
||||
|
|
@ -291,7 +292,7 @@ ResEachTile(tile, startpoint)
|
|||
tcell->te_thist = tstructs->deviceList;
|
||||
tcell->te_nextt = NULL;
|
||||
|
||||
InitializeNode(resptr, x, y, RES_NODE_JUNCTION);
|
||||
InitializeResNode(resptr, x, y, RES_NODE_JUNCTION);
|
||||
resptr->rn_te = tcell;
|
||||
ResAddToQueue(resptr, &ResNodeQueue);
|
||||
resNodeIsPort(resptr, x, y, tile);
|
||||
|
|
@ -516,7 +517,7 @@ ResEachTile(tile, startpoint)
|
|||
}
|
||||
}
|
||||
|
||||
tstructs->tj_status |= RES_TILE_DONE;
|
||||
tstructs->ri_status |= RES_TILE_DONE;
|
||||
|
||||
resAllPortNodes(tile, &ResNodeQueue);
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ ResSanityChecks(nodename, resistorList, nodeList, devlist)
|
|||
for (node = nodeList; node != NULL; node=node->rn_more)
|
||||
{
|
||||
node->rn_status &= ~RES_REACHED_NODE;
|
||||
if (node->rn_why == RES_NODE_ORIGIN)
|
||||
if (node->rn_why & RES_NODE_ORIGIN)
|
||||
STACKPUSH((ClientData) node, resSanityStack);
|
||||
}
|
||||
for (resistor = resistorList; resistor != NULL; resistor = resistor->rr_nextResistor)
|
||||
|
|
@ -112,7 +112,6 @@ ResSanityChecks(nodename, resistorList, nodeList, devlist)
|
|||
{
|
||||
int i;
|
||||
|
||||
if (dev->rd_status & RES_DEV_PLUG) continue;
|
||||
reached = FALSE;
|
||||
for (i = 0; i != dev->rd_nterms; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -120,7 +120,6 @@ ResPrintDeviceList(fp, list)
|
|||
int i;
|
||||
for (; list != NULL; list = list->rd_nextDev)
|
||||
{
|
||||
if (list->rd_status & RES_DEV_PLUG) continue;
|
||||
if (fp == stdout)
|
||||
TxPrintf("t w %d l %d ", list->rd_width, list->rd_length);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
|||
resDevice *resDev;
|
||||
tElement *tcell;
|
||||
int newnode;
|
||||
tileJunk *j;
|
||||
resInfo *ri;
|
||||
|
||||
newnode = FALSE;
|
||||
|
||||
|
|
@ -62,9 +62,9 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
|||
*/
|
||||
if (TiGetClient(tp) == CLIENTDEFAULT) return;
|
||||
|
||||
j = (tileJunk *) TiGetClientPTR(tp);
|
||||
resDev = j->deviceList;
|
||||
if ((j->sourceEdge & direction) != 0)
|
||||
ri = (resInfo *) TiGetClientPTR(tp);
|
||||
resDev = ri->deviceList;
|
||||
if ((ri->sourceEdge & direction) != 0)
|
||||
{
|
||||
if (resDev->rd_fet_source == (resNode *) NULL)
|
||||
{
|
||||
|
|
@ -94,8 +94,8 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
|||
{
|
||||
tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
|
||||
tcell->te_nextt = NULL;
|
||||
tcell->te_thist = j->deviceList;
|
||||
InitializeNode(resptr, xj, yj, RES_NODE_DEVICE);
|
||||
tcell->te_thist = ri->deviceList;
|
||||
InitializeResNode(resptr, xj, yj, RES_NODE_DEVICE);
|
||||
resptr->rn_te = tcell;
|
||||
ResAddToQueue(resptr, PendingList);
|
||||
}
|
||||
|
|
@ -125,11 +125,11 @@ ResNewSubDevice(tile, tp, xj, yj, direction, PendingList)
|
|||
resDevice *resDev;
|
||||
tElement *tcell;
|
||||
int newnode;
|
||||
tileJunk *j;
|
||||
resInfo *ri;
|
||||
|
||||
newnode = FALSE;
|
||||
j = (tileJunk *) TiGetClientPTR(tp);
|
||||
resDev = j->deviceList;
|
||||
ri = (resInfo *) TiGetClientPTR(tp);
|
||||
resDev = ri->deviceList;
|
||||
|
||||
/* Arrived at a device that has a terminal connected to substrate */
|
||||
/* that is not a FET bulk terminal (e.g., varactor, diode). */
|
||||
|
|
@ -150,8 +150,8 @@ ResNewSubDevice(tile, tp, xj, yj, direction, PendingList)
|
|||
{
|
||||
tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
|
||||
tcell->te_nextt = NULL;
|
||||
tcell->te_thist = j->deviceList;
|
||||
InitializeNode(resptr, xj, yj, RES_NODE_DEVICE);
|
||||
tcell->te_thist = ri->deviceList;
|
||||
InitializeResNode(resptr, xj, yj, RES_NODE_DEVICE);
|
||||
resptr->rn_te = tcell;
|
||||
ResAddToQueue(resptr, PendingList);
|
||||
}
|
||||
|
|
@ -181,8 +181,8 @@ ResProcessJunction(tile, tp, xj, yj, NodeList)
|
|||
ResJunction *junction;
|
||||
resNode *resptr;
|
||||
jElement *jcell;
|
||||
tileJunk *j0 = (tileJunk *)TiGetClientPTR(tile);
|
||||
tileJunk *j2 = (tileJunk *)TiGetClientPTR(tp);
|
||||
resInfo *ri0 = (resInfo *)TiGetClientPTR(tile);
|
||||
resInfo *ri2 = (resInfo *)TiGetClientPTR(tp);
|
||||
|
||||
#ifdef PARANOID
|
||||
if (tile == tp)
|
||||
|
|
@ -191,12 +191,12 @@ ResProcessJunction(tile, tp, xj, yj, NodeList)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
if (j2->tj_status & RES_TILE_DONE) return;
|
||||
if (ri2->ri_status & RES_TILE_DONE) return;
|
||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
||||
resptr->rn_te = (tElement *) NULL;
|
||||
junction = (ResJunction *) mallocMagic((unsigned)(sizeof(ResJunction)));
|
||||
jcell = (jElement *) mallocMagic((unsigned)(sizeof(jElement)));
|
||||
InitializeNode(resptr, xj, yj, RES_NODE_JUNCTION);
|
||||
InitializeResNode(resptr, xj, yj, RES_NODE_JUNCTION);
|
||||
resptr->rn_je = jcell;
|
||||
ResAddToQueue(resptr, NodeList);
|
||||
|
||||
|
|
@ -208,10 +208,10 @@ ResProcessJunction(tile, tp, xj, yj, NodeList)
|
|||
junction->rj_Tile[1] = tp;
|
||||
junction->rj_loc.p_x =xj;
|
||||
junction->rj_loc.p_y =yj;
|
||||
junction->rj_nextjunction[0] = j0->junctionList;
|
||||
j0->junctionList = junction;
|
||||
junction->rj_nextjunction[1] = j2->junctionList;
|
||||
j2->junctionList = junction;
|
||||
junction->rj_nextjunction[0] = ri0->junctionList;
|
||||
ri0->junctionList = junction;
|
||||
junction->rj_nextjunction[1] = ri2->junctionList;
|
||||
ri2->junctionList = junction;
|
||||
|
||||
NEWBREAK(junction->rj_jnode,tile, junction->rj_loc.p_x,
|
||||
junction->rj_loc.p_y, NULL);
|
||||
|
|
|
|||
303
resis/ResMain.c
303
resis/ResMain.c
|
|
@ -35,13 +35,12 @@ resNode *ResNodeList = NULL; /* Processed Nodes */
|
|||
resDevice *ResDevList = NULL; /* Devices */
|
||||
ResContactPoint *ResContactList = NULL; /* Contacts */
|
||||
resNode *ResNodeQueue = NULL; /* Pending nodes */
|
||||
resNode *ResOriginNode = NULL; /* node where R=0 */
|
||||
resNode *ResNodeAtOrigin = NULL; /* node where R=0 */
|
||||
resNode *resCurrentNode;
|
||||
int ResTileCount = 0; /* Number of tiles rn_status */
|
||||
extern ExtRegion *ResFirst();
|
||||
extern Tile *FindStartTile();
|
||||
extern int ResEachTile();
|
||||
extern ResSimNode *ResInitializeNode();
|
||||
TileTypeBitMask ResSDTypesBitMask;
|
||||
TileTypeBitMask ResSubTypesBitMask;
|
||||
|
||||
|
|
@ -184,7 +183,7 @@ ResDissolveContacts(contacts)
|
|||
* ResMakePortBreakpoints --
|
||||
*
|
||||
* Search for nodes which are ports, and force them to be breakpoints
|
||||
* in the "tileJunk" field of their respective tiles in ResUse. This
|
||||
* in the "resInfo" field of their respective tiles in ResUse. This
|
||||
* ensures that connected nodes that stretch between two ports will
|
||||
* not be assumed to be "hanging" nodes.
|
||||
*
|
||||
|
|
@ -201,13 +200,13 @@ ResMakePortBreakpoints(def)
|
|||
TileTypeBitMask mask;
|
||||
HashSearch hs;
|
||||
HashEntry *entry;
|
||||
ResSimNode *node;
|
||||
ResExtNode *node;
|
||||
int ResAddBreakpointFunc(); /* Forward Declaration */
|
||||
|
||||
HashStartSearch(&hs);
|
||||
while((entry = HashNext(&ResNodeTable,&hs)) != NULL)
|
||||
while((entry = HashNext(&ResNodeTable, &hs)) != NULL)
|
||||
{
|
||||
node = (ResSimNode *)HashGetValue(entry);
|
||||
node = (ResExtNode *)HashGetValue(entry);
|
||||
if (node->status & PORTNODE)
|
||||
{
|
||||
if (node->rs_ttype <= 0)
|
||||
|
|
@ -266,22 +265,22 @@ ResMakePortBreakpoints(def)
|
|||
* ResMakeLabelBreakpoints --
|
||||
*
|
||||
* Search for labels that are part of a node, and force them to be
|
||||
* breakpoints in the "tileJunk" field of their respective tiles in
|
||||
* breakpoints in the "resInfo" field of their respective tiles in
|
||||
* ResUse. This ensures (among other things) that pins of a top level
|
||||
* cell will be retained and become the endpoint of a net.
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ResMakeLabelBreakpoints(def, goodies)
|
||||
CellDef *def;
|
||||
ResGlobalParams *goodies;
|
||||
ResMakeLabelBreakpoints(def, resisdata)
|
||||
CellDef *def;
|
||||
ResisData *resisdata;
|
||||
{
|
||||
Plane *plane;
|
||||
Rect *rect;
|
||||
TileTypeBitMask mask;
|
||||
HashEntry *entry;
|
||||
ResSimNode *node;
|
||||
ResExtNode *node;
|
||||
Label *slab;
|
||||
int ResAddBreakpointFunc(); /* Forward Declaration */
|
||||
|
||||
|
|
@ -292,14 +291,14 @@ ResMakeLabelBreakpoints(def, goodies)
|
|||
if (*(slab->lab_text) == '\0') continue;
|
||||
|
||||
entry = HashFind(&ResNodeTable, slab->lab_text);
|
||||
node = ResInitializeNode(entry);
|
||||
node = ResExtInitNode(entry);
|
||||
|
||||
/* If the drivepoint position changes and the drivepoint is */
|
||||
/* in the "goodies" record, then make sure the tile type in */
|
||||
/* "goodies" gets changed to match. */
|
||||
/* If the drivepoint position changes and the drivepoint is */
|
||||
/* in the "resisdata" record, then make sure the tile type */
|
||||
/* in "resisdata" gets changed to match. */
|
||||
|
||||
if (goodies->rg_devloc == &node->drivepoint)
|
||||
goodies->rg_ttype = slab->lab_type;
|
||||
if (resisdata->rg_devloc == &node->drivepoint)
|
||||
resisdata->rg_ttype = slab->lab_type;
|
||||
|
||||
node->drivepoint = slab->lab_rect.r_ll;
|
||||
node->rs_bbox = slab->lab_rect;
|
||||
|
|
@ -344,7 +343,7 @@ ResMakeLabelBreakpoints(def, goodies)
|
|||
*
|
||||
* ResAddBreakpointFunc --
|
||||
*
|
||||
* Add a breakpoint to the "tileJunk" structure of the tile
|
||||
* Add a breakpoint to the "resInfo" structure of the tile
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -353,9 +352,9 @@ int
|
|||
ResAddBreakpointFunc(tile, dinfo, node)
|
||||
Tile *tile;
|
||||
TileType dinfo; /* (unused) */
|
||||
ResSimNode *node;
|
||||
ResExtNode *node;
|
||||
{
|
||||
tileJunk *junk;
|
||||
resInfo *info;
|
||||
|
||||
if (TiGetClient(tile) == CLIENTDEFAULT)
|
||||
return 0;
|
||||
|
|
@ -430,15 +429,15 @@ ResFindNewContactTiles(contacts)
|
|||
if ((IsSplit(tile) && TTMaskHasType(&mask, TiGetRightType(tile)))
|
||||
|| TTMaskHasType(&mask, TiGetLeftType(tile)))
|
||||
{
|
||||
tileJunk *j = (tileJunk *)TiGetClientPTR(tile);
|
||||
resInfo *ri = (resInfo *)TiGetClientPTR(tile);
|
||||
cElement *ce;
|
||||
|
||||
ce = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
|
||||
contacts->cp_tile[contacts->cp_currentcontact] = tile;
|
||||
ce->ce_thisc = contacts;
|
||||
ce->ce_nextc = j->contactList;
|
||||
ce->ce_nextc = ri->contactList;
|
||||
(contacts->cp_currentcontact) += 1;
|
||||
j->contactList = ce;
|
||||
ri->contactList = ce;
|
||||
}
|
||||
else if (!IsSplit(tile))
|
||||
{
|
||||
|
|
@ -452,15 +451,15 @@ ResFindNewContactTiles(contacts)
|
|||
*/
|
||||
if (TTMaskIntersect(DBResidueMask(ttype), &mask))
|
||||
{
|
||||
tileJunk *j = (tileJunk *)TiGetClientPTR(tile);
|
||||
resInfo *ri = (resInfo *)TiGetClientPTR(tile);
|
||||
cElement *ce;
|
||||
|
||||
ce = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
|
||||
contacts->cp_tile[contacts->cp_currentcontact] = tile;
|
||||
ce->ce_thisc = contacts;
|
||||
ce->ce_nextc = j->contactList;
|
||||
ce->ce_nextc = ri->contactList;
|
||||
(contacts->cp_currentcontact) += 1;
|
||||
j->contactList = ce;
|
||||
ri->contactList = ce;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -490,9 +489,9 @@ ResFindNewContactTiles(contacts)
|
|||
*/
|
||||
|
||||
int
|
||||
ResProcessTiles(goodies, origin)
|
||||
Point *origin;
|
||||
ResGlobalParams *goodies;
|
||||
ResProcessTiles(resisdata, origin)
|
||||
Point *origin;
|
||||
ResisData *resisdata;
|
||||
|
||||
{
|
||||
Tile *startTile;
|
||||
|
|
@ -506,57 +505,12 @@ ResProcessTiles(goodies, origin)
|
|||
|
||||
if (ResOptionsFlags & ResOpt_Signal)
|
||||
{
|
||||
startTile = FindStartTile(goodies, origin);
|
||||
startTile = FindStartTile(resisdata, origin);
|
||||
if (startTile == NULL)
|
||||
return 1;
|
||||
resCurrentNode = NULL;
|
||||
(void) ResEachTile(startTile, origin);
|
||||
}
|
||||
#ifdef ARIEL
|
||||
else if (ResOptionsFlags & ResOpt_Power)
|
||||
{
|
||||
for (fix = ResFixList; fix != NULL; fix = fix->fp_next)
|
||||
{
|
||||
Tile *tile = fix->fp_tile;
|
||||
if (tile == NULL)
|
||||
{
|
||||
tile = PlaneGetHint(ResDef->cd_planes[DBPlane(fix->fp_ttype)]);
|
||||
GOTOPOINT(tile, &(fix->fp_loc));
|
||||
if (TiGetTypeExact(tile) != TT_SPACE)
|
||||
{
|
||||
fix->fp_tile = tile;
|
||||
}
|
||||
else
|
||||
{
|
||||
tile = NULL;
|
||||
}
|
||||
}
|
||||
if (tile != NULL)
|
||||
{
|
||||
int x = fix->fp_loc.p_x;
|
||||
int y = fix->fp_loc.p_y;
|
||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
||||
InitializeNode(resptr, x, y, RES_NODE_ORIGIN);
|
||||
resptr->rn_status = TRUE;
|
||||
resptr->rn_noderes = 0;
|
||||
ResAddToQueue(resptr, &ResNodeQueue);
|
||||
fix->fp_node = resptr;
|
||||
NEWBREAK(resptr, tile, x, y, NULL);
|
||||
}
|
||||
}
|
||||
for (fix = ResFixList; fix != NULL; fix = fix->fp_next)
|
||||
{
|
||||
Tile *tile = fix->fp_tile;
|
||||
|
||||
if (tile != NULL && (((tileJunk *)TiGetClientPTR(tile)->tj_status &
|
||||
RES_TILE_DONE) == 0)
|
||||
{
|
||||
resCurrentNode = fix->fp_node;
|
||||
(void) ResEachTile(startile, (Point *)NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef PARANOID
|
||||
else
|
||||
{
|
||||
|
|
@ -569,7 +523,7 @@ ResProcessTiles(goodies, origin)
|
|||
while (ResNodeQueue != NULL)
|
||||
{
|
||||
/*
|
||||
* merged keeps track of whether another node gets merged into
|
||||
* "merged" keeps track of whether another node gets merged into
|
||||
* the current one. If it does, then the node must be processed
|
||||
* because additional junctions or contacts were added
|
||||
*/
|
||||
|
|
@ -587,16 +541,14 @@ ResProcessTiles(goodies, origin)
|
|||
for (tilenum = 0; tilenum < TILES_PER_JUNCTION; tilenum++)
|
||||
{
|
||||
Tile *tile = rj->rj_Tile[tilenum];
|
||||
tileJunk *j = (tileJunk *)TiGetClientPTR(tile);
|
||||
resInfo *ri = (resInfo *)TiGetClientPTR(tile);
|
||||
|
||||
if ((j->tj_status & RES_TILE_DONE) == 0)
|
||||
if ((ri->ri_status & RES_TILE_DONE) == 0)
|
||||
{
|
||||
resCurrentNode = resptr2;
|
||||
merged |= ResEachTile(tile, (Point *)NULL);
|
||||
}
|
||||
if (merged & ORIGIN) break;
|
||||
}
|
||||
if (merged & ORIGIN) break;
|
||||
rj->rj_status = TRUE;
|
||||
}
|
||||
}
|
||||
|
|
@ -607,16 +559,15 @@ ResProcessTiles(goodies, origin)
|
|||
{
|
||||
ResContactPoint *cp = workingc->ce_thisc;
|
||||
|
||||
if (merged & ORIGIN) break;
|
||||
if (cp->cp_status == FALSE)
|
||||
{
|
||||
int newstatus = TRUE;
|
||||
for (tilenum = 0; tilenum < cp->cp_currentcontact; tilenum++)
|
||||
{
|
||||
Tile *tile = cp->cp_tile[tilenum];
|
||||
tileJunk *j = (tileJunk *) TiGetClientPTR(tile);
|
||||
resInfo *ri = (resInfo *) TiGetClientPTR(tile);
|
||||
|
||||
if ((j->tj_status & RES_TILE_DONE) == 0)
|
||||
if ((ri->ri_status & RES_TILE_DONE) == 0)
|
||||
{
|
||||
if (cp->cp_cnode[tilenum] == resptr2)
|
||||
{
|
||||
|
|
@ -628,9 +579,7 @@ ResProcessTiles(goodies, origin)
|
|||
newstatus = FALSE;
|
||||
}
|
||||
}
|
||||
if (merged & ORIGIN) break;
|
||||
}
|
||||
if (merged & ORIGIN) break;
|
||||
cp->cp_status = newstatus;
|
||||
}
|
||||
}
|
||||
|
|
@ -646,15 +595,15 @@ ResProcessTiles(goodies, origin)
|
|||
ResRemoveFromQueue(resptr2, &ResNodeQueue);
|
||||
resptr2->rn_more = ResNodeList;
|
||||
resptr2->rn_less = NULL;
|
||||
resptr2->rn_status &= ~PENDING;
|
||||
resptr2->rn_status |= FINISHED | MARKED;
|
||||
resptr2->rn_status &= ~RES_PENDING;
|
||||
resptr2->rn_status |= RES_FINISHED | RES_MARKED;
|
||||
if (ResNodeList != NULL)
|
||||
{
|
||||
ResNodeList->rn_less = resptr2;
|
||||
}
|
||||
if (resptr2->rn_noderes == 0)
|
||||
{
|
||||
ResOriginNode=resptr2;
|
||||
ResNodeAtOrigin = resptr2;
|
||||
}
|
||||
ResNodeList = resptr2;
|
||||
ResCleanNode(resptr2, FALSE, &ResNodeList, &ResNodeQueue);
|
||||
|
|
@ -733,7 +682,7 @@ ResCalcPerimOverlap(tile, dev)
|
|||
* resMakeDevFunc --
|
||||
*
|
||||
* Callback function from ResExtractNet. For each device in a node's
|
||||
* device list pulled from the .sim file, find the tile(s) corresponding
|
||||
* device list pulled from the .ext file, find the tile(s) corresponding
|
||||
* to the device in the source tree, and fill out the complete device
|
||||
* record (namely the full device area).
|
||||
*
|
||||
|
|
@ -771,7 +720,7 @@ resMakeDevFunc(tile, dinfo, cx)
|
|||
|
||||
/* If more than one tile type extracts to the same device, then */
|
||||
/* the device type may be different from what was recorded when */
|
||||
/* the sim file was read. Restricted to the plane of the */
|
||||
/* the .ext file was read. Restricted to the plane of the */
|
||||
/* original type to avoid conflict with completely different */
|
||||
/* devices (like transistors vs. MiM caps). */
|
||||
|
||||
|
|
@ -1035,9 +984,9 @@ ResShaveContacts(tile, dinfo, def)
|
|||
*/
|
||||
|
||||
bool
|
||||
ResExtractNet(node, goodies, cellname)
|
||||
ResSimNode *node;
|
||||
ResGlobalParams *goodies;
|
||||
ResExtractNet(node, resisdata, cellname)
|
||||
ResExtNode *node;
|
||||
ResisData *resisdata;
|
||||
char *cellname;
|
||||
{
|
||||
SearchContext scx;
|
||||
|
|
@ -1059,12 +1008,12 @@ ResExtractNet(node, goodies, cellname)
|
|||
ResDevList = NULL;
|
||||
ResNodeQueue = NULL;
|
||||
ResContactList = NULL;
|
||||
ResOriginNode = NULL;
|
||||
ResNodeAtOrigin = NULL;
|
||||
|
||||
/* Pass back network pointers */
|
||||
|
||||
goodies->rg_maxres = 0;
|
||||
goodies->rg_tilecount = 0;
|
||||
resisdata->rg_maxres = 0;
|
||||
resisdata->rg_tilecount = 0;
|
||||
|
||||
/* Set up internal stuff if this is the first time through */
|
||||
|
||||
|
|
@ -1103,11 +1052,6 @@ ResExtractNet(node, goodies, cellname)
|
|||
|
||||
DBCellClearDef(ResUse->cu_def);
|
||||
|
||||
#ifdef ARIEL
|
||||
if ((ResOptionsFlags & ResOpt_Power) &&
|
||||
strcmp(node->name, goodies->rg_name) != 0) continue;
|
||||
#endif
|
||||
|
||||
/* Copy Paint */
|
||||
|
||||
scx.scx_area.r_ll.p_x = node->location.p_x - 2;
|
||||
|
|
@ -1152,10 +1096,10 @@ ResExtractNet(node, goodies, cellname)
|
|||
resMakeDevFunc, (ClientData)thisDev);
|
||||
if (result == 0)
|
||||
{
|
||||
TxError("No device of type %s found at location %d,%d\n",
|
||||
TxError("No device of type %s found at location %s, %s\n",
|
||||
DBTypeLongNameTbl[thisDev->type],
|
||||
tptr->thisDev->location.p_x,
|
||||
tptr->thisDev->location.p_y);
|
||||
DBWPrintValue(tptr->thisDev->location.p_x, (MagWindow*)NULL, TRUE),
|
||||
DBWPrintValue(tptr->thisDev->location.p_y, (MagWindow*)NULL, FALSE));
|
||||
freeMagic(thisDev);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1219,7 +1163,7 @@ ResExtractNet(node, goodies, cellname)
|
|||
|
||||
ResDissolveContacts(ResContactList);
|
||||
|
||||
/* Add "junk" fields to tiles */
|
||||
/* Add "resInfo" fields to tiles */
|
||||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
{
|
||||
|
|
@ -1232,39 +1176,22 @@ ResExtractNet(node, goodies, cellname)
|
|||
(ClientData) &ResDevList);
|
||||
}
|
||||
|
||||
/* Finish preprocessing. */
|
||||
/* If this is a top-level cell, then determine where connections
|
||||
* are made into the cell from ports. Otherwise, determine points
|
||||
* of entry by looking at how all parent cells connect to this
|
||||
* cell.
|
||||
*/
|
||||
|
||||
ResMakePortBreakpoints(ResUse->cu_def);
|
||||
ResMakeLabelBreakpoints(ResUse->cu_def, goodies);
|
||||
ResMakeLabelBreakpoints(ResUse->cu_def, resisdata);
|
||||
|
||||
/* Finish preprocessing. */
|
||||
|
||||
ResFindNewContactTiles(ResContactList);
|
||||
ResPreProcessDevices(DevTiles, ResDevList, ResUse->cu_def);
|
||||
|
||||
#ifdef LAPLACE
|
||||
if (ResOptionsFlags & ResOpt_DoLaplace)
|
||||
{
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
{
|
||||
Plane *plane = ResUse->cu_def->cd_planes[pNum];
|
||||
Rect *rect = &ResUse->cu_def->cd_bbox;
|
||||
Res1d(plane, rect);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ARIEL
|
||||
if (ResOptionsFlags & ResOpt_Power)
|
||||
{
|
||||
for (fix = startlist; fix != NULL; fix = fix->fp_next)
|
||||
{
|
||||
fix->fp_tile = PlaneGetHint(ResUse->cu_def->cd_planes[DBPlane(fix->fp_ttype)]);
|
||||
GOTOPOINT(fix->fp_tile, &fix->fp_loc);
|
||||
if (TiGetTypeExact(fix->fp_tile) == TT_SPACE) fix->fp_tile = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* do extraction */
|
||||
if (ResProcessTiles(goodies, &startpoint) != 0) return TRUE;
|
||||
if (ResProcessTiles(resisdata, &startpoint) != 0) return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -1383,7 +1310,7 @@ ResGetTileFunc(tile, dinfo, tpptr)
|
|||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* FindStartTile-- To start the extraction, we need to find the first driver.
|
||||
* The sim file gives us the location of a point in or near (within 1
|
||||
* The .ext file gives us the location of a point in or near (within 1
|
||||
* unit) of the device. FindStartTile looks for the device, then
|
||||
* for adjoining diffusion. The diffusion tile is returned.
|
||||
*
|
||||
|
|
@ -1397,10 +1324,9 @@ ResGetTileFunc(tile, dinfo, tpptr)
|
|||
*/
|
||||
|
||||
Tile *
|
||||
FindStartTile(goodies, SourcePoint)
|
||||
FindStartTile(resisdata, SourcePoint)
|
||||
ResisData *resisdata;
|
||||
Point *SourcePoint;
|
||||
ResGlobalParams *goodies;
|
||||
|
||||
{
|
||||
Point workingPoint;
|
||||
Tile *tile, *tp;
|
||||
|
|
@ -1413,39 +1339,39 @@ FindStartTile(goodies, SourcePoint)
|
|||
/* If the drive point is on a contact, check for the contact residues */
|
||||
/* first, then the contact type itself. */
|
||||
|
||||
if (DBIsContact(goodies->rg_ttype))
|
||||
if (DBIsContact(resisdata->rg_ttype))
|
||||
{
|
||||
TileTypeBitMask *rmask = DBResidueMask(goodies->rg_ttype);
|
||||
TileType savtype = goodies->rg_ttype;
|
||||
TileTypeBitMask *rmask = DBResidueMask(resisdata->rg_ttype);
|
||||
TileType savtype = resisdata->rg_ttype;
|
||||
TileType rtype;
|
||||
|
||||
for (rtype = TT_TECHDEPBASE; rtype < DBNumUserLayers; rtype++)
|
||||
if (TTMaskHasType(rmask, rtype))
|
||||
{
|
||||
goodies->rg_ttype = rtype;
|
||||
if ((tile = FindStartTile(goodies, SourcePoint)) != NULL)
|
||||
resisdata->rg_ttype = rtype;
|
||||
if ((tile = FindStartTile(resisdata, SourcePoint)) != NULL)
|
||||
{
|
||||
goodies->rg_ttype = savtype;
|
||||
resisdata->rg_ttype = savtype;
|
||||
return tile;
|
||||
}
|
||||
}
|
||||
goodies->rg_ttype = savtype;
|
||||
resisdata->rg_ttype = savtype;
|
||||
}
|
||||
|
||||
workingPoint.p_x = goodies->rg_devloc->p_x;
|
||||
workingPoint.p_y = goodies->rg_devloc->p_y;
|
||||
workingPoint.p_x = resisdata->rg_devloc->p_x;
|
||||
workingPoint.p_y = resisdata->rg_devloc->p_y;
|
||||
|
||||
pnum = DBPlane(goodies->rg_ttype);
|
||||
pnum = DBPlane(resisdata->rg_ttype);
|
||||
|
||||
/* for drivepoints, we don't have to find a device */
|
||||
if (goodies->rg_status & DRIVEONLY)
|
||||
if (resisdata->rg_status & DRIVEONLY)
|
||||
{
|
||||
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
||||
GOTOPOINT(tile, &workingPoint);
|
||||
SourcePoint->p_x = workingPoint.p_x;
|
||||
SourcePoint->p_y = workingPoint.p_y;
|
||||
|
||||
if (TiGetTypeExact(tile) == goodies->rg_ttype)
|
||||
if (TiGetTypeExact(tile) == resisdata->rg_ttype)
|
||||
return tile;
|
||||
else
|
||||
{
|
||||
|
|
@ -1457,18 +1383,19 @@ FindStartTile(goodies, SourcePoint)
|
|||
if (workingPoint.p_x == LEFT(tile))
|
||||
{
|
||||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
|
||||
if (TiGetRightType(tp) == goodies->rg_ttype)
|
||||
if (TiGetRightType(tp) == resisdata->rg_ttype)
|
||||
return(tp);
|
||||
}
|
||||
else if (workingPoint.p_y == BOTTOM(tile))
|
||||
{
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
|
||||
if (TiGetTopType(tp) == goodies->rg_ttype)
|
||||
if (TiGetTopType(tp) == resisdata->rg_ttype)
|
||||
return(tp);
|
||||
}
|
||||
}
|
||||
TxError("Couldn't find wire at %d %d\n",
|
||||
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
|
||||
TxError("Couldn't find wire at %s %s\n",
|
||||
DBWPrintValue(resisdata->rg_devloc->p_x, (MagWindow *)NULL, TRUE),
|
||||
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow *)NULL, FALSE));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1483,15 +1410,17 @@ FindStartTile(goodies, SourcePoint)
|
|||
t1 = TiGetRightType(tile);
|
||||
else
|
||||
{
|
||||
TxError("Couldn't find device at %d %d\n",
|
||||
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
|
||||
TxError("Couldn't find device at %s %s\n",
|
||||
DBWPrintValue(resisdata->rg_devloc->p_x, (MagWindow *)NULL, TRUE),
|
||||
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow *)NULL, FALSE));
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
else if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetType(tile)) == 0)
|
||||
{
|
||||
TxError("Couldn't find device at %d %d\n",
|
||||
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
|
||||
TxError("Couldn't find device at %s %s\n",
|
||||
DBWPrintValue(resisdata->rg_devloc->p_x, (MagWindow *)NULL, TRUE),
|
||||
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow *)NULL, FALSE));
|
||||
return(NULL);
|
||||
}
|
||||
else
|
||||
|
|
@ -1522,8 +1451,9 @@ FindStartTile(goodies, SourcePoint)
|
|||
else
|
||||
{
|
||||
const ClientData ticlient = TiGetClient(tp);
|
||||
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
||||
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
|
||||
const resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||
|
||||
if (ticlient != CLIENTDEFAULT && rinfo->ri_status & RES_TILE_DEV)
|
||||
complex = TRUE;
|
||||
}
|
||||
}
|
||||
|
|
@ -1543,8 +1473,8 @@ FindStartTile(goodies, SourcePoint)
|
|||
else
|
||||
{
|
||||
const ClientData ticlient = TiGetClient(tp);
|
||||
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
||||
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
|
||||
const resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||
if (ticlient != CLIENTDEFAULT && rinfo->ri_status & RES_TILE_DEV)
|
||||
complex = TRUE;
|
||||
}
|
||||
}
|
||||
|
|
@ -1564,8 +1494,8 @@ FindStartTile(goodies, SourcePoint)
|
|||
else
|
||||
{
|
||||
const ClientData ticlient = TiGetClient(tp);
|
||||
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
||||
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
|
||||
const resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||
if (ticlient != CLIENTDEFAULT && rinfo->ri_status & RES_TILE_DEV)
|
||||
complex = TRUE;
|
||||
}
|
||||
}
|
||||
|
|
@ -1585,8 +1515,8 @@ FindStartTile(goodies, SourcePoint)
|
|||
else
|
||||
{
|
||||
const ClientData ticlient = TiGetClient(tp);
|
||||
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
||||
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
|
||||
const resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||
if (ticlient != CLIENTDEFAULT && rinfo->ri_status & RES_TILE_DEV)
|
||||
complex = TRUE;
|
||||
}
|
||||
}
|
||||
|
|
@ -1599,7 +1529,7 @@ FindStartTile(goodies, SourcePoint)
|
|||
|
||||
if (devStack == NULL) devStack = StackNew(8);
|
||||
|
||||
((tileJunk *)TiGetClientPTR(tile))->tj_status |= RES_TILE_PUSHED;
|
||||
((resInfo *)TiGetClientPTR(tile))->ri_status |= RES_TILE_PUSHED;
|
||||
STACKPUSH((ClientData)tile, devStack);
|
||||
while (!StackEmpty(devStack))
|
||||
{
|
||||
|
|
@ -1626,12 +1556,12 @@ FindStartTile(goodies, SourcePoint)
|
|||
const ClientData ticlient = TiGetClient(tp);
|
||||
if (ticlient != CLIENTDEFAULT)
|
||||
{
|
||||
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
||||
if (tj->tj_status & RES_TILE_DEV)
|
||||
resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||
if (rinfo->ri_status & RES_TILE_DEV)
|
||||
{
|
||||
if (!(tj->tj_status & RES_TILE_PUSHED))
|
||||
if (!(rinfo->ri_status & RES_TILE_PUSHED))
|
||||
{
|
||||
tj->tj_status |= RES_TILE_PUSHED;
|
||||
rinfo->ri_status |= RES_TILE_PUSHED;
|
||||
STACKPUSH((ClientData)tp, devStack);
|
||||
}
|
||||
}
|
||||
|
|
@ -1660,12 +1590,12 @@ FindStartTile(goodies, SourcePoint)
|
|||
const ClientData ticlient = TiGetClient(tp);
|
||||
if (ticlient != CLIENTDEFAULT)
|
||||
{
|
||||
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
||||
if (tj->tj_status & RES_TILE_DEV)
|
||||
resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||
if (rinfo->ri_status & RES_TILE_DEV)
|
||||
{
|
||||
if (!(tj->tj_status & RES_TILE_PUSHED))
|
||||
if (!(rinfo->ri_status & RES_TILE_PUSHED))
|
||||
{
|
||||
tj->tj_status |= RES_TILE_PUSHED;
|
||||
rinfo->ri_status |= RES_TILE_PUSHED;
|
||||
STACKPUSH((ClientData)tp, devStack);
|
||||
}
|
||||
}
|
||||
|
|
@ -1694,12 +1624,12 @@ FindStartTile(goodies, SourcePoint)
|
|||
const ClientData ticlient = TiGetClient(tp);
|
||||
if (ticlient != CLIENTDEFAULT)
|
||||
{
|
||||
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
||||
if (tj->tj_status & RES_TILE_DEV)
|
||||
resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||
if (rinfo->ri_status & RES_TILE_DEV)
|
||||
{
|
||||
if (!(tj->tj_status & RES_TILE_PUSHED))
|
||||
if (!(rinfo->ri_status & RES_TILE_PUSHED))
|
||||
{
|
||||
tj->tj_status |= RES_TILE_PUSHED;
|
||||
rinfo->ri_status |= RES_TILE_PUSHED;
|
||||
STACKPUSH((ClientData)tp, devStack);
|
||||
}
|
||||
}
|
||||
|
|
@ -1728,12 +1658,12 @@ FindStartTile(goodies, SourcePoint)
|
|||
const ClientData ticlient = TiGetClient(tp);
|
||||
if (ticlient != CLIENTDEFAULT)
|
||||
{
|
||||
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
||||
if (tj->tj_status & RES_TILE_DEV)
|
||||
resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||
if (rinfo->ri_status & RES_TILE_DEV)
|
||||
{
|
||||
if (!(tj->tj_status & RES_TILE_PUSHED))
|
||||
if (!(rinfo->ri_status & RES_TILE_PUSHED))
|
||||
{
|
||||
tj->tj_status |= RES_TILE_PUSHED;
|
||||
rinfo->ri_status |= RES_TILE_PUSHED;
|
||||
STACKPUSH((ClientData)tp, devStack);
|
||||
}
|
||||
}
|
||||
|
|
@ -1782,8 +1712,9 @@ FindStartTile(goodies, SourcePoint)
|
|||
/* Didn't find a terminal (S/D or substrate) type tile anywhere. Flag an error. */
|
||||
|
||||
if (devptr == NULL)
|
||||
TxError("Couldn't find a terminal of the device at %d %d\n",
|
||||
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
|
||||
TxError("Couldn't find a terminal of the device at %s %s\n",
|
||||
DBWPrintValue(resisdata->rg_devloc->p_x, (MagWindow*)NULL, TRUE),
|
||||
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow*)NULL, FALSE));
|
||||
return((Tile *) NULL);
|
||||
}
|
||||
|
||||
|
|
@ -1791,7 +1722,7 @@ FindStartTile(goodies, SourcePoint)
|
|||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResGetDevice -- Once the net is extracted, we still have to equate
|
||||
* the sim file devices with the layout devices. ResGetDevice
|
||||
* the .ext file devices with the layout devices. ResGetDevice
|
||||
* looks for a device at the given location. "type" is also
|
||||
* specified to that the right plane will be searched.
|
||||
*
|
||||
|
|
@ -1827,7 +1758,7 @@ ResGetDevice(pt, type)
|
|||
{
|
||||
if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetLeftType(tile))
|
||||
|| TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetRightType(tile)))
|
||||
return (((tileJunk *)CD2PTR(ticlient))->deviceList);
|
||||
return (((resInfo *)CD2PTR(ticlient))->deviceList);
|
||||
}
|
||||
else if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetType(tile)))
|
||||
{
|
||||
|
|
@ -1835,7 +1766,7 @@ ResGetDevice(pt, type)
|
|||
* error and indicates a problem that needs debugging.
|
||||
*/
|
||||
if (ticlient != CLIENTDEFAULT)
|
||||
return (((tileJunk *)CD2PTR(ticlient))->deviceList);
|
||||
return (((resInfo *)CD2PTR(ticlient))->deviceList);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,9 +52,9 @@ bool ResCalcEastWest();
|
|||
*/
|
||||
|
||||
bool
|
||||
ResCalcTileResistance(tile, junk, pendingList, doneList)
|
||||
ResCalcTileResistance(tile, info, pendingList, doneList)
|
||||
Tile *tile;
|
||||
tileJunk *junk;
|
||||
resInfo *info;
|
||||
resNode **pendingList, **doneList;
|
||||
|
||||
{
|
||||
|
|
@ -67,7 +67,7 @@ ResCalcTileResistance(tile, junk, pendingList, doneList)
|
|||
merged = FALSE;
|
||||
device = FALSE;
|
||||
|
||||
if ((p1 = junk->breakList) == NULL) return FALSE;
|
||||
if ((p1 = info->breakList) == NULL) return FALSE;
|
||||
for (; p1; p1 = p1->br_next)
|
||||
{
|
||||
int x = p1->br_loc.p_x;
|
||||
|
|
@ -133,7 +133,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
|||
resElement *element;
|
||||
resNode *currNode;
|
||||
float rArea;
|
||||
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
|
||||
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||
|
||||
merged = FALSE;
|
||||
height = TOP(tile) - BOTTOM(tile);
|
||||
|
|
@ -143,12 +143,12 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
|||
* breakpoint, then return.
|
||||
*/
|
||||
|
||||
p1 = junk->breakList;
|
||||
p1 = info->breakList;
|
||||
if (p1->br_next == NULL)
|
||||
{
|
||||
p1->br_this->rn_float.rn_area += height * (LEFT(tile) - RIGHT(tile));
|
||||
freeMagic((char *)p1);
|
||||
junk->breakList = NULL;
|
||||
info->breakList = NULL;
|
||||
return(merged);
|
||||
}
|
||||
|
||||
|
|
@ -164,14 +164,14 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
|||
|
||||
/* Re-sort nodes left to right. */
|
||||
|
||||
ResSortBreaks(&junk->breakList, TRUE);
|
||||
ResSortBreaks(&info->breakList, TRUE);
|
||||
|
||||
/*
|
||||
* Eliminate breakpoints with the same X coordinate and merge
|
||||
* their nodes.
|
||||
*/
|
||||
|
||||
p2= junk->breakList;
|
||||
p2= info->breakList;
|
||||
|
||||
/* Add extra left area to leftmost node */
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
|||
}
|
||||
|
||||
/*
|
||||
* Was the node used in another junk or breakpoint?
|
||||
* Was the node used in another info or breakpoint?
|
||||
* If so, replace the old node with the new one.
|
||||
*/
|
||||
|
||||
|
|
@ -263,10 +263,6 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
|||
{
|
||||
resistor->rr_status = RES_EW;
|
||||
}
|
||||
#ifdef ARIEL
|
||||
resistor->rr_csArea = height *
|
||||
ExtCurStyle->exts_thick[resistor->rr_tt];
|
||||
#endif
|
||||
resistor->rr_value =
|
||||
(float)ExtCurStyle->exts_sheetResist[resistor->rr_tt]
|
||||
* (float)(p2->br_loc.p_x - p1->br_loc.p_x)
|
||||
|
|
@ -282,7 +278,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
|||
|
||||
p2->br_this->rn_float.rn_area += height * (RIGHT(tile) - p2->br_loc.p_x);
|
||||
freeMagic((char *)p2);
|
||||
junk->breakList = NULL;
|
||||
info->breakList = NULL;
|
||||
return merged;
|
||||
}
|
||||
|
||||
|
|
@ -313,7 +309,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
|||
resElement *element;
|
||||
resNode *currNode;
|
||||
float rArea;
|
||||
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
|
||||
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||
|
||||
merged = FALSE;
|
||||
width = RIGHT(tile) - LEFT(tile);
|
||||
|
|
@ -323,17 +319,17 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
|||
* breakpoint, then return.
|
||||
*/
|
||||
|
||||
p1 = junk->breakList;
|
||||
p1 = info->breakList;
|
||||
if (p1->br_next == NULL)
|
||||
{
|
||||
p1->br_this->rn_float.rn_area += width * (TOP(tile) - BOTTOM(tile));
|
||||
freeMagic((char *)p1);
|
||||
junk->breakList = NULL;
|
||||
info->breakList = NULL;
|
||||
return(merged);
|
||||
}
|
||||
|
||||
/* Re-sort nodes south to north. */
|
||||
ResSortBreaks(&junk->breakList, FALSE);
|
||||
ResSortBreaks(&info->breakList, FALSE);
|
||||
|
||||
/* Simplified split tile handling */
|
||||
if (IsSplit(tile))
|
||||
|
|
@ -350,7 +346,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
|||
* their nodes.
|
||||
*/
|
||||
|
||||
p2 = junk->breakList;
|
||||
p2 = info->breakList;
|
||||
|
||||
/* Add extra left area to leftmost node */
|
||||
|
||||
|
|
@ -392,7 +388,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
|||
}
|
||||
|
||||
/*
|
||||
* Was the node used in another junk or breakpoint?
|
||||
* Was the node used in another info or breakpoint?
|
||||
* If so, replace the old node with the new one.
|
||||
*/
|
||||
p3 = p2->br_next;
|
||||
|
|
@ -440,10 +436,6 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
|||
{
|
||||
resistor->rr_status = RES_NS;
|
||||
}
|
||||
#ifdef ARIEL
|
||||
resistor->rr_csArea = width
|
||||
* ExtCurStyle->exts_thick[resistor->rr_tt];
|
||||
#endif
|
||||
resistor->rr_value =
|
||||
(float)ExtCurStyle->exts_sheetResist[resistor->rr_tt]
|
||||
* (float)(p2->br_loc.p_y - p1->br_loc.p_y)
|
||||
|
|
@ -457,7 +449,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
|||
}
|
||||
p2->br_this->rn_float.rn_area += width * (TOP(tile) - p2->br_loc.p_y);
|
||||
freeMagic((char *)p2);
|
||||
junk->breakList = NULL;
|
||||
info->breakList = NULL;
|
||||
return(merged);
|
||||
}
|
||||
|
||||
|
|
@ -490,7 +482,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
|||
bool merged;
|
||||
int devcount, devedge, deltax, deltay;
|
||||
Breakpoint *p1, *p2, *p3;
|
||||
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
|
||||
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||
|
||||
merged = FALSE;
|
||||
|
||||
|
|
@ -499,10 +491,10 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
|||
* breakpoint, then return.
|
||||
*/
|
||||
|
||||
if (junk->breakList->br_next == NULL)
|
||||
if (info->breakList->br_next == NULL)
|
||||
{
|
||||
freeMagic((char *)junk->breakList);
|
||||
junk->breakList = NULL;
|
||||
freeMagic((char *)info->breakList);
|
||||
info->breakList = NULL;
|
||||
return(merged);
|
||||
}
|
||||
|
||||
|
|
@ -511,7 +503,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
|||
|
||||
devcount = 0;
|
||||
devedge = 0;
|
||||
for (p1 = junk->breakList; p1 != NULL; p1 = p1->br_next)
|
||||
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
|
||||
{
|
||||
if (p1->br_this->rn_why == RES_NODE_DEVICE)
|
||||
{
|
||||
|
|
@ -533,9 +525,9 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
|||
(devedge & TOPEDGE) == devedge ||
|
||||
(devedge & BOTTOMEDGE) == devedge)
|
||||
{
|
||||
ResSortBreaks(&junk->breakList,TRUE);
|
||||
ResSortBreaks(&info->breakList,TRUE);
|
||||
p2 = NULL;
|
||||
for (p1 = junk->breakList; p1 != NULL; p1 = p1->br_next)
|
||||
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
|
||||
{
|
||||
if (p1->br_this->rn_why == RES_NODE_DEVICE)
|
||||
break;
|
||||
|
|
@ -595,9 +587,9 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
|||
}
|
||||
|
||||
/* Re-sort nodes south to north. */
|
||||
ResSortBreaks(&junk->breakList, FALSE);
|
||||
ResSortBreaks(&info->breakList, FALSE);
|
||||
p2 = NULL;
|
||||
for (p1 = junk->breakList; p1 != NULL; p1 = p1->br_next)
|
||||
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
|
||||
{
|
||||
if (p1->br_this->rn_why == RES_NODE_DEVICE)
|
||||
{
|
||||
|
|
@ -692,17 +684,17 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
|||
(RIGHT(tile) - LEFT(tile)) > (TOP(tile) - BOTTOM(tile))))
|
||||
{
|
||||
/* re-sort nodes south to north. */
|
||||
ResSortBreaks(&junk->breakList, FALSE);
|
||||
ResSortBreaks(&info->breakList, FALSE);
|
||||
|
||||
/* eliminate duplicate S/D pointers */
|
||||
for (p1 = junk->breakList; p1 != NULL; p1 = p1->br_next)
|
||||
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
|
||||
{
|
||||
if (p1->br_this->rn_why == RES_NODE_DEVICE &&
|
||||
(p1->br_loc.p_y == BOTTOM(tile) ||
|
||||
p1->br_loc.p_y == TOP(tile)))
|
||||
{
|
||||
p3 = NULL;
|
||||
p2 = junk->breakList;
|
||||
p2 = info->breakList;
|
||||
while (p2 != NULL)
|
||||
{
|
||||
if (p2->br_this == p1->br_this && p2 != p1 &&
|
||||
|
|
@ -711,9 +703,9 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
|||
{
|
||||
if (p3 == NULL)
|
||||
{
|
||||
junk->breakList = p2->br_next;
|
||||
info->breakList = p2->br_next;
|
||||
freeMagic((char *) p2);
|
||||
p2 = junk->breakList;
|
||||
p2 = info->breakList;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -735,14 +727,14 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
|||
else
|
||||
{
|
||||
/* Eliminate duplicate S/D pointers */
|
||||
for (p1 = junk->breakList; p1 != NULL; p1 = p1->br_next)
|
||||
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
|
||||
{
|
||||
if (p1->br_this->rn_why == RES_NODE_DEVICE &&
|
||||
(p1->br_loc.p_x == LEFT(tile) ||
|
||||
p1->br_loc.p_x == RIGHT(tile)))
|
||||
{
|
||||
p3 = NULL;
|
||||
p2 = junk->breakList;
|
||||
p2 = info->breakList;
|
||||
while (p2 != NULL)
|
||||
{
|
||||
if (p2->br_this == p1->br_this && p2 != p1 &&
|
||||
|
|
@ -751,9 +743,9 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
|||
{
|
||||
if (p3 == NULL)
|
||||
{
|
||||
junk->breakList = p2->br_next;
|
||||
info->breakList = p2->br_next;
|
||||
freeMagic((char *) p2);
|
||||
p2 = junk->breakList;
|
||||
p2 = info->breakList;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -813,7 +805,7 @@ ResDoContacts(contact, nodes, resList)
|
|||
int y = contact->cp_center.p_y;
|
||||
|
||||
resptr = (resNode *) mallocMagic((unsigned) (sizeof(resNode)));
|
||||
InitializeNode(resptr, x, y, RES_NODE_CONTACT);
|
||||
InitializeResNode(resptr, x, y, RES_NODE_CONTACT);
|
||||
ResAddToQueue(resptr, nodes);
|
||||
|
||||
ccell = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
|
||||
|
|
@ -866,7 +858,7 @@ ResDoContacts(contact, nodes, resList)
|
|||
Tile *tile = contact->cp_tile[tilenum];
|
||||
|
||||
resptr = (resNode *) mallocMagic((unsigned) (sizeof(resNode)));
|
||||
InitializeNode(resptr, x, y, RES_NODE_CONTACT);
|
||||
InitializeResNode(resptr, x, y, RES_NODE_CONTACT);
|
||||
ResAddToQueue(resptr, nodes);
|
||||
|
||||
/* Add contact pointer to node */
|
||||
|
|
@ -916,11 +908,6 @@ ResDoContacts(contact, nodes, resList)
|
|||
resistor->rr_value =
|
||||
(float)ExtCurStyle->exts_viaResist[contact->cp_type] /
|
||||
(float)(squaresx * squaresy);
|
||||
#ifdef ARIEL
|
||||
resistor->rr_csArea =
|
||||
(float)ExtCurStyle->exts_thick[contact->cp_type] /
|
||||
(float)(squaresx * squaresy);
|
||||
#endif
|
||||
resistor->rr_tt = contact->cp_type;
|
||||
resistor->rr_float.rr_area = 0;
|
||||
resistor->rr_status = 0;
|
||||
|
|
|
|||
135
resis/ResMerge.c
135
resis/ResMerge.c
|
|
@ -53,7 +53,7 @@ ResDoneWithNode(resptr)
|
|||
resResistor *rr1;
|
||||
|
||||
resptr2 = NULL;
|
||||
resptr->rn_status |= RESTRUE;
|
||||
resptr->rn_status |= RES_TRUE;
|
||||
status = UNTOUCHED;
|
||||
|
||||
/* are there any resistors? */
|
||||
|
|
@ -93,9 +93,9 @@ ResDoneWithNode(resptr)
|
|||
ResMergeNodes(resptr2, resptr, &ResNodeQueue, &ResNodeList);
|
||||
resptr2->rn_float.rn_area += rr1->rr_float.rr_area;
|
||||
ResEliminateResistor(rr1, &ResResList);
|
||||
if ((resptr2->rn_status & RESTRUE) == RESTRUE)
|
||||
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
|
||||
{
|
||||
resptr2->rn_status &= ~RESTRUE;
|
||||
resptr2->rn_status &= ~RES_TRUE;
|
||||
ResDoneWithNode(resptr2);
|
||||
}
|
||||
resptr2 = NULL;
|
||||
|
|
@ -108,14 +108,16 @@ ResDoneWithNode(resptr)
|
|||
/* Eliminations that can be only if there are no devices connected */
|
||||
/* to node. Series and dangling connections fall in this group. */
|
||||
|
||||
if ((resptr->rn_te == NULL) && (resptr->rn_why != RES_NODE_ORIGIN)
|
||||
&& (status == UNTOUCHED))
|
||||
if ((status == UNTOUCHED) && (resptr->rn_te == NULL) &&
|
||||
!(resptr->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK)))
|
||||
status = ResSeriesCheck(resptr);
|
||||
|
||||
if ((status == UNTOUCHED) && (resptr->rn_why != RES_NODE_ORIGIN))
|
||||
if ((status == UNTOUCHED) &&
|
||||
!(resptr->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK)))
|
||||
status = ResParallelCheck(resptr);
|
||||
|
||||
if ((status == UNTOUCHED) && (resptr->rn_why != RES_NODE_ORIGIN))
|
||||
if ((status == UNTOUCHED) &&
|
||||
!(resptr->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK)))
|
||||
status = ResTriangleCheck(resptr);
|
||||
}
|
||||
|
||||
|
|
@ -150,14 +152,6 @@ ResFixRes(resptr, resptr2, resptr3, elimResis, newResis)
|
|||
ASSERT(newResis->rr_value > 0, "series");
|
||||
newResis->rr_float.rr_area += elimResis->rr_float.rr_area;
|
||||
|
||||
#ifdef ARIEL
|
||||
if (elimResis->rr_csArea && elimResis->rr_csArea < newResis->rr_csArea
|
||||
|| newResis->rr_csArea == 0)
|
||||
{
|
||||
newResis->rr_csArea = elimResis->rr_csArea;
|
||||
newResis->rr_tt = elimResis->rr_tt;
|
||||
}
|
||||
#endif
|
||||
for (thisREl = resptr3->rn_re; (thisREl != NULL); thisREl = thisREl->re_nextEl)
|
||||
{
|
||||
if (thisREl->re_thisEl == elimResis)
|
||||
|
|
@ -206,9 +200,6 @@ ResFixParallel(elimResis, newResis)
|
|||
newResis->rr_value = 0;
|
||||
}
|
||||
newResis->rr_float.rr_area += elimResis->rr_float.rr_area;
|
||||
#ifdef ARIEL
|
||||
newResis->rr_csArea += elimResis->rr_csArea;
|
||||
#endif
|
||||
ResDeleteResPointer(elimResis->rr_connection1, elimResis);
|
||||
ResDeleteResPointer(elimResis->rr_connection2, elimResis);
|
||||
ResEliminateResistor(elimResis, &ResResList);
|
||||
|
|
@ -253,9 +244,9 @@ ResSeriesCheck(resptr)
|
|||
ResEliminateResistor(rr1, &ResResList);
|
||||
ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue);
|
||||
status = SINGLE;
|
||||
if (resptr2->rn_status & RESTRUE)
|
||||
if (resptr2->rn_status & RES_TRUE)
|
||||
{
|
||||
resptr2->rn_status &= ~RESTRUE;
|
||||
resptr2->rn_status &= ~RES_TRUE;
|
||||
ResDoneWithNode(resptr2);
|
||||
}
|
||||
resptr2 = NULL;
|
||||
|
|
@ -291,9 +282,9 @@ ResSeriesCheck(resptr)
|
|||
rr1->rr_connection1 = rr2->rr_connection2;
|
||||
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
|
||||
}
|
||||
if ((resptr2->rn_status & RESTRUE) == RESTRUE)
|
||||
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
|
||||
{
|
||||
resptr2->rn_status &= ~RESTRUE;
|
||||
resptr2->rn_status &= ~RES_TRUE;
|
||||
ResDoneWithNode(resptr2);
|
||||
}
|
||||
resptr2 = NULL;
|
||||
|
|
@ -322,9 +313,9 @@ ResSeriesCheck(resptr)
|
|||
rr1->rr_connection1 = rr2->rr_connection1;
|
||||
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
|
||||
}
|
||||
if ((resptr2->rn_status & RESTRUE) == RESTRUE)
|
||||
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
|
||||
{
|
||||
resptr2->rn_status &= ~RESTRUE;
|
||||
resptr2->rn_status &= ~RES_TRUE;
|
||||
ResDoneWithNode(resptr2);
|
||||
}
|
||||
resptr2 = NULL;
|
||||
|
|
@ -356,9 +347,9 @@ ResSeriesCheck(resptr)
|
|||
rr1->rr_connection2 = rr2->rr_connection2;
|
||||
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
|
||||
}
|
||||
if ((resptr2->rn_status & RESTRUE) == RESTRUE)
|
||||
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
|
||||
{
|
||||
resptr2->rn_status &= ~RESTRUE;
|
||||
resptr2->rn_status &= ~RES_TRUE;
|
||||
ResDoneWithNode(resptr2);
|
||||
}
|
||||
resptr2 = NULL;
|
||||
|
|
@ -387,9 +378,9 @@ ResSeriesCheck(resptr)
|
|||
rr1->rr_connection2 = rr2->rr_connection1;
|
||||
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
|
||||
}
|
||||
if ((resptr2->rn_status & RESTRUE) == RESTRUE)
|
||||
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
|
||||
{
|
||||
resptr2->rn_status &= ~RESTRUE;
|
||||
resptr2->rn_status &= ~RES_TRUE;
|
||||
ResDoneWithNode(resptr2);
|
||||
}
|
||||
resptr2 = NULL;
|
||||
|
|
@ -444,10 +435,10 @@ ResParallelCheck(resptr)
|
|||
ResFixParallel(r1, r2);
|
||||
status = PARALLEL;
|
||||
resptr2 = NULL;
|
||||
if (resptr3->rn_status & RESTRUE)
|
||||
if (resptr3->rn_status & RES_TRUE)
|
||||
{
|
||||
resptr2 = resptr3;
|
||||
resptr2->rn_status &= ~RESTRUE;
|
||||
resptr2->rn_status &= ~RES_TRUE;
|
||||
}
|
||||
ResDoneWithNode(resptr);
|
||||
if (resptr2 != NULL) ResDoneWithNode(resptr2);
|
||||
|
|
@ -542,8 +533,8 @@ ResTriangleCheck(resptr)
|
|||
/* is arbitrarily assigned to the location */
|
||||
/* occupied by the first node. */
|
||||
|
||||
InitializeNode(n3, resptr->rn_loc.p_x, resptr->rn_loc.p_y, TRIANGLE);
|
||||
n3->rn_status = FINISHED | RESTRUE | MARKED;
|
||||
InitializeResNode(n3, resptr->rn_loc.p_x, resptr->rn_loc.p_y, TRIANGLE);
|
||||
n3->rn_status = RES_FINISHED | RES_TRUE | RES_MARKED;
|
||||
|
||||
n3->rn_less = NULL;
|
||||
n3->rn_more = ResNodeList;
|
||||
|
|
@ -591,13 +582,13 @@ ResTriangleCheck(resptr)
|
|||
element->re_nextEl = n3->rn_re;
|
||||
element->re_thisEl = rr3;
|
||||
n3->rn_re = element;
|
||||
if ((n1->rn_status & RESTRUE) == RESTRUE)
|
||||
n1->rn_status &= ~RESTRUE;
|
||||
if ((n1->rn_status & RES_TRUE) == RES_TRUE)
|
||||
n1->rn_status &= ~RES_TRUE;
|
||||
else
|
||||
n1 = NULL;
|
||||
|
||||
if ((n2->rn_status & RESTRUE) == RESTRUE)
|
||||
n2->rn_status &= ~RESTRUE;
|
||||
if ((n2->rn_status & RES_TRUE) == RES_TRUE)
|
||||
n2->rn_status &= ~RES_TRUE;
|
||||
else
|
||||
n2 = NULL;
|
||||
|
||||
|
|
@ -648,15 +639,18 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
|||
return;
|
||||
}
|
||||
|
||||
/* don't want to merge away startpoint */
|
||||
/* don't want to merge away start or end points */
|
||||
if (node2->rn_why & RES_NODE_ORIGIN)
|
||||
node1->rn_why = RES_NODE_ORIGIN;
|
||||
|
||||
if (node2->rn_why & RES_NODE_SINK)
|
||||
node1->rn_why = RES_NODE_SINK;
|
||||
|
||||
/* set node resistance */
|
||||
if (node1->rn_noderes > node2->rn_noderes)
|
||||
{
|
||||
node1->rn_noderes = node2->rn_noderes;
|
||||
if ((node1->rn_status & FINISHED) != FINISHED)
|
||||
if ((node1->rn_status & RES_FINISHED) != RES_FINISHED)
|
||||
{
|
||||
ResRemoveFromQueue(node1, pendingList);
|
||||
ResAddToQueue(node1, pendingList);
|
||||
|
|
@ -665,37 +659,22 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
|||
node1->rn_float.rn_area += node2->rn_float.rn_area;
|
||||
|
||||
/* combine relevant flags */
|
||||
node1->rn_status |= (node2->rn_status & RN_MAXTDI);
|
||||
node1->rn_status |= (node2->rn_status & RES_MAXTDI);
|
||||
|
||||
/* merge device lists */
|
||||
workingDev = node2->rn_te;
|
||||
while (workingDev != NULL)
|
||||
{
|
||||
if (workingDev->te_thist->rd_status & RES_DEV_PLUG)
|
||||
{
|
||||
ResPlug *plug = (ResPlug *) workingDev->te_thist;
|
||||
if (plug->rpl_node == node2)
|
||||
plug->rpl_node = node1;
|
||||
else
|
||||
{
|
||||
TxError("Bad plug node: is (%d %d), should be (%d %d)\n",
|
||||
plug->rpl_node->rn_loc.p_x, plug->rpl_node->rn_loc.p_y,
|
||||
node2->rn_loc.p_x, node2->rn_loc.p_y);
|
||||
plug->rpl_node = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int j;
|
||||
int j;
|
||||
|
||||
for (j = 0; j != workingDev->te_thist->rd_nterms; j++)
|
||||
if (workingDev->te_thist->rd_terminals[j] == node2)
|
||||
workingDev->te_thist->rd_terminals[j] = node1;
|
||||
}
|
||||
tDev = workingDev;
|
||||
workingDev = workingDev->te_nextt;
|
||||
tDev->te_nextt = node1->rn_te;
|
||||
node1->rn_te = tDev;
|
||||
for (j = 0; j != workingDev->te_thist->rd_nterms; j++)
|
||||
if (workingDev->te_thist->rd_terminals[j] == node2)
|
||||
workingDev->te_thist->rd_terminals[j] = node1;
|
||||
|
||||
tDev = workingDev;
|
||||
workingDev = workingDev->te_nextt;
|
||||
tDev->te_nextt = node1->rn_te;
|
||||
node1->rn_te = tDev;
|
||||
}
|
||||
|
||||
/* append junction lists */
|
||||
|
|
@ -706,13 +685,13 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
|||
tJunc = workingJunc;
|
||||
for (i = 0; i < TILES_PER_JUNCTION; i++)
|
||||
{
|
||||
tileJunk *junk;
|
||||
resInfo *info;
|
||||
|
||||
tile = tJunc->je_thisj->rj_Tile[i];
|
||||
junk = (tileJunk *) TiGetClientPTR(tile);
|
||||
info = (resInfo *) TiGetClientPTR(tile);
|
||||
|
||||
if ((junk->tj_status & RES_TILE_DONE) == FALSE)
|
||||
ResFixBreakPoint(&junk->breakList, node2, node1);
|
||||
if ((info->ri_status & RES_TILE_DONE) == FALSE)
|
||||
ResFixBreakPoint(&info->breakList, node2, node1);
|
||||
}
|
||||
tJunc->je_thisj->rj_jnode = node1;
|
||||
workingJunc = workingJunc->je_nextj;
|
||||
|
|
@ -729,13 +708,13 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
|||
{
|
||||
if (workingCon->ce_thisc->cp_cnode[i] == node2)
|
||||
{
|
||||
tileJunk *junk;
|
||||
resInfo *info;
|
||||
|
||||
workingCon->ce_thisc->cp_cnode[i] = node1;
|
||||
tile =tCon->ce_thisc->cp_tile[i];
|
||||
junk = (tileJunk *) TiGetClientPTR(tile);
|
||||
if ((junk->tj_status & RES_TILE_DONE) == FALSE)
|
||||
ResFixBreakPoint(&junk->breakList, node2, node1);
|
||||
info = (resInfo *) TiGetClientPTR(tile);
|
||||
if ((info->ri_status & RES_TILE_DONE) == FALSE)
|
||||
ResFixBreakPoint(&info->breakList, node2, node1);
|
||||
}
|
||||
}
|
||||
workingCon = workingCon->ce_nextc;
|
||||
|
|
@ -749,11 +728,11 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
|||
else if ((node2->rn_name != NULL) && (node2->rn_name != node1->rn_name))
|
||||
{
|
||||
HashEntry *entry;
|
||||
ResSimNode *node;
|
||||
ResExtNode *node;
|
||||
|
||||
/* Check if node2 is a port */
|
||||
entry = HashFind(&ResNodeTable, node2->rn_name);
|
||||
node = (ResSimNode *)HashGetValue(entry);
|
||||
node = (ResExtNode *)HashGetValue(entry);
|
||||
if (node && (node->status & PORTNODE))
|
||||
node1->rn_name = node2->rn_name;
|
||||
}
|
||||
|
|
@ -775,7 +754,7 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
|||
tRes->re_nextEl = node1->rn_re;
|
||||
node1->rn_re = tRes;
|
||||
}
|
||||
if ((node2->rn_status & FINISHED) == FINISHED)
|
||||
if ((node2->rn_status & RES_FINISHED) == RES_FINISHED)
|
||||
ResRemoveFromQueue(node2, doneList);
|
||||
else
|
||||
ResRemoveFromQueue(node2, pendingList);
|
||||
|
|
@ -885,7 +864,7 @@ ResEliminateResistor(resistor, homelist)
|
|||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResCleanNode--removes the linked lists of junctions and contacts after
|
||||
* they are no longer needed. If the 'junk' option is used,
|
||||
* they are no longer needed. If the 'info' option is used,
|
||||
* the node is eradicated.
|
||||
*
|
||||
* Results:
|
||||
|
|
@ -897,9 +876,9 @@ ResEliminateResistor(resistor, homelist)
|
|||
*/
|
||||
|
||||
void
|
||||
ResCleanNode(resptr, junk, homelist1, homelist2)
|
||||
ResCleanNode(resptr, info, homelist1, homelist2)
|
||||
resNode *resptr;
|
||||
int junk;
|
||||
int info;
|
||||
resNode **homelist1;
|
||||
resNode **homelist2;
|
||||
{
|
||||
|
|
@ -922,7 +901,7 @@ ResCleanNode(resptr, junk, homelist1, homelist2)
|
|||
freeMagic((char *)jcell->je_thisj);
|
||||
freeMagic((char *)jcell);
|
||||
}
|
||||
if (junk == TRUE)
|
||||
if (info == TRUE)
|
||||
{
|
||||
if (resptr->rn_client != (ClientData)NULL)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "database/database.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "textio/textio.h"
|
||||
#include "extflat/extparse.h"
|
||||
#include "extract/extract.h"
|
||||
#include "extract/extractInt.h"
|
||||
#include "windows/windows.h"
|
||||
|
|
@ -32,9 +33,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#define MAXNAME 1000
|
||||
#define KV_TO_mV 1000000
|
||||
|
||||
extern ResSimNode *ResInitializeNode();
|
||||
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -57,7 +55,7 @@ ResPrintExtRes(outextfile, resistors, nodename)
|
|||
int nodenum=0;
|
||||
char newname[MAXNAME];
|
||||
HashEntry *entry;
|
||||
ResSimNode *node, *ResInitializeNode();
|
||||
ResExtNode *node;
|
||||
|
||||
for (; resistors != NULL; resistors = resistors->rr_nextResistor)
|
||||
{
|
||||
|
|
@ -72,7 +70,7 @@ ResPrintExtRes(outextfile, resistors, nodename)
|
|||
{
|
||||
(void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++);
|
||||
entry = HashFind(&ResNodeTable, newname);
|
||||
node = ResInitializeNode(entry);
|
||||
node = ResExtInitNode(entry);
|
||||
resistors->rr_connection1->rn_name = node->name;
|
||||
node->oldname = nodename;
|
||||
}
|
||||
|
|
@ -80,7 +78,7 @@ ResPrintExtRes(outextfile, resistors, nodename)
|
|||
{
|
||||
(void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++);
|
||||
entry = HashFind(&ResNodeTable, newname);
|
||||
node = ResInitializeNode(entry);
|
||||
node = ResExtInitNode(entry);
|
||||
resistors->rr_connection2->rn_name = node->name;
|
||||
node->oldname = nodename;
|
||||
}
|
||||
|
|
@ -175,13 +173,13 @@ ResPrintExtDev(outextfile, devices)
|
|||
fprintf(outextfile, " \"%s\" %d %s",
|
||||
devices->gate->name,
|
||||
devices->layout->rd_length * 2,
|
||||
devices->rs_gattr);
|
||||
(*devices->rs_gattr == '\0') ? "0" : devices->rs_gattr);
|
||||
|
||||
if (devices->source != NULL)
|
||||
fprintf(outextfile, " \"%s\" %d %s",
|
||||
devices->source->name,
|
||||
devices->layout->rd_width,
|
||||
devices->rs_sattr);
|
||||
(*devices->rs_sattr == '\0') ? "0" : devices->rs_sattr);
|
||||
|
||||
/* Don't write drain values for 2-terminal devices */
|
||||
if (devptr->exts_deviceSDCount > 1)
|
||||
|
|
@ -189,7 +187,7 @@ ResPrintExtDev(outextfile, devices)
|
|||
fprintf(outextfile, " \"%s\" %d %s",
|
||||
devices->drain->name,
|
||||
devices->layout->rd_width,
|
||||
devices->rs_dattr);
|
||||
(*devices->rs_dattr == '\0') ? "0" : devices->rs_dattr);
|
||||
|
||||
fprintf(outextfile, "\n");
|
||||
}
|
||||
|
|
@ -215,13 +213,13 @@ void
|
|||
ResPrintExtNode(outextfile, nodelist, node)
|
||||
FILE *outextfile;
|
||||
resNode *nodelist;
|
||||
ResSimNode *node;
|
||||
ResExtNode *node;
|
||||
{
|
||||
char *nodename = node->name;
|
||||
int nodenum = 0;
|
||||
char newname[MAXNAME+32], tmpname[MAXNAME], *cp;
|
||||
HashEntry *entry;
|
||||
ResSimNode *newnode, *ResInitializeNode();
|
||||
ResExtNode *newnode;
|
||||
bool DoKillNode = TRUE;
|
||||
bool NeedFix = FALSE;
|
||||
resNode *snode;
|
||||
|
|
@ -270,7 +268,7 @@ ResPrintExtNode(outextfile, nodelist, node)
|
|||
|
||||
(void)sprintf(newname, "%s%s%d", tmpname, ".n", nodenum++);
|
||||
entry = HashFind(&ResNodeTable, newname);
|
||||
newnode = ResInitializeNode(entry);
|
||||
newnode = ResExtInitNode(entry);
|
||||
snode->rn_name = newnode->name;
|
||||
newnode->oldname = nodename;
|
||||
}
|
||||
|
|
@ -290,6 +288,13 @@ ResPrintExtNode(outextfile, nodelist, node)
|
|||
|
||||
if (NeedFix)
|
||||
{
|
||||
if (nodelist == NULL)
|
||||
{
|
||||
TxError("Error: Orphaned node \"%s\" not output.\n",
|
||||
node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Patch up the output netlist for an orphaned node by
|
||||
* creating a zero-valued resistance between it and the
|
||||
* first subnode (arbitrary connection). Flag a warning.
|
||||
|
|
@ -316,16 +321,16 @@ ResPrintExtNode(outextfile, nodelist, node)
|
|||
*/
|
||||
|
||||
void
|
||||
ResPrintStats(goodies, name)
|
||||
ResGlobalParams *goodies;
|
||||
char *name;
|
||||
ResPrintStats(resisdata, name)
|
||||
ResisData *resisdata;
|
||||
char *name;
|
||||
{
|
||||
static int totalnets = 0, totalnodes = 0, totalresistors = 0;
|
||||
int nodes, resistors;
|
||||
resNode *node;
|
||||
resResistor *res;
|
||||
|
||||
if (goodies == NULL)
|
||||
if (resisdata == NULL)
|
||||
{
|
||||
TxError("nets:%d nodes:%d resistors:%d\n",
|
||||
totalnets, totalnodes, totalresistors);
|
||||
|
|
@ -411,16 +416,16 @@ ResPrintFHNodes(fp, nodelist, nodename, nidx, celldef)
|
|||
else
|
||||
{
|
||||
HashEntry *entry;
|
||||
ResSimNode *simnode;
|
||||
ResExtNode *extnode;
|
||||
|
||||
/* If we process another sim file node while doing this */
|
||||
/* one, mark it as status "REDUNDANT" so we don't duplicate */
|
||||
/* the entry. */
|
||||
|
||||
entry = HashFind(&ResNodeTable, nodeptr->rn_name);
|
||||
simnode = (ResSimNode *)HashGetValue(entry);
|
||||
if (simnode != NULL)
|
||||
simnode->status |= REDUNDANT;
|
||||
extnode = (ResExtNode *)HashGetValue(entry);
|
||||
if (extnode != NULL)
|
||||
extnode->status |= REDUNDANT;
|
||||
}
|
||||
resWriteNodeName(fp, nodeptr);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,684 @@
|
|||
|
||||
#ifndef lint
|
||||
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResReadExt.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResReadExt.c -- Routines to parse .ext files for information needed
|
||||
* by extresist.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/main.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "utils/geofast.h"
|
||||
#include "tiles/tile.h"
|
||||
#include "utils/hash.h"
|
||||
#include "database/database.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "textio/textio.h"
|
||||
#include "extract/extract.h"
|
||||
#include "extract/extractInt.h"
|
||||
#include "extflat/extflat.h"
|
||||
#include "extflat/extparse.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"
|
||||
|
||||
/* constants defining where various fields can be found in .ext files. */
|
||||
/* The value corresponds to the argument number on the list after */
|
||||
/* parsing by efReadLine(). */
|
||||
|
||||
#define FET_NAME 1
|
||||
#define FET_X 2
|
||||
#define FET_Y 3
|
||||
#define FET_AREA 4
|
||||
#define FET_PERIM 5
|
||||
#define FET_SUBS 6
|
||||
#define FET_GATE 7
|
||||
#define FET_GATE_ATTR 9
|
||||
#define FET_SOURCE 10
|
||||
#define FET_SOURCE_ATTR 12
|
||||
#define FET_DRAIN 13
|
||||
#define FET_DRAIN_ATTR 15
|
||||
|
||||
#define DEV_NAME 2
|
||||
#define DEV_X 3
|
||||
#define DEV_Y 4
|
||||
#define DEV_PARAM_START 7
|
||||
|
||||
#define NODES_NODENAME 1
|
||||
#define NODES_NODEX 4
|
||||
#define NODES_NODEY 5
|
||||
#define NODES_NODETYPE 6
|
||||
|
||||
#define COUPLETERMINAL1 1
|
||||
#define COUPLETERMINAL2 2
|
||||
#define COUPLEVALUE 3
|
||||
|
||||
#define RES_EXT_ATTR_NAME 1
|
||||
#define RES_EXT_ATTR_X 2
|
||||
#define RES_EXT_ATTR_Y 3
|
||||
#define RES_EXT_ATTR_TYPE 6
|
||||
#define RES_EXT_ATTR_TEXT 7
|
||||
|
||||
#define PORT_NAME 1
|
||||
#define PORT_LLX 3
|
||||
#define PORT_LLY 4
|
||||
#define PORT_URX 5
|
||||
#define PORT_URY 6
|
||||
#define PORT_TYPE 7
|
||||
|
||||
#define MAXDIGIT 20
|
||||
|
||||
ResExtNode *ResOriginalNodes; /*Linked List of Nodes */
|
||||
char RDEV_NOATTR[1] = {'0'};
|
||||
ResFixPoint *ResFixList;
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResReadExt--
|
||||
*
|
||||
* Results: returns 0 if ext file is correct, 1 if not.
|
||||
*
|
||||
* Side Effects:Reads in ExtTable and makes a hash table of nodes.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResReadExt(CellDef *def)
|
||||
{
|
||||
char *line = NULL, *argv[128];
|
||||
int result, locresult;
|
||||
int argc, n, size = 0;
|
||||
FILE *fp;
|
||||
CellDef *dbdef;
|
||||
ResExtNode *curnode;
|
||||
|
||||
/* Search for the .ext file in the same way that efReadDef() does. */
|
||||
|
||||
fp = ExtFileOpen(def, (char *)NULL, "r", (char **)NULL);
|
||||
if (fp == NULL)
|
||||
{
|
||||
TxError("Cannot open file %s%s\n", def->cd_name, ".ext");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read in the file. Makes use of various functions
|
||||
* from extflat, mostly in EFread.c.
|
||||
*/
|
||||
|
||||
EFSaveLocs = FALSE;
|
||||
efReadLineNum = 0;
|
||||
result = 0;
|
||||
|
||||
while ((argc = efReadLine(&line, &size, fp, argv)) >= 0)
|
||||
{
|
||||
n = LookupStruct(argv[0], (const LookupTable *)keyTable, sizeof keyTable[0]);
|
||||
if (n < 0)
|
||||
{
|
||||
efReadError("Unrecognized token \"%s\" (ignored)\n", argv[0]);
|
||||
continue;
|
||||
}
|
||||
if (argc < keyTable[n].k_mintokens)
|
||||
{
|
||||
efReadError("Not enough tokens for %s line\n", argv[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We don't care about most tokens, only DEVICE, NODE, PORT,
|
||||
* and SUBSTRATE; and MERGE is used to locate drive points.
|
||||
*/
|
||||
switch (keyTable[n].k_key)
|
||||
{
|
||||
case SCALE:
|
||||
/* NOTE: Currently the code assumes that the .ext
|
||||
* file is read back immediately and has the same
|
||||
* scale values currently in the extraction style.
|
||||
* However, this should be style-independent and
|
||||
* scale values should be read back and used.
|
||||
* (to be completed).
|
||||
*/
|
||||
break;
|
||||
case DEVICE:
|
||||
locresult = ResReadDevice(argc, argv);
|
||||
break;
|
||||
case FET:
|
||||
locresult = ResReadFET(argc, argv);
|
||||
break;
|
||||
case MERGE:
|
||||
/* To be completed */
|
||||
/* ResReadDrivePoint(argc, argv); */
|
||||
break;
|
||||
case NODE:
|
||||
case SUBSTRATE:
|
||||
curnode = ResReadNode(argc, argv);
|
||||
break;
|
||||
case PORT:
|
||||
locresult = ResReadPort(argc, argv);
|
||||
break;
|
||||
case ATTR:
|
||||
locresult = ResReadAttribute(curnode, argc, argv);
|
||||
break;
|
||||
case CAP:
|
||||
locresult = ResReadCapacitor(argc, argv);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (locresult == 1) result = 1;
|
||||
}
|
||||
fclose(fp);
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResReadNode-- Reads in a node statement, puts location and type of
|
||||
* node into a node structure.
|
||||
*
|
||||
* Results: Pointer to the node record if the node was read correctly,
|
||||
* NULL otherwise.
|
||||
*
|
||||
* Side Effects: see above
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
ResExtNode *
|
||||
ResReadNode(int argc, char *argv[])
|
||||
{
|
||||
HashEntry *entry;
|
||||
ResExtNode *node;
|
||||
|
||||
entry = HashFind(&ResNodeTable, argv[NODES_NODENAME]);
|
||||
node = ResExtInitNode(entry);
|
||||
|
||||
node->location.p_x = atoi(argv[NODES_NODEX]);
|
||||
node->location.p_y = atoi(argv[NODES_NODEY]);
|
||||
|
||||
/* If this node was previously read as a port, then don't change the
|
||||
* node type, which is tracking the type at the drivepoint.
|
||||
*/
|
||||
if (!(node->status & PORTNODE))
|
||||
{
|
||||
node->type = DBTechNameType(argv[NODES_NODETYPE]);
|
||||
}
|
||||
|
||||
if (node->type == -1)
|
||||
{
|
||||
TxError("Bad tile type name in .ext file for node %s\n", node->name);
|
||||
return NULL;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResReadPort-- Reads in a port statement from the .ext file and sets
|
||||
* node records accordingly to mark the node as a drivepoint.
|
||||
*
|
||||
* Results: 0 if successful and 1 otherwise.
|
||||
*
|
||||
* Side Effects: see above
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResReadPort(int argc,
|
||||
char *argv[])
|
||||
{
|
||||
HashEntry *entry;
|
||||
ResExtNode *node;
|
||||
|
||||
entry = HashFind(&ResNodeTable, argv[PORT_NAME]);
|
||||
node = ResExtInitNode(entry);
|
||||
|
||||
node->drivepoint.p_x = atoi(argv[PORT_LLX]);
|
||||
node->drivepoint.p_y = atoi(argv[PORT_LLY]);
|
||||
node->status |= FORCE;
|
||||
/* To do: Check for multiple ports on a net; each port needs its
|
||||
* own drivepoint.
|
||||
*/
|
||||
node->status |= DRIVELOC | PORTNODE;
|
||||
node->rs_bbox.r_ll = node->drivepoint;
|
||||
node->rs_bbox.r_ur.p_x = atoi(argv[PORT_URX]);
|
||||
node->rs_bbox.r_ur.p_y = atoi(argv[PORT_URY]);
|
||||
node->rs_ttype = DBTechNoisyNameType(argv[PORT_TYPE]);
|
||||
node->type = node->rs_ttype;
|
||||
|
||||
if (node->type == -1)
|
||||
{
|
||||
TxError("Bad tile type name in .ext file for node %s\n", node->name);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResNodeAddDevice --
|
||||
*
|
||||
* Given a device and a node which connects to one of its terminals,
|
||||
* add the device to the node's device list. Device type is one
|
||||
* of the indexes defined by GATE, SOURCE, or DRAIN (to do: generalize
|
||||
* this).
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Allocates memory for a devPtr, adds to the node's firstDev linked
|
||||
* list.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
ResNodeAddDevice(ResExtNode *node,
|
||||
RDev *device,
|
||||
int termtype)
|
||||
{
|
||||
devPtr *tptr;
|
||||
|
||||
tptr = (devPtr *)mallocMagic((unsigned)(sizeof(devPtr)));
|
||||
tptr->thisDev = device;
|
||||
tptr->nextDev = node->firstDev;
|
||||
node->firstDev = tptr;
|
||||
tptr->terminal = termtype;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResReadDevice--
|
||||
*
|
||||
* Process a "device" line from a ext file.
|
||||
*
|
||||
* Results: returns 0 if line was added correctly.
|
||||
*
|
||||
* Side Effects: Allocates devicesl
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResReadDevice(int argc,
|
||||
char *argv[])
|
||||
{
|
||||
RDev *device;
|
||||
int rvalue, i, j, k;
|
||||
ExtDevice *devptr;
|
||||
TileType ttype;
|
||||
HashEntry *entry;
|
||||
ResExtNode *node;
|
||||
ResValue rpersquare;
|
||||
float wval;
|
||||
|
||||
device = (RDev *)mallocMagic((unsigned)(sizeof(RDev)));
|
||||
|
||||
device->status = FALSE;
|
||||
device->nextDev = ResRDevList;
|
||||
|
||||
/* Find the device definition record corresponding to the device name */
|
||||
devptr = (ExtDevice *)NULL;
|
||||
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
|
||||
{
|
||||
for (devptr = ExtCurStyle->exts_device[ttype]; devptr;
|
||||
devptr = devptr->exts_next)
|
||||
if (!strcmp(devptr->exts_deviceName, argv[DEV_NAME])) break;
|
||||
if (devptr != NULL) break;
|
||||
}
|
||||
|
||||
device->location.p_x = atoi(argv[DEV_X]);
|
||||
device->location.p_y = atoi(argv[DEV_Y]);
|
||||
|
||||
device->rs_gattr = RDEV_NOATTR;
|
||||
device->rs_sattr = RDEV_NOATTR;
|
||||
device->rs_dattr = RDEV_NOATTR;
|
||||
device->rs_devptr = devptr;
|
||||
|
||||
device->source = (ResExtNode *)NULL;
|
||||
device->drain = (ResExtNode *)NULL;
|
||||
device->subs = (ResExtNode *)NULL;
|
||||
|
||||
entry = HashLookOnly(&devptr->exts_deviceResist, "linear");
|
||||
if (entry != NULL)
|
||||
rpersquare = (ResValue)(spointertype)HashGetValue(entry);
|
||||
else
|
||||
rpersquare = (ResValue)10000.0; /* Default to a sane value */
|
||||
|
||||
/* For devices, the device width is in the parameter list */
|
||||
wval = 0.0;
|
||||
for (i = DEV_Y; i < argc; i++)
|
||||
{
|
||||
char *eptr;
|
||||
if ((eptr = strchr(argv[i], '=')) != NULL)
|
||||
{
|
||||
if (*argv[i] == 'w')
|
||||
sscanf(eptr + 1, "%f", &wval);
|
||||
}
|
||||
else if (!StrIsInt(argv[i]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == argc)
|
||||
{
|
||||
TxError("Bad device %s: Too few arguments in .ext file\n",
|
||||
argv[DEV_NAME]);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
device->resistance = wval * rpersquare; /* Channel resistance */
|
||||
|
||||
/* Find and record the device terminal nodes */
|
||||
/* Note that this only records up to two terminals matching FET
|
||||
* source and drain; it needs to be expanded to include an
|
||||
* arbitrary number of terminals.
|
||||
*/
|
||||
|
||||
if (strcmp(argv[i], "None"))
|
||||
{
|
||||
entry = HashFind(&ResNodeTable, argv[i]);
|
||||
device->subs = (ResExtNode *)HashGetValue(entry);
|
||||
ResNodeAddDevice(device->subs, device, SUBS);
|
||||
}
|
||||
i++;
|
||||
entry = HashFind(&ResNodeTable, argv[i]);
|
||||
device->gate = (ResExtNode *)HashGetValue(entry);
|
||||
device->rs_gattr = StrDup((char **)NULL, argv[i + 2]);
|
||||
ResNodeAddDevice(device->gate, device, GATE);
|
||||
i += 3;
|
||||
|
||||
if (i < argc - 2)
|
||||
{
|
||||
entry = HashFind(&ResNodeTable, argv[i]);
|
||||
device->source = (ResExtNode *)HashGetValue(entry);
|
||||
device->rs_sattr = StrDup((char **)NULL, argv[i + 2]);
|
||||
ResNodeAddDevice(device->source, device, SOURCE);
|
||||
i += 3;
|
||||
}
|
||||
|
||||
if (i < argc - 2)
|
||||
{
|
||||
entry = HashFind(&ResNodeTable, argv[i]);
|
||||
device->drain = (ResExtNode *)HashGetValue(entry);
|
||||
device->rs_dattr = StrDup((char **)NULL, argv[i + 2]);
|
||||
ResNodeAddDevice(device->drain, device, DRAIN);
|
||||
i += 3;
|
||||
}
|
||||
if (i < argc - 2)
|
||||
{
|
||||
TxError("Warning: Device %s has more than 4 ports (not handled).\n",
|
||||
argv[DEV_NAME]);
|
||||
}
|
||||
|
||||
device->rs_ttype = extGetDevType(devptr->exts_deviceName);
|
||||
|
||||
ResRDevList = device;
|
||||
device->layout = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResReadFET-- Processes a "fet" line from a ext file.
|
||||
*
|
||||
* Results: returns 0 if line was added correctly.
|
||||
*
|
||||
* Side Effects: Allocates devices.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResReadFET(int argc,
|
||||
char *argv[])
|
||||
{
|
||||
RDev *device;
|
||||
int rvalue, i, j, k;
|
||||
ExtDevice *devptr;
|
||||
TileType ttype;
|
||||
HashEntry *entry;
|
||||
ResExtNode *node;
|
||||
ResValue rpersquare;
|
||||
float area, perim, wval, lval;
|
||||
|
||||
device = (RDev *)mallocMagic((unsigned)(sizeof(RDev)));
|
||||
|
||||
device->status = FALSE;
|
||||
device->nextDev = ResRDevList;
|
||||
|
||||
/* Find the device definition record corresponding to the device name */
|
||||
devptr = (ExtDevice *)NULL;
|
||||
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
|
||||
{
|
||||
for (devptr = ExtCurStyle->exts_device[ttype]; devptr;
|
||||
devptr = devptr->exts_next)
|
||||
if (!strcmp(devptr->exts_deviceName, argv[FET_NAME])) break;
|
||||
if (devptr != NULL) break;
|
||||
}
|
||||
|
||||
device->location.p_x = atoi(argv[FET_X]);
|
||||
device->location.p_y = atoi(argv[FET_Y]);
|
||||
|
||||
device->rs_gattr = RDEV_NOATTR;
|
||||
device->rs_sattr = RDEV_NOATTR;
|
||||
device->rs_dattr = RDEV_NOATTR;
|
||||
device->rs_devptr = devptr;
|
||||
|
||||
entry = HashLookOnly(&devptr->exts_deviceResist, "linear");
|
||||
if (entry != NULL)
|
||||
rpersquare = (ResValue)(spointertype)HashGetValue(entry);
|
||||
else
|
||||
rpersquare = (ResValue)10000.0; /* Default to a sane value */
|
||||
|
||||
/* For old-style FETs, the width is determined from area and perimeter */
|
||||
area = MagAtof(argv[FET_AREA]);
|
||||
perim = MagAtof(argv[FET_PERIM]);
|
||||
lval = 0.5 * (perim + sqrt(perim * perim - 4 * area));
|
||||
wval = area / lval;
|
||||
|
||||
device->resistance = wval * rpersquare; /* Channel resistance */
|
||||
|
||||
/* Find and record the FET terminal nodes */
|
||||
|
||||
entry = HashFind(&ResNodeTable, argv[FET_GATE]);
|
||||
device->gate = (ResExtNode *)HashGetValue(entry);
|
||||
|
||||
entry = HashFind(&ResNodeTable, argv[FET_SOURCE]);
|
||||
device->source = (ResExtNode *)HashGetValue(entry);
|
||||
|
||||
entry = HashFind(&ResNodeTable, argv[FET_DRAIN]);
|
||||
device->drain = (ResExtNode *)HashGetValue(entry);
|
||||
|
||||
entry = HashFind(&ResNodeTable, argv[FET_SUBS]);
|
||||
device->subs = (ResExtNode *)HashGetValue(entry);
|
||||
|
||||
device->rs_ttype = extGetDevType(devptr->exts_deviceName);
|
||||
|
||||
/* Copy attributes verbatim */
|
||||
device->rs_gattr = StrDup((char **)NULL, argv[FET_GATE_ATTR]);
|
||||
device->rs_sattr = StrDup((char **)NULL, argv[FET_SOURCE_ATTR]);
|
||||
device->rs_dattr = StrDup((char **)NULL, argv[FET_DRAIN_ATTR]);
|
||||
|
||||
ResRDevList = device;
|
||||
device->layout = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResReadCapacitor-- Adds the capacitance from a C line to the appropriate
|
||||
* node. Coupling capacitors are added twice, moving the capacitance
|
||||
* to the substrate.
|
||||
*
|
||||
* Results:
|
||||
* Always return 0
|
||||
*
|
||||
* Side Effects: modifies capacitance field of ResExtNode.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResReadCapacitor(int argc,
|
||||
char *argv[])
|
||||
{
|
||||
HashEntry *entry1, *entry2;
|
||||
ResExtNode *node1, *node2;
|
||||
|
||||
entry1 = HashFind(&ResNodeTable, argv[COUPLETERMINAL1]);
|
||||
node1 = ResExtInitNode(entry1);
|
||||
|
||||
if (ResOptionsFlags & ResOpt_Signal)
|
||||
{
|
||||
node1->capacitance += MagAtof(argv[COUPLEVALUE]);
|
||||
entry2 = HashFind(&ResNodeTable, argv[COUPLETERMINAL2]);
|
||||
node2 = ResExtInitNode(entry2);
|
||||
node2->capacitance += MagAtof(argv[COUPLEVALUE]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
entry2 = HashFind(&ResNodeTable, argv[COUPLETERMINAL2]);
|
||||
node2 = ResExtInitNode(entry2);
|
||||
|
||||
node1->cap_couple += MagAtof(argv[COUPLEVALUE]);
|
||||
node2->cap_couple += MagAtof(argv[COUPLEVALUE]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResReadAttribute--checks to see if a node attribute is a resistance
|
||||
* attribute. If it is, add it to the correct node's status flag.
|
||||
* Only works with 5.0 1/line attributes
|
||||
*
|
||||
* Results:
|
||||
* Return 0 to keep search going, 1 to abort
|
||||
*
|
||||
* Side Effects: modifies resistance field of ResExtNode
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResReadAttribute(ResExtNode *node,
|
||||
int argc,
|
||||
char *argv[])
|
||||
{
|
||||
char *aname, *avalue;
|
||||
char digit[MAXDIGIT];
|
||||
int i;
|
||||
static int notwarned = TRUE;
|
||||
|
||||
aname = argv[RES_EXT_ATTR_NAME];
|
||||
avalue = argv[RES_EXT_ATTR_TEXT];
|
||||
|
||||
if (strncmp(avalue, "res:skip", 8) == 0)
|
||||
{
|
||||
if (node->status & FORCE)
|
||||
{
|
||||
TxError("Warning: Node %s is both forced and skipped\n", aname);
|
||||
}
|
||||
else
|
||||
{
|
||||
node->status |= SKIP;
|
||||
}
|
||||
}
|
||||
else if (strncmp(avalue, "res:force", 9) == 0)
|
||||
{
|
||||
if (node->status & SKIP)
|
||||
TxError("Warning: Node %s is both skipped and forced \n", aname);
|
||||
else
|
||||
node->status |= FORCE;
|
||||
}
|
||||
else if (strncmp(avalue, "res:min=", 8) == 0)
|
||||
{
|
||||
node->status |= MINSIZE;
|
||||
for (i = 0, avalue += 8; *avalue != '\0'; avalue++)
|
||||
{
|
||||
digit[i++] = *avalue;
|
||||
}
|
||||
digit[i++] = '\0';
|
||||
node->minsizeres = MagAtof(digit);
|
||||
}
|
||||
else if (strncmp(avalue, "res:drive", 9) == 0 &&
|
||||
(ResOptionsFlags & ResOpt_Signal))
|
||||
{
|
||||
node->drivepoint.p_x = atoi(argv[RES_EXT_ATTR_X]);
|
||||
node->drivepoint.p_y = atoi(argv[RES_EXT_ATTR_Y]);
|
||||
node->rs_ttype = DBTechNoisyNameType(argv[RES_EXT_ATTR_TYPE]);
|
||||
node->status |= DRIVELOC;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResExtInitNode --
|
||||
* Gets the node corresponding to a given hash table entry. If no
|
||||
* such node exists, one is created.
|
||||
*
|
||||
* Results: Returns ResExtNode corresponding to entry.
|
||||
*
|
||||
* Side Effects: May allocate a new ResExtNode.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
ResExtNode *
|
||||
ResExtInitNode(entry)
|
||||
HashEntry *entry;
|
||||
{
|
||||
ResExtNode *node;
|
||||
|
||||
if ((node = (ResExtNode *) HashGetValue(entry)) == NULL)
|
||||
{
|
||||
node = (ResExtNode *)mallocMagic((unsigned)(sizeof(ResExtNode)));
|
||||
HashSetValue(entry, (char *) node);
|
||||
node->nextnode = ResOriginalNodes;
|
||||
ResOriginalNodes = node;
|
||||
node->status = FALSE;
|
||||
node->forward = (ResExtNode *) NULL;
|
||||
node->capacitance = 0;
|
||||
node->cap_couple = 0;
|
||||
node->resistance = 0;
|
||||
node->type = 0;
|
||||
node->firstDev = NULL;
|
||||
node->name = entry->h_key.h_name;
|
||||
node->oldname = NULL;
|
||||
node->drivepoint.p_x = INFINITY;
|
||||
node->drivepoint.p_y = INFINITY;
|
||||
node->location.p_x = INFINITY;
|
||||
node->location.p_y = INFINITY;
|
||||
}
|
||||
while (node->status & FORWARD)
|
||||
{
|
||||
node = node->forward;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
1095
resis/ResReadSim.c
1095
resis/ResReadSim.c
File diff suppressed because it is too large
Load Diff
872
resis/ResRex.c
872
resis/ResRex.c
File diff suppressed because it is too large
Load Diff
|
|
@ -32,7 +32,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/stack.h"
|
||||
#include "utils/tech.h"
|
||||
#include "textio/txcommands.h"
|
||||
#include "resis/resis.h"
|
||||
#include "resis/resis.h"
|
||||
|
||||
#define MILLIOHMSPEROHM 1000
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
|
|||
|
||||
if (*nodelist == NULL) return;
|
||||
node = *nodelist;
|
||||
node->rn_status |= MARKED | FINISHED;
|
||||
node->rn_status |= RES_MARKED | RES_FINISHED;
|
||||
*nodelist = node->rn_more;
|
||||
if (node->rn_more != NULL)
|
||||
node->rn_more->rn_less = (resNode *) NULL;
|
||||
|
|
@ -138,7 +138,8 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
|
|||
* more than 1, delete the current resistor to break the deadlock.
|
||||
*/
|
||||
|
||||
if (numreceive == 0 && numdrive == 1 && node->rn_why != RES_NODE_ORIGIN)
|
||||
if (numreceive == 0 && numdrive == 1 &&
|
||||
!(node->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK)))
|
||||
{
|
||||
resistor1->rr_status |= RES_DEADEND;
|
||||
if (resistor1->rr_value < tolerance)
|
||||
|
|
@ -155,8 +156,8 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
|
|||
{
|
||||
if (resisptr->re_thisEl->rr_connection1 == otherNode)
|
||||
{
|
||||
if ((resisptr->re_thisEl->rr_connection2->rn_status & MARKED)
|
||||
!= MARKED)
|
||||
if ((resisptr->re_thisEl->rr_connection2->rn_status & RES_MARKED)
|
||||
!= RES_MARKED)
|
||||
{
|
||||
PendingReceivers++;
|
||||
}
|
||||
|
|
@ -180,9 +181,9 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
|
|||
(UnMarkedReceivers == 0 && MarkedReceivers > 1 &&
|
||||
resistor2 == resistor1 && PendingReceivers == 0))
|
||||
{
|
||||
if (otherNode->rn_status & MARKED)
|
||||
if (otherNode->rn_status & RES_MARKED)
|
||||
{
|
||||
otherNode->rn_status &= ~MARKED;
|
||||
otherNode->rn_status &= ~RES_MARKED;
|
||||
ResRemoveFromQueue(otherNode, biglist);
|
||||
otherNode->rn_less = NULL;
|
||||
otherNode->rn_more = *nodelist;
|
||||
|
|
@ -208,9 +209,9 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
|
|||
ResDeleteResPointer(resistor1->rr_connection2, resistor1);
|
||||
ResEliminateResistor(resistor1, reslist);
|
||||
ResMergeNodes(otherNode, node, nodelist, biglist);
|
||||
if (otherNode->rn_status & MARKED)
|
||||
if (otherNode->rn_status & RES_MARKED)
|
||||
{
|
||||
otherNode->rn_status &= ~MARKED;
|
||||
otherNode->rn_status &= ~RES_MARKED;
|
||||
ResRemoveFromQueue(otherNode, biglist);
|
||||
otherNode->rn_less= NULL;
|
||||
otherNode->rn_more = *nodelist;
|
||||
|
|
@ -287,12 +288,12 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
|
|||
resisptr->re_nextEl = node2->rn_re;
|
||||
node2->rn_re = resisptr;
|
||||
ResEliminateResistor(resistor2, reslist);
|
||||
otherNode->rn_status |= (node->rn_status & RN_MAXTDI);
|
||||
otherNode->rn_status |= (node->rn_status & RES_MAXTDI);
|
||||
ResCleanNode(node, TRUE, biglist, nodelist);
|
||||
node1->rn_status &= ~RES_DONE_ONCE;
|
||||
if (node1->rn_status & MARKED)
|
||||
if (node1->rn_status & RES_MARKED)
|
||||
{
|
||||
node1->rn_status &= ~MARKED;
|
||||
node1->rn_status &= ~RES_MARKED;
|
||||
ResRemoveFromQueue(node1, biglist);
|
||||
node1->rn_less = NULL;
|
||||
node1->rn_more = *nodelist;
|
||||
|
|
@ -301,9 +302,9 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
|
|||
*nodelist = node1;
|
||||
}
|
||||
node2->rn_status &= ~RES_DONE_ONCE;
|
||||
if (node2->rn_status & MARKED)
|
||||
if (node2->rn_status & RES_MARKED)
|
||||
{
|
||||
node2->rn_status &= ~MARKED;
|
||||
node2->rn_status &= ~RES_MARKED;
|
||||
ResRemoveFromQueue(node2, biglist);
|
||||
node2->rn_less = NULL;
|
||||
node2->rn_more = *nodelist;
|
||||
|
|
@ -334,7 +335,7 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
|
|||
if (resisptr->re_thisEl->rr_status & RES_DONE_ONCE)
|
||||
continue;
|
||||
|
||||
if (resisptr->re_thisEl->rr_connection2->rn_status & MARKED)
|
||||
if (resisptr->re_thisEl->rr_connection2->rn_status & RES_MARKED)
|
||||
{
|
||||
/*
|
||||
* Mark big resistors so we only process them
|
||||
|
|
@ -343,7 +344,7 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
|
|||
if (resisptr->re_thisEl->rr_value > tolerance)
|
||||
resisptr->re_thisEl->rr_status |= RES_DONE_ONCE;
|
||||
|
||||
resisptr->re_thisEl->rr_connection2->rn_status &= ~MARKED;
|
||||
resisptr->re_thisEl->rr_connection2->rn_status &= ~RES_MARKED;
|
||||
ResRemoveFromQueue(resisptr->re_thisEl->rr_connection2, biglist);
|
||||
resisptr->re_thisEl->rr_connection2->rn_less= NULL;
|
||||
resisptr->re_thisEl->rr_connection2->rn_more = *nodelist;
|
||||
|
|
@ -383,27 +384,17 @@ ResMoveDevices(node1, node2)
|
|||
device = devptr->te_thist;
|
||||
oldptr = devptr;
|
||||
devptr = devptr->te_nextt;
|
||||
if (device->rd_status & RES_DEV_PLUG)
|
||||
{
|
||||
if (((ResPlug *)(device))->rpl_node == node1)
|
||||
((ResPlug *)(device))->rpl_node = node2;
|
||||
else
|
||||
TxError("Bad node connection in plug\n");
|
||||
}
|
||||
if (device->rd_fet_gate == node1)
|
||||
device->rd_fet_gate = node2;
|
||||
else if (device->rd_fet_subs == node1)
|
||||
device->rd_fet_subs = node2;
|
||||
else if (device->rd_fet_source == node1)
|
||||
device->rd_fet_source = node2;
|
||||
else if (device->rd_fet_drain == node1)
|
||||
device->rd_fet_drain = node2;
|
||||
else
|
||||
{
|
||||
if (device->rd_fet_gate == node1)
|
||||
device->rd_fet_gate = node2;
|
||||
else if (device->rd_fet_subs == node1)
|
||||
device->rd_fet_subs = node2;
|
||||
else if (device->rd_fet_source == node1)
|
||||
device->rd_fet_source = node2;
|
||||
else if (device->rd_fet_drain == node1)
|
||||
device->rd_fet_drain = node2;
|
||||
else
|
||||
TxError("Missing Device connection in squish routines"
|
||||
TxError("Missing Device connection in squish routines"
|
||||
" at %d, %d\n", node1->rn_loc.p_x, node1->rn_loc.p_y);
|
||||
}
|
||||
oldptr->te_nextt = node2->rn_te;
|
||||
node2->rn_te = oldptr;
|
||||
}
|
||||
|
|
@ -537,7 +528,7 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
|
|||
|
||||
ResEliminateResistor(current, reslist);
|
||||
ResAddResistorToList(working, reslist);
|
||||
if (node2->rn_why & RES_NODE_ORIGIN)
|
||||
if (node2->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK))
|
||||
{
|
||||
ResMergeNodes(node2, node1, pendingList, biglist);
|
||||
node1 = node2;
|
||||
|
|
@ -551,7 +542,7 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
|
|||
*/
|
||||
ResRemoveFromQueue(node1, biglist);
|
||||
ResAddToQueue(node1, pendingList);
|
||||
node1->rn_status &= ~(RES_DONE_ONCE | FINISHED);
|
||||
node1->rn_status &= ~(RES_DONE_ONCE | RES_FINISHED);
|
||||
ResDoneWithNode(node1);
|
||||
while (*pendingList != NULL)
|
||||
ResSimplifyNet(pendingList, biglist, reslist, tolerance);
|
||||
|
|
@ -650,7 +641,7 @@ ResDistributeCapacitance(nodelist, totalcap)
|
|||
TxError("Error: Node with no area.\n");
|
||||
return;
|
||||
}
|
||||
capperarea = FEMTOTOATTO * totalcap / totalarea;
|
||||
capperarea = totalcap / totalarea;
|
||||
|
||||
for (workingNode = nodelist; workingNode != NULL; workingNode = workingNode->rn_more)
|
||||
workingNode->rn_float.rn_area *= capperarea;
|
||||
|
|
@ -852,24 +843,26 @@ ResPruneTree(node, minTdi, nodelist1, nodelist2, resistorlist)
|
|||
*/
|
||||
|
||||
int
|
||||
ResDoSimplify(tolerance, rctol, goodies)
|
||||
float tolerance;
|
||||
float rctol;
|
||||
ResGlobalParams *goodies;
|
||||
ResDoSimplify(tolerance,resisdata)
|
||||
float tolerance;
|
||||
ResisData *resisdata;
|
||||
|
||||
{
|
||||
resNode *node, *slownode;
|
||||
float bigres = 0;
|
||||
float millitolerance;
|
||||
float totalcap;
|
||||
float rctol;
|
||||
resResistor *res;
|
||||
|
||||
ResSetPathRes();
|
||||
rctol = resisdata->tdiTolerance;
|
||||
ResSetPathRes(resisdata);
|
||||
|
||||
for (node = ResNodeList; node != NULL; node = node->rn_more)
|
||||
bigres = MAX(bigres, node->rn_noderes);
|
||||
|
||||
bigres /= OHMSTOMILLIOHMS; /* convert from milliohms to ohms */
|
||||
goodies->rg_maxres = bigres;
|
||||
resisdata->rg_maxres = bigres;
|
||||
|
||||
#ifdef PARANOID
|
||||
ResSanityChecks("ExtractSingleNet", ResResList, ResNodeList, ResDevList);
|
||||
|
|
@ -880,7 +873,7 @@ ResDoSimplify(tolerance, rctol, goodies)
|
|||
/* we're calculating lumped values so that the capacitance */
|
||||
/* values get calculated correctly. */
|
||||
|
||||
(void) ResDistributeCapacitance(ResNodeList, goodies->rg_nodecap);
|
||||
(void) ResDistributeCapacitance(ResNodeList, resisdata->rg_nodecap);
|
||||
|
||||
if (((tolerance > bigres) || ((ResOptionsFlags & ResOpt_Simplify) == 0)) &&
|
||||
((ResOptionsFlags & ResOpt_DoLumpFile) == 0))
|
||||
|
|
@ -905,43 +898,48 @@ ResDoSimplify(tolerance, rctol, goodies)
|
|||
------*/
|
||||
}
|
||||
|
||||
if (ResOptionsFlags & ResOpt_Tdi)
|
||||
if (ResNodeAtOrigin == NULL)
|
||||
{
|
||||
if (goodies->rg_nodecap != -1 &&
|
||||
(totalcap = ResCalculateChildCapacitance(ResOriginNode)) != -1)
|
||||
TxError("Error: Network simplification: Failed to to get origin node.\n");
|
||||
resisdata->rg_Tdi = 0;
|
||||
}
|
||||
else if (ResOptionsFlags & ResOpt_Tdi)
|
||||
{
|
||||
if ((resisdata->rg_nodecap != -1) &&
|
||||
(totalcap = ResCalculateChildCapacitance(ResNodeAtOrigin)) != -1)
|
||||
{
|
||||
RCDelayStuff *rc = (RCDelayStuff *) ResNodeList->rn_client;
|
||||
RCDelayStuff *rc = (RCDelayStuff *) ResNodeList->rn_client;
|
||||
|
||||
goodies->rg_nodecap = totalcap;
|
||||
ResCalculateTDi(ResOriginNode, (resResistor *)NULL,
|
||||
goodies->rg_bigdevres);
|
||||
resisdata->rg_nodecap = totalcap;
|
||||
ResCalculateTDi(ResNodeAtOrigin, (resResistor *)NULL,
|
||||
resisdata->rg_bigdevres);
|
||||
if (rc != (RCDelayStuff *)NULL)
|
||||
goodies->rg_Tdi = rc->rc_Tdi;
|
||||
resisdata->rg_Tdi = rc->rc_Tdi;
|
||||
else
|
||||
goodies->rg_Tdi = 0;
|
||||
resisdata->rg_Tdi = 0;
|
||||
|
||||
slownode = ResNodeList;
|
||||
for (node = ResNodeList; node != NULL; node = node->rn_more)
|
||||
{
|
||||
rc = (RCDelayStuff *)node->rn_client;
|
||||
if ((rc != NULL) && (goodies->rg_Tdi < rc->rc_Tdi))
|
||||
if ((rc != NULL) && (resisdata->rg_Tdi < rc->rc_Tdi))
|
||||
{
|
||||
slownode = node;
|
||||
goodies->rg_Tdi = rc->rc_Tdi;
|
||||
resisdata->rg_Tdi = rc->rc_Tdi;
|
||||
}
|
||||
}
|
||||
slownode->rn_status |= RN_MAXTDI;
|
||||
slownode->rn_status |= RES_MAXTDI;
|
||||
}
|
||||
else
|
||||
goodies->rg_Tdi = -1;
|
||||
resisdata->rg_Tdi = -1;
|
||||
}
|
||||
else
|
||||
goodies->rg_Tdi = 0;
|
||||
resisdata->rg_Tdi = 0;
|
||||
|
||||
if ((rctol+1) * goodies->rg_bigdevres * goodies->rg_nodecap >
|
||||
rctol * goodies->rg_Tdi &&
|
||||
if ((rctol+1) * resisdata->rg_bigdevres * resisdata->rg_nodecap >
|
||||
rctol * resisdata->rg_Tdi &&
|
||||
(ResOptionsFlags & ResOpt_Tdi) &&
|
||||
goodies->rg_Tdi != -1)
|
||||
resisdata->rg_Tdi != -1)
|
||||
return 0;
|
||||
|
||||
/* Simplify network; resistors are still in milliohms, so use
|
||||
|
|
@ -960,35 +958,35 @@ ResDoSimplify(tolerance, rctol, goodies)
|
|||
for (node = ResNodeList; node != NULL; node = node->rn_more)
|
||||
{
|
||||
if (node->rn_noderes == 0)
|
||||
ResOriginNode = node;
|
||||
ResNodeAtOrigin = node;
|
||||
|
||||
node->rn_status |= FINISHED;
|
||||
node->rn_status |= RES_FINISHED;
|
||||
}
|
||||
if (ResOriginNode != NULL)
|
||||
if (ResNodeAtOrigin != NULL)
|
||||
{
|
||||
/* if Tdi is enabled, prune all branches whose end nodes */
|
||||
/* have time constants less than the tolerance. */
|
||||
|
||||
if ((ResOptionsFlags & ResOpt_Tdi) &&
|
||||
goodies->rg_Tdi != -1 &&
|
||||
resisdata->rg_Tdi != -1 &&
|
||||
rctol != 0)
|
||||
{
|
||||
ResPruneTree(ResOriginNode, (rctol + 1) *
|
||||
goodies->rg_bigdevres * goodies->rg_nodecap / rctol,
|
||||
ResPruneTree(ResNodeAtOrigin, (rctol + 1) *
|
||||
resisdata->rg_bigdevres * resisdata->rg_nodecap / rctol,
|
||||
&ResNodeList, &ResNodeQueue, &ResResList);
|
||||
}
|
||||
ResOriginNode->rn_status &= ~MARKED;
|
||||
if (ResOriginNode->rn_less == NULL)
|
||||
ResNodeList = ResOriginNode->rn_more;
|
||||
ResNodeAtOrigin->rn_status &= ~RES_MARKED;
|
||||
if (ResNodeAtOrigin->rn_less == NULL)
|
||||
ResNodeList = ResNodeAtOrigin->rn_more;
|
||||
else
|
||||
ResOriginNode->rn_less->rn_more = ResOriginNode->rn_more;
|
||||
ResNodeAtOrigin->rn_less->rn_more = ResNodeAtOrigin->rn_more;
|
||||
|
||||
if (ResOriginNode->rn_more != NULL)
|
||||
ResOriginNode->rn_more->rn_less = ResOriginNode->rn_less;
|
||||
if (ResNodeAtOrigin->rn_more != NULL)
|
||||
ResNodeAtOrigin->rn_more->rn_less = ResNodeAtOrigin->rn_less;
|
||||
|
||||
ResOriginNode->rn_more = NULL;
|
||||
ResOriginNode->rn_less = NULL;
|
||||
ResNodeQueue = ResOriginNode;
|
||||
ResNodeAtOrigin->rn_more = NULL;
|
||||
ResNodeAtOrigin->rn_less = NULL;
|
||||
ResNodeQueue = ResNodeAtOrigin;
|
||||
while (ResNodeQueue != NULL)
|
||||
ResSimplifyNet(&ResNodeQueue, &ResNodeList, &ResResList, millitolerance);
|
||||
|
||||
|
|
@ -1009,7 +1007,7 @@ ResDoSimplify(tolerance, rctol, goodies)
|
|||
*/
|
||||
|
||||
void
|
||||
ResSetPathRes()
|
||||
ResSetPathRes(ResisData *resisdata)
|
||||
{
|
||||
HeapEntry he;
|
||||
resNode *node;
|
||||
|
|
@ -1025,24 +1023,32 @@ ResSetPathRes()
|
|||
{
|
||||
if (node->rn_noderes == 0)
|
||||
{
|
||||
ResOriginNode = node;
|
||||
node->rn_status |= FINISHED;
|
||||
ResNodeAtOrigin = node;
|
||||
node->rn_status |= RES_FINISHED;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->rn_noderes = RES_INFINITY;
|
||||
node->rn_status &= ~FINISHED;
|
||||
node->rn_status &= ~RES_FINISHED;
|
||||
}
|
||||
}
|
||||
if (ResOriginNode == NULL)
|
||||
if (ResNodeAtOrigin == NULL)
|
||||
{
|
||||
resDevice *res = ResGetDevice(gparams.rg_devloc, gparams.rg_ttype);
|
||||
ResOriginNode = res->rd_fet_source;
|
||||
ResOriginNode->rn_why = RES_NODE_ORIGIN;
|
||||
ResOriginNode->rn_noderes = 0;
|
||||
resDevice *res = ResGetDevice(resisdata->rg_devloc, resisdata->rg_ttype);
|
||||
if (res == (resDevice *)NULL)
|
||||
{
|
||||
TxError("Error: No device type %s found at location %s %s\n",
|
||||
DBTypeLongNameTbl[resisdata->rg_ttype],
|
||||
DBWPrintValue(resisdata->rg_devloc->p_x, (MagWindow *)NULL, TRUE),
|
||||
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow *)NULL, FALSE));
|
||||
return;
|
||||
}
|
||||
ResNodeAtOrigin = res->rd_fet_source;
|
||||
ResNodeAtOrigin->rn_why = RES_NODE_ORIGIN;
|
||||
ResNodeAtOrigin->rn_noderes = 0;
|
||||
}
|
||||
ASSERT(ResOriginNode != NULL, "ResDoSimplify");
|
||||
resPathNode(ResOriginNode);
|
||||
ASSERT(ResNodeAtOrigin != NULL, "ResDoSimplify");
|
||||
resPathNode(ResNodeAtOrigin);
|
||||
while (HeapRemoveTop(&ResistorHeap,&he))
|
||||
resPathRes((resResistor *)he.he_id);
|
||||
}
|
||||
|
|
@ -1053,7 +1059,7 @@ ResSetPathRes()
|
|||
*
|
||||
* Given node "node", add every resistor connected to the node, and
|
||||
* for which the node on the other side has not been processed, to
|
||||
* the heap. Node is marked with FINISHED to prevent going 'round
|
||||
* the heap. Node is marked with RES_FINISHED to prevent going 'round
|
||||
* and 'round loops.
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -1065,7 +1071,7 @@ resPathNode(node)
|
|||
{
|
||||
resElement *re;
|
||||
|
||||
node->rn_status |= FINISHED;
|
||||
node->rn_status |= RES_FINISHED;
|
||||
for (re = node->rn_re; re; re = re->re_nextEl)
|
||||
{
|
||||
resResistor *res = re->re_thisEl;
|
||||
|
|
@ -1073,7 +1079,7 @@ resPathNode(node)
|
|||
|
||||
if (res->rr_status & RES_HEAP) continue;
|
||||
if ((node2 = res->rr_node[0]) == node) node2 = res->rr_node[1];
|
||||
if ((node2->rn_status & FINISHED) == 0)
|
||||
if ((node2->rn_status & RES_FINISHED) == 0)
|
||||
HeapAddInt(&ResistorHeap, node->rn_noderes + res->rr_value,
|
||||
(char *)res);
|
||||
}
|
||||
|
|
@ -1109,8 +1115,8 @@ resPathRes(res)
|
|||
res->rr_status &= ~RES_MARKED;
|
||||
node0 = res->rr_node[0];
|
||||
node1 = res->rr_node[1];
|
||||
flag0 = node0->rn_status & FINISHED;
|
||||
flag1 = node1->rn_status & FINISHED;
|
||||
flag0 = node0->rn_status & RES_FINISHED;
|
||||
flag1 = node1->rn_status & RES_FINISHED;
|
||||
if (flag0 && flag1)
|
||||
{
|
||||
res->rr_status |= RES_TDI_IGNORE;
|
||||
|
|
|
|||
184
resis/ResUtils.c
184
resis/ResUtils.c
|
|
@ -93,7 +93,7 @@ ResFirst(tile, dinfo, arg)
|
|||
*
|
||||
* resMultiPlaneTerm --
|
||||
*
|
||||
* Callback function to set a junk field
|
||||
* Callback function to set a resInfo field
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -102,13 +102,13 @@ int
|
|||
resMultiPlaneTerm(
|
||||
Tile *tile,
|
||||
TileType dinfo, // Unused (but should be handled)
|
||||
tileJunk *junk2)
|
||||
resInfo *rinfo2)
|
||||
{
|
||||
tileJunk *Junk;
|
||||
resInfo *Info;
|
||||
|
||||
Junk = resAddField(tile);
|
||||
Junk->tj_status |= RES_TILE_SD;
|
||||
junk2->sourceEdge |= OTHERPLANE;
|
||||
Info = resAddField(tile);
|
||||
Info->ri_status |= RES_TILE_SD;
|
||||
rinfo2->sourceEdge |= OTHERPLANE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ resMultiPlaneTerm(
|
|||
*
|
||||
* resSubstrateTerm --
|
||||
*
|
||||
* Callback function to set a junk field
|
||||
* Callback function to set a resInfo field
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -128,10 +128,10 @@ resSubstrateTerm(
|
|||
TileType dinfo,
|
||||
ClientData clientdata) /* (unused) */
|
||||
{
|
||||
tileJunk *Junk;
|
||||
resInfo *Info;
|
||||
|
||||
Junk = resAddField(tile);
|
||||
Junk->tj_status |= RES_TILE_SUBS;
|
||||
Info = resAddField(tile);
|
||||
Info->ri_status |= RES_TILE_SUBS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +168,7 @@ ResEach(tile, dinfo, pNum, arg)
|
|||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResAddPlumbing-- Each tile is a tileJunk structure associated with it
|
||||
* ResAddPlumbing-- Each tile has a resInfo structure associated with it
|
||||
* to keep track of various things used by the extractor. ResAddPlumbing
|
||||
* adds this structure and sets the tile's ClientData field to point to it.
|
||||
* If the tile is a device, then a device structure is also added;
|
||||
|
|
@ -188,7 +188,7 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
TileType dinfo;
|
||||
ClientData *arg;
|
||||
{
|
||||
tileJunk *Junk, *junk2;
|
||||
resInfo *Info, *rinfo2;
|
||||
static Stack *resDevStack = NULL;
|
||||
TileType loctype, t1;
|
||||
Tile *tp1, *tp2, *source;
|
||||
|
|
@ -208,7 +208,7 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
loctype = TiGetTypeExact(tile);
|
||||
|
||||
devptr = ExtCurStyle->exts_device[loctype];
|
||||
junk2 = resAddField(tile);
|
||||
rinfo2 = resAddField(tile);
|
||||
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), loctype))
|
||||
{
|
||||
int i, nterms, pNum;
|
||||
|
|
@ -249,8 +249,8 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
resDev->rd_status = 0;
|
||||
resDev->rd_nextDev = (resDevice *)*arg;
|
||||
*arg = (ClientData)resDev;
|
||||
junk2->deviceList = resDev;
|
||||
junk2->tj_status |= RES_TILE_DEV;
|
||||
rinfo2->deviceList = resDev;
|
||||
rinfo2->ri_status |= RES_TILE_DEV;
|
||||
|
||||
for (i = 0; i < nterms - 2; i++)
|
||||
{
|
||||
|
|
@ -263,10 +263,10 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
if TTMaskHasType(&(devptr->exts_deviceSDTypes[i]),
|
||||
TiGetBottomType(tp2))
|
||||
{
|
||||
junk2->sourceEdge |= TOPEDGE;
|
||||
rinfo2->sourceEdge |= TOPEDGE;
|
||||
source = tp2;
|
||||
Junk = resAddField(source);
|
||||
Junk->tj_status |= RES_TILE_SD;
|
||||
Info = resAddField(source);
|
||||
Info->ri_status |= RES_TILE_SD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -278,10 +278,10 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
if TTMaskHasType(&(devptr->exts_deviceSDTypes[i]),
|
||||
TiGetTopType(tp2))
|
||||
{
|
||||
junk2->sourceEdge |= BOTTOMEDGE;
|
||||
rinfo2->sourceEdge |= BOTTOMEDGE;
|
||||
source = tp2;
|
||||
Junk = resAddField(source);
|
||||
Junk->tj_status |= RES_TILE_SD;
|
||||
Info = resAddField(source);
|
||||
Info->ri_status |= RES_TILE_SD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -293,10 +293,10 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
if TTMaskHasType(&(devptr->exts_deviceSDTypes[i]),
|
||||
TiGetLeftType(tp2))
|
||||
{
|
||||
junk2->sourceEdge |= RIGHTEDGE;
|
||||
rinfo2->sourceEdge |= RIGHTEDGE;
|
||||
source = tp2;
|
||||
Junk = resAddField(source);
|
||||
Junk->tj_status |= RES_TILE_SD;
|
||||
Info = resAddField(source);
|
||||
Info->ri_status |= RES_TILE_SD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -309,9 +309,9 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
TiGetRightType(tp2))
|
||||
{
|
||||
source = tp2;
|
||||
Junk = resAddField(source);
|
||||
Junk->tj_status |= RES_TILE_SD;
|
||||
junk2->sourceEdge |= LEFTEDGE;
|
||||
Info = resAddField(source);
|
||||
Info->ri_status |= RES_TILE_SD;
|
||||
rinfo2->sourceEdge |= LEFTEDGE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -327,7 +327,7 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
DBSrPaintArea((Tile *)NULL,
|
||||
ResUse->cu_def->cd_planes[pNum],
|
||||
&r, &(devptr->exts_deviceSDTypes[i]),
|
||||
resMultiPlaneTerm, (ClientData)junk2);
|
||||
resMultiPlaneTerm, (ClientData)rinfo2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -360,10 +360,10 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
{
|
||||
if (TiGetBottomType(tp2) == t1)
|
||||
{
|
||||
tileJunk *j = resAddField(tp2);
|
||||
if ((j->tj_status & RES_TILE_SD) == 0)
|
||||
resInfo *re = resAddField(tp2);
|
||||
if ((re->ri_status & RES_TILE_SD) == 0)
|
||||
{
|
||||
j->tj_status |= RES_TILE_SD;
|
||||
re->ri_status |= RES_TILE_SD;
|
||||
STACKPUSH((ClientData)tp2, resDevStack);
|
||||
}
|
||||
}
|
||||
|
|
@ -373,10 +373,10 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
{
|
||||
if (TiGetTopType(tp2) == t1)
|
||||
{
|
||||
tileJunk *j = resAddField(tp2);
|
||||
if ((j->tj_status & RES_TILE_SD) == 0)
|
||||
resInfo *re = resAddField(tp2);
|
||||
if ((re->ri_status & RES_TILE_SD) == 0)
|
||||
{
|
||||
j->tj_status |= RES_TILE_SD;
|
||||
re->ri_status |= RES_TILE_SD;
|
||||
STACKPUSH((ClientData)tp2, resDevStack);
|
||||
}
|
||||
}
|
||||
|
|
@ -386,10 +386,10 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
{
|
||||
if (TiGetLeftType(tp2) == t1)
|
||||
{
|
||||
tileJunk *j = resAddField(tp2);
|
||||
if ((j->tj_status & RES_TILE_SD) == 0)
|
||||
resInfo *re = resAddField(tp2);
|
||||
if ((re->ri_status & RES_TILE_SD) == 0)
|
||||
{
|
||||
j->tj_status |= RES_TILE_SD;
|
||||
re->ri_status |= RES_TILE_SD;
|
||||
STACKPUSH((ClientData)tp2, resDevStack);
|
||||
}
|
||||
}
|
||||
|
|
@ -399,10 +399,10 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
{
|
||||
if (TiGetRightType(tp2) == t1)
|
||||
{
|
||||
tileJunk *j = resAddField(tp2);
|
||||
if ((j->tj_status & RES_TILE_SD) == 0)
|
||||
resInfo *re = resAddField(tp2);
|
||||
if ((re->ri_status & RES_TILE_SD) == 0)
|
||||
{
|
||||
j->tj_status |= RES_TILE_SD;
|
||||
re->ri_status |= RES_TILE_SD;
|
||||
STACKPUSH((ClientData)tp2, resDevStack);
|
||||
}
|
||||
}
|
||||
|
|
@ -430,7 +430,7 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
STACKPUSH((ClientData)tile, resDevStack);
|
||||
while (!StackEmpty(resDevStack))
|
||||
{
|
||||
tileJunk *j0;
|
||||
resInfo *re0;
|
||||
|
||||
tp1 = (Tile *) STACKPOP(resDevStack);
|
||||
if (IsSplit(tp1))
|
||||
|
|
@ -446,17 +446,17 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
t1 = TiGetTypeExact(tp1);
|
||||
|
||||
devptr = ExtCurStyle->exts_device[t1];
|
||||
j0 = (tileJunk *) TiGetClientPTR(tp1);
|
||||
re0 = (resInfo *) TiGetClientPTR(tp1);
|
||||
/* top */
|
||||
for (tp2 = RT(tp1); RIGHT(tp2) > LEFT(tp1); tp2 = BL(tp2))
|
||||
{
|
||||
if ((TiGetBottomType(tp2) == t1) &&
|
||||
(TiGetClient(tp2) == CLIENTDEFAULT))
|
||||
{
|
||||
Junk = resAddField(tp2);
|
||||
Info = resAddField(tp2);
|
||||
STACKPUSH((ClientData)tp2, resDevStack);
|
||||
Junk->deviceList = resDev;
|
||||
Junk->tj_status |= RES_TILE_DEV;
|
||||
Info->deviceList = resDev;
|
||||
Info->ri_status |= RES_TILE_DEV;
|
||||
|
||||
/* Update device position to point to the lower-leftmost tile */
|
||||
if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) ||
|
||||
|
|
@ -472,9 +472,9 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
|
||||
TiGetBottomType(tp2))
|
||||
{
|
||||
Junk = resAddField(tp2);
|
||||
if (Junk->tj_status & RES_TILE_SD)
|
||||
j0->sourceEdge |= TOPEDGE;
|
||||
Info = resAddField(tp2);
|
||||
if (Info->ri_status & RES_TILE_SD)
|
||||
re0->sourceEdge |= TOPEDGE;
|
||||
}
|
||||
}
|
||||
/* bottom */
|
||||
|
|
@ -483,10 +483,10 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
if ((TiGetTopType(tp2) == t1) &&
|
||||
(TiGetClient(tp2) == CLIENTDEFAULT))
|
||||
{
|
||||
Junk = resAddField(tp2);
|
||||
Info = resAddField(tp2);
|
||||
STACKPUSH((ClientData)tp2, resDevStack);
|
||||
Junk->deviceList = resDev;
|
||||
Junk->tj_status |= RES_TILE_DEV;
|
||||
Info->deviceList = resDev;
|
||||
Info->ri_status |= RES_TILE_DEV;
|
||||
|
||||
/* Update device position to point to the lower-leftmost tile */
|
||||
if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) ||
|
||||
|
|
@ -502,9 +502,9 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
|
||||
TiGetTopType(tp2))
|
||||
{
|
||||
Junk = resAddField(tp2);
|
||||
if (Junk->tj_status & RES_TILE_SD)
|
||||
j0->sourceEdge |= BOTTOMEDGE;
|
||||
Info = resAddField(tp2);
|
||||
if (Info->ri_status & RES_TILE_SD)
|
||||
re0->sourceEdge |= BOTTOMEDGE;
|
||||
}
|
||||
}
|
||||
/* right */
|
||||
|
|
@ -513,10 +513,10 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
if ((TiGetLeftType(tp2) == t1) &&
|
||||
(TiGetClient(tp2) == CLIENTDEFAULT))
|
||||
{
|
||||
Junk = resAddField(tp2);
|
||||
Info = resAddField(tp2);
|
||||
STACKPUSH((ClientData)tp2, resDevStack);
|
||||
Junk->deviceList = resDev;
|
||||
Junk->tj_status |= RES_TILE_DEV;
|
||||
Info->deviceList = resDev;
|
||||
Info->ri_status |= RES_TILE_DEV;
|
||||
|
||||
/* Update device position to point to the lower-leftmost tile */
|
||||
if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) ||
|
||||
|
|
@ -532,9 +532,9 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
|
||||
TiGetLeftType(tp2))
|
||||
{
|
||||
Junk = resAddField(tp2);
|
||||
if (Junk->tj_status & RES_TILE_SD)
|
||||
j0->sourceEdge |= RIGHTEDGE;
|
||||
Info = resAddField(tp2);
|
||||
if (Info->ri_status & RES_TILE_SD)
|
||||
re0->sourceEdge |= RIGHTEDGE;
|
||||
}
|
||||
}
|
||||
/* left */
|
||||
|
|
@ -543,10 +543,10 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
if ((TiGetRightType(tp2) == t1) &&
|
||||
(TiGetClient(tp2) == CLIENTDEFAULT))
|
||||
{
|
||||
Junk = resAddField(tp2);
|
||||
Info = resAddField(tp2);
|
||||
STACKPUSH((ClientData)tp2, resDevStack);
|
||||
Junk->deviceList = resDev;
|
||||
Junk->tj_status |= RES_TILE_DEV;
|
||||
Info->deviceList = resDev;
|
||||
Info->ri_status |= RES_TILE_DEV;
|
||||
|
||||
/* Update device position to point to the lower-leftmost tile */
|
||||
if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) ||
|
||||
|
|
@ -562,9 +562,9 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
|
||||
TiGetRightType(tp2))
|
||||
{
|
||||
Junk = resAddField(tp2);
|
||||
if (Junk->tj_status & RES_TILE_SD)
|
||||
j0->sourceEdge |= LEFTEDGE;
|
||||
Info = resAddField(tp2);
|
||||
if (Info->ri_status & RES_TILE_SD)
|
||||
re0->sourceEdge |= LEFTEDGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -573,10 +573,10 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
|
||||
if (source != (Tile *) NULL)
|
||||
{
|
||||
tileJunk *j = (tileJunk *) TiGetClientPTR(source);
|
||||
resInfo *re = (resInfo *) TiGetClientPTR(source);
|
||||
|
||||
STACKPUSH((ClientData)source, resDevStack);
|
||||
j->tj_status &= ~RES_TILE_SD;
|
||||
re->ri_status &= ~RES_TILE_SD;
|
||||
}
|
||||
while (!StackEmpty(resDevStack))
|
||||
{
|
||||
|
|
@ -592,12 +592,12 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
/* top */
|
||||
for (tp2 = RT(tp1); RIGHT(tp2) > LEFT(tp1); tp2 = BL(tp2))
|
||||
{
|
||||
tileJunk *j2 = (tileJunk *) TiGetClientPTR(tp2);
|
||||
resInfo *re2 = (resInfo *) TiGetClientPTR(tp2);
|
||||
if (TiGetBottomType(tp2) == t1)
|
||||
{
|
||||
if (j2->tj_status & RES_TILE_SD)
|
||||
if (re2->ri_status & RES_TILE_SD)
|
||||
{
|
||||
j2->tj_status &= ~RES_TILE_SD;
|
||||
re2->ri_status &= ~RES_TILE_SD;
|
||||
STACKPUSH((ClientData)tp2, resDevStack);
|
||||
}
|
||||
}
|
||||
|
|
@ -605,12 +605,12 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
/* bottom */
|
||||
for(tp2 = LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2))
|
||||
{
|
||||
tileJunk *j2 = (tileJunk *) TiGetClientPTR(tp2);
|
||||
resInfo *re2 = (resInfo *) TiGetClientPTR(tp2);
|
||||
if (TiGetTopType(tp2) == t1)
|
||||
{
|
||||
if (j2->tj_status & RES_TILE_SD)
|
||||
if (re2->ri_status & RES_TILE_SD)
|
||||
{
|
||||
j2->tj_status &= ~RES_TILE_SD;
|
||||
re2->ri_status &= ~RES_TILE_SD;
|
||||
STACKPUSH((ClientData)tp2, resDevStack);
|
||||
}
|
||||
}
|
||||
|
|
@ -618,12 +618,12 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
/* right */
|
||||
for (tp2 = TR(tp1); TOP(tp2) > BOTTOM(tp1); tp2 = LB(tp2))
|
||||
{
|
||||
tileJunk *j2 = (tileJunk *) TiGetClientPTR(tp2);
|
||||
resInfo *re2 = (resInfo *) TiGetClientPTR(tp2);
|
||||
if (TiGetLeftType(tp2) == t1)
|
||||
{
|
||||
if (j2->tj_status & RES_TILE_SD)
|
||||
if (re2->ri_status & RES_TILE_SD)
|
||||
{
|
||||
j2->tj_status &= ~RES_TILE_SD;
|
||||
re2->ri_status &= ~RES_TILE_SD;
|
||||
STACKPUSH((ClientData)tp2, resDevStack);
|
||||
}
|
||||
}
|
||||
|
|
@ -631,12 +631,12 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
/* left */
|
||||
for (tp2 = BL(tp1); BOTTOM(tp2) < TOP(tp1); tp2 = RT(tp2))
|
||||
{
|
||||
tileJunk *j2 = (tileJunk *) TiGetClientPTR(tp2);
|
||||
resInfo *re2 = (resInfo *) TiGetClientPTR(tp2);
|
||||
if (TiGetRightType(tp2) == t1)
|
||||
{
|
||||
if (j2->tj_status & RES_TILE_SD)
|
||||
if (re2->ri_status & RES_TILE_SD)
|
||||
{
|
||||
j2->tj_status &= ~RES_TILE_SD;
|
||||
re2->ri_status &= ~RES_TILE_SD;
|
||||
STACKPUSH((ClientData)tp2, resDevStack);
|
||||
}
|
||||
}
|
||||
|
|
@ -650,7 +650,7 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResRemovePlumbing-- Removes and deallocates all the tileJunk fields.
|
||||
* ResRemovePlumbing-- Removes and deallocates all the resInfo fields.
|
||||
*
|
||||
* Results: returns 0
|
||||
*
|
||||
|
|
@ -702,7 +702,7 @@ ResPreProcessDevices(TileList, DeviceList, Def)
|
|||
{
|
||||
Tile *tile;
|
||||
ResDevTile *oldTile;
|
||||
tileJunk *tstruct;
|
||||
resInfo *tstruct;
|
||||
TileType tt, residue;
|
||||
int pNum;
|
||||
|
||||
|
|
@ -735,9 +735,9 @@ ResPreProcessDevices(TileList, DeviceList, Def)
|
|||
GOTOPOINT(tile, &(TileList->area.r_ll));
|
||||
|
||||
tt = TiGetType(tile);
|
||||
tstruct = (tileJunk *) TiGetClientPTR(tile);
|
||||
tstruct = (resInfo *) TiGetClientPTR(tile);
|
||||
|
||||
if ((tstruct == (tileJunk *)CLIENTDEFAULT) ||
|
||||
if ((tstruct == (resInfo *)CLIENTDEFAULT) ||
|
||||
(tstruct->deviceList == NULL) ||
|
||||
!TTMaskHasType(&ExtCurStyle->exts_deviceMask, tt))
|
||||
{
|
||||
|
|
@ -745,11 +745,11 @@ ResPreProcessDevices(TileList, DeviceList, Def)
|
|||
TileList->area.r_ll.p_x,
|
||||
TileList->area.r_ll.p_y);
|
||||
}
|
||||
else if ((tstruct->tj_status & RES_TILE_MARK) == 0)
|
||||
else if ((tstruct->ri_status & RES_TILE_MARK) == 0)
|
||||
{
|
||||
resDevice *rd = tstruct->deviceList;
|
||||
|
||||
tstruct->tj_status |= RES_TILE_MARK;
|
||||
tstruct->ri_status |= RES_TILE_MARK;
|
||||
rd->rd_perim += TileList->perim;
|
||||
rd->rd_length += TileList->overlap;
|
||||
rd->rd_area += (TileList->area.r_xtop - TileList->area.r_xbot)
|
||||
|
|
@ -851,17 +851,17 @@ ResRemoveFromQueue(node, list)
|
|||
node->rn_less = NULL;
|
||||
}
|
||||
|
||||
tileJunk *
|
||||
resInfo *
|
||||
resAddField(tile)
|
||||
Tile *tile;
|
||||
{
|
||||
ClientData ticlient = TiGetClient(tile);
|
||||
tileJunk *Junk = (tileJunk *)CD2PTR(ticlient);
|
||||
resInfo *Info = (resInfo *)CD2PTR(ticlient);
|
||||
if (ticlient == CLIENTDEFAULT)
|
||||
{
|
||||
Junk = (tileJunk *) mallocMagic((unsigned) (sizeof(tileJunk)));
|
||||
ResJunkInit(Junk);
|
||||
TiSetClientPTR(tile, Junk);
|
||||
Info = (resInfo *) mallocMagic((unsigned) (sizeof(resInfo)));
|
||||
ResInfoInit(Info);
|
||||
TiSetClientPTR(tile, Info);
|
||||
}
|
||||
return Junk;
|
||||
return Info;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,9 +140,8 @@ resCurrentPrintFunc(node, resistor, filename)
|
|||
for (workingDev = node->rn_te; workingDev != NULL;
|
||||
workingDev = workingDev->te_nextt)
|
||||
{
|
||||
if ((workingDev->te_thist->rd_status & RES_DEV_PLUG) ||
|
||||
workingDev->te_thist->rd_gate != node)
|
||||
i_sum += workingDev->te_thist->rd_i;
|
||||
if (workingDev->te_thist->rd_gate != node)
|
||||
i_sum += workingDev->te_thist->rd_i;
|
||||
}
|
||||
if (i_sum != 0.0)
|
||||
{
|
||||
|
|
|
|||
608
resis/resis.h
608
resis/resis.h
|
|
@ -1,49 +1,38 @@
|
|||
/* Header files for resistance extraction */
|
||||
|
||||
/* Type declarations */
|
||||
|
||||
/* contact points: keeps track where contacts are and what tiles they
|
||||
refer to both before and after processing.
|
||||
*/
|
||||
/* Header files for resistance extraction */
|
||||
|
||||
#ifndef _MAGIC__RESIS__RESIS_H
|
||||
#define _MAGIC__RESIS__RESIS_H
|
||||
|
||||
/*
|
||||
* Contact points: keeps track where contacts are and what tiles they refer to both
|
||||
* before and after processing.
|
||||
*/
|
||||
|
||||
#define LAYERS_PER_CONTACT 4
|
||||
#define TILES_PER_JUNCTION 2
|
||||
|
||||
typedef struct contactpoint
|
||||
{
|
||||
struct contactpoint *cp_nextcontact;/* Next contact in linked */
|
||||
/* list. */
|
||||
Point cp_center; /*Center of contact */
|
||||
Rect cp_rect; /* Tile rectangle */
|
||||
Tile *cp_contactTile;
|
||||
/*
|
||||
The following two keep
|
||||
track of the tiles where
|
||||
the contact was before
|
||||
preprocessing, and the
|
||||
next contact in that tile's
|
||||
area.
|
||||
*/
|
||||
|
||||
Tile *cp_tile[LAYERS_PER_CONTACT];
|
||||
int cp_currentcontact; /* keeps track of tile
|
||||
being processed
|
||||
*/
|
||||
TileType cp_type; /* Type of contact */
|
||||
int cp_width; /* Width (in x) of contact region */
|
||||
int cp_height; /* Height (in y) of contact region */
|
||||
struct resnode *cp_cnode[LAYERS_PER_CONTACT];/* this contact's nodes */
|
||||
int cp_status; /* status of processing on
|
||||
this contact
|
||||
*/
|
||||
struct contactpoint *cp_nextcontact; /* Next contact in linked list. */
|
||||
Point cp_center; /* Center of contact */
|
||||
Rect cp_rect; /* Tile rectangle */
|
||||
Tile *cp_contactTile; /* The following two keep track of
|
||||
* the tiles where the contact was
|
||||
* before preprocessing, and the
|
||||
* next contact in that tile's area.
|
||||
*/
|
||||
Tile *cp_tile[LAYERS_PER_CONTACT];
|
||||
int cp_currentcontact; /* keeps track of tile being processed */
|
||||
TileType cp_type; /* Type of contact */
|
||||
int cp_width; /* Width (in x) of contact region */
|
||||
int cp_height; /* Height (in y) of contact region */
|
||||
struct resnode *cp_cnode[LAYERS_PER_CONTACT]; /* this contact's nodes */
|
||||
int cp_status; /* status of processing on this contact */
|
||||
} ResContactPoint;
|
||||
|
||||
typedef struct resistor
|
||||
{
|
||||
struct resistor *rr_nextResistor; /* Doubly linked list pointers */
|
||||
struct resistor *rr_nextResistor; /* Doubly linked list pointers */
|
||||
struct resistor *rr_lastResistor;
|
||||
struct resnode *rr_node[2];
|
||||
float rr_value; /* Resistor's value in milliohms */
|
||||
|
|
@ -57,10 +46,6 @@ typedef struct resistor
|
|||
int rr_cl; /* resistor centerline for geometry */
|
||||
int rr_width; /* resistor width for geometry */
|
||||
TileType rr_tt; /* type that composes this */
|
||||
/* resistor. */
|
||||
#ifdef ARIEL
|
||||
int rr_csArea; /* crosssectional area in lamba**2*/
|
||||
#endif
|
||||
} resResistor;
|
||||
|
||||
#define rr_connection1 rr_node[0]
|
||||
|
|
@ -85,22 +70,18 @@ typedef struct device
|
|||
struct resnode **rd_terminals;
|
||||
int rd_nterms; /* number of terminals in rt_terminals */
|
||||
int rd_perim; /* info about device */
|
||||
int rd_area; /* used in .ext and .sim file */
|
||||
int rd_area; /* used in .ext file */
|
||||
int rd_length; /* patches. */
|
||||
int rd_width;
|
||||
int rd_tiles; /* number of tiles in device */
|
||||
int rd_devtype; /* tiletype of device. */
|
||||
Rect rd_inside; /* 1x1 rectangle inside device */
|
||||
Tile *rd_tile; /* pointer to a tile in device */
|
||||
#ifdef ARIEL
|
||||
float rd_i; /* Current injected from this device */
|
||||
/* in milliamps */
|
||||
#endif
|
||||
} resDevice;
|
||||
|
||||
/*
|
||||
a junction is formed when two tiles that connect are next to one another.
|
||||
*/
|
||||
* A junction is formed when two tiles that connect are next to one another.
|
||||
*/
|
||||
|
||||
typedef struct junction
|
||||
{
|
||||
|
|
@ -112,8 +93,8 @@ typedef struct junction
|
|||
} ResJunction;
|
||||
|
||||
/*
|
||||
* A port is declared for subcircuits; its name overrides any locally-
|
||||
* generated node name.
|
||||
* A port is declared for subcircuits; its name overrides any locally-generated
|
||||
* node name.
|
||||
*/
|
||||
|
||||
typedef struct resport
|
||||
|
|
@ -125,9 +106,9 @@ typedef struct resport
|
|||
} resPort;
|
||||
|
||||
/*
|
||||
?element are 'cons' cells used to make linked lists of their referential
|
||||
structures.
|
||||
*/
|
||||
* *element are 'cons' (in the LISP sense) cells used to make linked lists of
|
||||
* their referential structures.
|
||||
*/
|
||||
|
||||
typedef struct reselement
|
||||
{
|
||||
|
|
@ -161,15 +142,16 @@ typedef struct celement
|
|||
} cElement;
|
||||
|
||||
/*
|
||||
Nodes formed from network. These are linked both forwards and backwords
|
||||
to other nodes. Lists of devices, resistors, junctions, and contacts
|
||||
corresponding to this node are kept.
|
||||
*/
|
||||
* Nodes formed from network. These are linked both forwards and backwards
|
||||
* to other nodes. Lists of devices, resistors, junctions, and contacts
|
||||
* corresponding to this node are kept.
|
||||
*/
|
||||
|
||||
typedef struct resnode
|
||||
{
|
||||
struct resnode *rn_more; /* doubly linked list pointers */
|
||||
struct resnode *rn_less;
|
||||
tElement *rn_te; /* widgets connected to this node */
|
||||
tElement *rn_te; /* widgets connected to this node */
|
||||
resElement *rn_re;
|
||||
jElement *rn_je;
|
||||
cElement *rn_ce;
|
||||
|
|
@ -202,10 +184,10 @@ typedef struct nelement
|
|||
} nElement;
|
||||
|
||||
/*
|
||||
Breakpoints are places on a tile which may serve as sources/sinks of
|
||||
current. When resistance is calculated for a tile. this is calculated
|
||||
between these points.
|
||||
*/
|
||||
* Breakpoints are places on a tile which may serve as sources/sinks of
|
||||
* current. When resistance is calculated for a tile. this is calculated
|
||||
* between these points.
|
||||
*/
|
||||
|
||||
typedef struct breakpoint
|
||||
{
|
||||
|
|
@ -216,31 +198,31 @@ typedef struct breakpoint
|
|||
} Breakpoint;
|
||||
|
||||
/*
|
||||
Each tile needs to keep track of the following things associated with it.
|
||||
Since there are too many things to fit in the single ti_client field,
|
||||
this 1 to 6 adaptor is used.
|
||||
*/
|
||||
* Each tile needs to keep track of the following things associated with it.
|
||||
* Since there are too many things to fit in the single ti_client field,
|
||||
* this 1 to 7 adaptor is used.
|
||||
*/
|
||||
|
||||
typedef struct tilejunk
|
||||
typedef struct resinfo
|
||||
{
|
||||
cElement *contactList; /*widgets connected to this tile */
|
||||
resDevice *deviceList;
|
||||
resPort *portList;
|
||||
ResJunction *junctionList;
|
||||
Breakpoint *breakList;
|
||||
cElement *contactList; /* widgets connected to this tile */
|
||||
resDevice *deviceList; /* devices this tile is part of */
|
||||
resPort *portList; /* ports connected to this tile */
|
||||
ResJunction *junctionList; /* junctions inside the tile */
|
||||
Breakpoint *breakList; /* breakpoints inside the tile */
|
||||
int sourceEdge; /* used in device tiles to keep
|
||||
* of which diffusion edges are
|
||||
* a transistor's source
|
||||
* track of which diffusion edges
|
||||
* are a transistor's source
|
||||
*/
|
||||
int tj_status; /* status of tile processing */
|
||||
} tileJunk;
|
||||
int ri_status; /* status of tile processing */
|
||||
} resInfo;
|
||||
|
||||
/* ResDevTile keeps track of the location and type of devices.
|
||||
These areas are painted into our copied def after the tree is totally
|
||||
flattened. (They can't be painted right away becasue the copy routine
|
||||
uses the new def to keep track of where it is in the design. It is also
|
||||
used when devices are preproceesed.
|
||||
*/
|
||||
* These areas are painted into our copied def after the tree is totally
|
||||
* flattened. (They can't be painted right away becasue the copy routine
|
||||
* uses the new def to keep track of where it is in the design. It is also
|
||||
* used when devices are preproceesed.
|
||||
*/
|
||||
|
||||
typedef struct resdevtile
|
||||
{
|
||||
|
|
@ -253,25 +235,47 @@ typedef struct resdevtile
|
|||
} ResDevTile;
|
||||
|
||||
/*
|
||||
Goodies contains random stuff passed between the node extractor
|
||||
and ResCheckSimNodes. The location of a start tile and the resistive
|
||||
tolerance are passed down, while the derived network is passed back.
|
||||
*/
|
||||
* 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.
|
||||
*/
|
||||
|
||||
typedef struct goodstuff
|
||||
struct saveList {
|
||||
Plane *sl_plane;
|
||||
CellDef *sl_def;
|
||||
struct saveList *sl_next;
|
||||
};
|
||||
|
||||
/* Structure stores information required to be sent to ExtResisForDef() */
|
||||
|
||||
typedef struct resoptions
|
||||
{
|
||||
TileType rg_ttype;
|
||||
float rg_maxres;
|
||||
float rg_nodecap;
|
||||
float rg_Tdi;
|
||||
int rg_bigdevres;
|
||||
int rg_tilecount;
|
||||
int rg_status;
|
||||
Point *rg_devloc;
|
||||
char *rg_name;
|
||||
} ResGlobalParams;
|
||||
/* Global options for extresist */
|
||||
|
||||
/* Used in RC delay calculations for Tdi filter */
|
||||
float tdiTolerance;
|
||||
float frequency;
|
||||
float rthresh;
|
||||
struct saveList *savePlanes;
|
||||
CellDef *mainDef;
|
||||
|
||||
/*
|
||||
* Various information passed between the node extractor and
|
||||
* ResCheckExtNodes. The location of a start tile and the resistive
|
||||
* tolerance are passed down, while the derived network is passed back.
|
||||
*/
|
||||
|
||||
TileType rg_ttype;
|
||||
float rg_maxres;
|
||||
float rg_nodecap;
|
||||
float rg_Tdi;
|
||||
int rg_bigdevres;
|
||||
int rg_tilecount;
|
||||
int rg_status;
|
||||
Point *rg_devloc;
|
||||
char *rg_name;
|
||||
} ResisData;
|
||||
|
||||
/* Structure used in RC delay calculations for Tdi filter. */
|
||||
/* Attaches to rn_client field of resNode */
|
||||
|
||||
typedef struct rcdelaystuff
|
||||
|
|
@ -280,8 +284,7 @@ typedef struct rcdelaystuff
|
|||
float rc_Tdi; /* Tdi for node */
|
||||
} RCDelayStuff;
|
||||
|
||||
|
||||
/* ResSim.c type declarations */
|
||||
/* More type declarations */
|
||||
|
||||
typedef struct rdev
|
||||
{
|
||||
|
|
@ -291,10 +294,10 @@ typedef struct rdev
|
|||
resDevice *layout; /* pointer to resDevice that */
|
||||
/* corresponds to RDev */
|
||||
int status;
|
||||
struct ressimnode *gate; /* Terminals of transistor. */
|
||||
struct ressimnode *source;
|
||||
struct ressimnode *drain;
|
||||
struct ressimnode *subs; /* Used with subcircuit type only */
|
||||
struct resextnode *gate; /* Terminals of transistor. */
|
||||
struct resextnode *source;
|
||||
struct resextnode *drain;
|
||||
struct resextnode *subs; /* Used with subcircuit type only */
|
||||
Point location; /* Location of lower left point of */
|
||||
/* device. */
|
||||
float resistance; /* "Resistance" of device. */
|
||||
|
|
@ -305,47 +308,40 @@ typedef struct rdev
|
|||
char *rs_dattr;
|
||||
} RDev;
|
||||
|
||||
typedef struct ressimnode
|
||||
typedef struct resextnode
|
||||
{
|
||||
struct ressimnode *nextnode; /* next node in OriginalNodes */
|
||||
struct resextnode *nextnode; /* next node in OriginalNodes */
|
||||
/* linked list. */
|
||||
int status;
|
||||
struct ressimnode *forward; /* If node has been merged, this */
|
||||
int status;
|
||||
struct resextnode *forward; /* If node has been merged, this */
|
||||
/* points to the merged node. */
|
||||
float capacitance; /* capacitance between node and */
|
||||
/* GND for power connections */
|
||||
/* and all capacitance for every */
|
||||
/* thing else. */
|
||||
float cap_vdd; /* capacitance to VDD (used for */
|
||||
/* power calculations only */
|
||||
float cap_couple; /* coupling capacitance */
|
||||
float resistance; /* lumped resistance */
|
||||
float minsizeres; /* Minimum size resistor allowed */
|
||||
Point drivepoint; /* optional, user specified drive */
|
||||
float capacitance; /* Capacitance between node and */
|
||||
/* substrate */
|
||||
float cap_couple; /* Coupling capacitance */
|
||||
float resistance; /* Lumped resistance */
|
||||
float minsizeres; /* Minimum size resistor allowed */
|
||||
Point drivepoint; /* optional, user specified drive */
|
||||
/* point for network. */
|
||||
TileType rs_ttype; /* tiletype of drivepoint */
|
||||
Point location; /* location of bottom of leftmost */
|
||||
TileType rs_ttype; /* Tiletype of drivepoint */
|
||||
Point location; /* Location of bottom of leftmost */
|
||||
/* tile in the lowest numbered */
|
||||
/* plane contained in the node . */
|
||||
Rect rs_bbox; /* location of bottom of leftmost */
|
||||
/* plane contained in the node. */
|
||||
Rect rs_bbox; /* Location of bottom of leftmost */
|
||||
/* tile in the lowest numbered */
|
||||
/* plane contained in the node . */
|
||||
TileType type; /* Tile type of tile at location */
|
||||
struct devptr *firstDev; /* linked list of devices */
|
||||
/* plane contained in the node. */
|
||||
TileType type; /* Tile type of tile at location */
|
||||
struct devptr *firstDev; /* Linked list of devices */
|
||||
/* connected to node. */
|
||||
char *name; /* Pointer to name of node stored */
|
||||
char *name; /* Pointer to name of node stored */
|
||||
/* in hash table. */
|
||||
char *oldname; /* Pointer to previous name of */
|
||||
char *oldname; /* Pointer to previous name of */
|
||||
/* node, if it exists */
|
||||
tElement *rs_sublist[2]; /* pointers to Gnd and Vdd sub */
|
||||
/* strate connections,
|
||||
if they exist */
|
||||
} ResSimNode;
|
||||
} ResExtNode;
|
||||
|
||||
#define RES_SUB_GND 0
|
||||
#define RES_SUB_VDD 1
|
||||
|
||||
/* `cons' cell for linked list of devices connected to node */
|
||||
/* `cons' cell for linked list of devices connected to node */
|
||||
|
||||
typedef struct devptr
|
||||
{
|
||||
|
|
@ -355,40 +351,6 @@ typedef struct devptr
|
|||
/* is connected to node. */
|
||||
} devPtr;
|
||||
|
||||
/* ResTime.c type declarations */
|
||||
|
||||
typedef struct resevent /* Raw event list read in from rsim/tv */
|
||||
{
|
||||
int rv_node; /* node number */
|
||||
int rv_final; /* final value; (0,1, or X) */
|
||||
int rv_tmin; /* minimum event time in units of 100ps */
|
||||
int rv_tmax; /* maximum event time in units of 100ps */
|
||||
float rv_i; /* event current in milliamps */
|
||||
resDevice *rv_dev; /* device where charge drains */
|
||||
} ResEvent;
|
||||
|
||||
typedef struct reseventcell
|
||||
{
|
||||
ResEvent *rl_this;
|
||||
struct reseventcell *rl_next;
|
||||
} REcell;
|
||||
|
||||
typedef struct rescurrentevent /* processed event used to feed relaxer */
|
||||
{
|
||||
struct rescurrentevent *ri_next;
|
||||
float ri_i;
|
||||
resDevice *ri_dev;
|
||||
} ResCurrentEvent;
|
||||
|
||||
typedef struct restimebin /* Holds one timestep's worth of Events */
|
||||
{
|
||||
struct restimebin *rb_next;
|
||||
struct restimebin *rb_last;
|
||||
int rb_start;
|
||||
int rb_end;
|
||||
ResCurrentEvent *rb_first;
|
||||
} ResTimeBin;
|
||||
|
||||
typedef struct resfixpoint /* Keeps track of where voltage sources are */
|
||||
{
|
||||
struct resfixpoint *fp_next;
|
||||
|
|
@ -400,197 +362,136 @@ typedef struct resfixpoint /* Keeps track of where voltage sources are */
|
|||
char fp_name[1];
|
||||
} ResFixPoint;
|
||||
|
||||
typedef struct clump
|
||||
{
|
||||
unsigned rp_status;
|
||||
rElement *rp_grouplist;
|
||||
nElement *rp_nodelist;
|
||||
rElement *rp_downlist;
|
||||
rElement *rp_singlelist;
|
||||
} ResClump;
|
||||
|
||||
/* the first two fields of this plug must be the the same as for
|
||||
resDevice
|
||||
*/
|
||||
typedef struct plug
|
||||
{
|
||||
float rpl_i; /* current injected through
|
||||
this plug
|
||||
*/
|
||||
int rpl_status; /* status bits for this plug */
|
||||
struct plug *rpl_next; /* next plug in this bin */
|
||||
Point rpl_loc; /*location of plug */
|
||||
int rpl_type; /*type of plug */
|
||||
resNode *rpl_node; /* this point's node */
|
||||
} ResPlug;
|
||||
/*
|
||||
* Multipliers telling what portion of capacitance is to Vdd and what part is
|
||||
* to ground. Right now, coupling capacitance is counted twice, so
|
||||
* cap[0] + cap[1] = (c_vdd + c_gnd + 2 * c_couple) / (c_vdd + c_gnd + c_couple);
|
||||
*/
|
||||
|
||||
typedef struct capval
|
||||
{
|
||||
float cap[1][2]; /* multipliers telling what portion of capacitance is
|
||||
to Vdd and what part is to ground. Right now,
|
||||
coupling capacitance is counted twice, so
|
||||
cap[0]+cap[1] = (c_vdd+c_gnd+2*c_couple)/
|
||||
(c_vdd+c_gnd+c_couple);
|
||||
*/
|
||||
float cap[1][2];
|
||||
} ResCapVal;
|
||||
|
||||
/* node flags */
|
||||
#define RES_REACHED_NODE 0x00200000
|
||||
#define RES_NODE_XADJ 0x00400000
|
||||
#define RES_NODE_YADJ 0x00800000
|
||||
/* Node flags ("rn_status" field) */
|
||||
|
||||
/* type of node flags */
|
||||
#define RES_NODE_JUNCTION 0x00000001
|
||||
#define RES_NODE_DEVICE 0x00000002
|
||||
#define RES_NODE_CONTACT 0x00000004
|
||||
#define RES_NODE_ORIGIN 0x00000008
|
||||
#define RES_TRUE 0x00000001
|
||||
#define RES_PENDING 0x00000002
|
||||
#define RES_FINISHED 0x00000004
|
||||
#define RES_MARKED 0x00000100
|
||||
#define RES_MAXTDI 0x00001000
|
||||
#define RES_DONE_ONCE 0x00002000
|
||||
#define RES_REACHED_NODE 0x00200000
|
||||
#define RES_NODE_XADJ 0x00400000
|
||||
#define RES_NODE_YADJ 0x00800000
|
||||
|
||||
/* resistor flags */
|
||||
#define RES_DEADEND 0x00001000
|
||||
#define RES_DONE_ONCE 0x00002000
|
||||
#define RES_MARKED 0x00000100
|
||||
#define RES_EW 0x00000200
|
||||
#define RES_NS 0x00000400
|
||||
#define RES_DIAGONAL 0x00000800
|
||||
#define RES_TDI_IGNORE 0x00010000
|
||||
#define RES_REACHED_RESISTOR 0x00100000
|
||||
#define RES_HEAP 0x00200000
|
||||
/* Resistor flags ("rr_status" field) */
|
||||
|
||||
/* device flags */
|
||||
#define RES_DEV_SAVE 0x00000001
|
||||
#define RES_DEV_PLUG 0x00000002
|
||||
#define RES_EW 0x00000200
|
||||
#define RES_NS 0x00000400
|
||||
#define RES_DIAGONAL 0x00000800
|
||||
#define RES_DEADEND 0x00001000
|
||||
#define RES_TDI_IGNORE 0x00010000
|
||||
#define RES_REACHED_RESISTOR 0x00100000
|
||||
#define RES_HEAP 0x00200000
|
||||
|
||||
/* Note that RES_DONE_ONCE and RES_MARKED are used both for rn_status and
|
||||
* rr_status, and these bit values must not collide with any other field
|
||||
* values.
|
||||
*/
|
||||
|
||||
/* Device flags ("rd_status" field) */
|
||||
|
||||
#define RES_DEV_SAVE 0x00000001
|
||||
|
||||
/* Type of node flags ("why" field) */
|
||||
|
||||
#define RES_NODE_JUNCTION 0x00000001
|
||||
#define RES_NODE_DEVICE 0x00000002
|
||||
#define RES_NODE_CONTACT 0x00000004
|
||||
#define RES_NODE_ORIGIN 0x00000008
|
||||
#define RES_NODE_SINK 0x00000010
|
||||
|
||||
/* Flags for tiles ("ri_status" field) */
|
||||
|
||||
#define RES_TILE_SUBS 0x01 /* A tile which is part of a substrate region. */
|
||||
#define RES_TILE_SD 0x02 /* A tile which is part of a source/drain region. */
|
||||
#define RES_TILE_DEV 0x04 /* A tile which is actually a device */
|
||||
#define RES_TILE_DONE 0x08 /* Indicates whether tile has been processed */
|
||||
#define RES_TILE_MARK 0x10 /* A temporary marking flag */
|
||||
#define RES_TILE_PUSHED 0x20 /* Another temporary marking flag */
|
||||
|
||||
/* Tree walking flags */
|
||||
|
||||
/* flags for tiles */
|
||||
/* A tile which is part of a substrate region. */
|
||||
#define RES_TILE_SUBS 0x01
|
||||
/* A tile which is part of a source/drain region. */
|
||||
#define RES_TILE_SD 0x02
|
||||
/* A tile which is actually a device */
|
||||
#define RES_TILE_DEV 0x04
|
||||
/* Indicates whether the tile has been processed or not */
|
||||
#define RES_TILE_DONE 0x08
|
||||
/*a temporary marking flag */
|
||||
#define RES_TILE_MARK 0x10
|
||||
/*another temporary marking flag */
|
||||
#define RES_TILE_PUSHED 0x20
|
||||
/* indicates that tile has unidirectional current flow */
|
||||
#ifdef LAPLACE
|
||||
#define RES_TILE_1D 0x40
|
||||
#define RES_TILE_GDONE 0x80
|
||||
#endif
|
||||
/* tree walking flags */
|
||||
#define RES_LOOP_OK 1
|
||||
#define RES_NO_LOOP 1
|
||||
#define RES_DO_LAST 0
|
||||
#define RES_DO_FIRST 1
|
||||
#define RES_NO_FLAGS 0
|
||||
|
||||
/* Constants (ResExtNode "status" field) */
|
||||
|
||||
/* ResSim Constants */
|
||||
#define FORWARD 0x0000010
|
||||
#define SKIP 0x0000020
|
||||
#define FORCE 0x0000040
|
||||
#define MINSIZE 0x0000080
|
||||
#define DRIVELOC 0x0000100
|
||||
#define PORTNODE 0x0000200
|
||||
#define REDUNDANT 0x0000400
|
||||
#define DONTKILL 0x0000800
|
||||
#define FORWARD 0x0000010
|
||||
#define SKIP 0x0000020
|
||||
#define FORCE 0x0000040
|
||||
#define MINSIZE 0x0000080
|
||||
#define DRIVELOC 0x0000100
|
||||
#define PORTNODE 0x0000200
|
||||
#define REDUNDANT 0x0000400
|
||||
#define DONTKILL 0x0000800
|
||||
|
||||
/* Capacitance table constants */
|
||||
#define RES_CAP_GND 0
|
||||
#define RES_CAP_VDD 1
|
||||
#define RES_CAP_COUPLE 2
|
||||
|
||||
#define OHMSTOMILLIOHMS 1000
|
||||
#define FEMTOTOATTO 1000
|
||||
#define ATTOTOFEMTO 0.001
|
||||
|
||||
#define UNTOUCHED 0
|
||||
#define SERIES 1
|
||||
#define PARALLEL 2
|
||||
#define LOOP 4
|
||||
#define SINGLE 8
|
||||
#define TRIANGLE 32
|
||||
#define UNTOUCHED 0
|
||||
#define SERIES 1
|
||||
#define PARALLEL 2
|
||||
#define LOOP 4
|
||||
#define SINGLE 8
|
||||
#define TRIANGLE 32
|
||||
|
||||
#define RESTRUE 1
|
||||
#define PENDING 2
|
||||
#define FINISHED 4
|
||||
#define LEFTEDGE 1
|
||||
#define RIGHTEDGE 4
|
||||
#define TOPEDGE 8
|
||||
#define BOTTOMEDGE 16
|
||||
#define OTHERPLANE 32
|
||||
|
||||
#define LEFTEDGE 1
|
||||
#define RIGHTEDGE 4
|
||||
#define TOPEDGE 8
|
||||
#define BOTTOMEDGE 16
|
||||
#define OTHERPLANE 32
|
||||
#define GATE 1
|
||||
#define SOURCE 2
|
||||
#define DRAIN 3
|
||||
#define SUBS 4
|
||||
|
||||
#define RN_MAXTDI 0x00001000
|
||||
/* "rg_status" flag */
|
||||
|
||||
#define MARKED 0x00000100
|
||||
#define DRIVEONLY 0x00001000
|
||||
|
||||
#define GATE 1
|
||||
#define SOURCE 2
|
||||
#define DRAIN 3
|
||||
#define SUBS 4
|
||||
/* Magic's normal value of infinity is too small---67108863 is only 67K ohms. */
|
||||
|
||||
#define DRIVEONLY 0x00001000
|
||||
#define ORIGIN 0x00000008
|
||||
|
||||
/* magic's normal value of infinity is too small- */
|
||||
/* 67108863 is only 67K ohms. */
|
||||
|
||||
#define RES_INFINITY 0x3FFFFFFF
|
||||
|
||||
#define ResCheckIntegrity
|
||||
#define RES_INFINITY 0x3FFFFFFF
|
||||
|
||||
/* The following turns on and off various options */
|
||||
|
||||
#define ResOpt_ExtractAll 0x00000002
|
||||
#define ResOpt_Simplify 0x00000004
|
||||
#define ResOpt_DoExtFile 0x00000008
|
||||
#define ResOpt_DoRsmFile 0x00000010
|
||||
#define ResOpt_DoLumpFile 0x00000020
|
||||
#define ResOpt_RunSilent 0x00000040
|
||||
#define ResOpt_ExplicitRtol 0x00000080
|
||||
#define ResOpt_ExplicitTditol 0x00000100
|
||||
#define ResOpt_Tdi 0x00000200
|
||||
#define ResOpt_Stat 0x00000400
|
||||
#define ResOpt_Power 0x00000800
|
||||
#define ResOpt_Signal 0x00001000
|
||||
#define ResOpt_Pname 0x00002000
|
||||
#define ResOpt_Geometry 0x00004000
|
||||
#define ResOpt_FastHenry 0x00008000
|
||||
#define ResOpt_Blackbox 0x00010000
|
||||
#define ResOpt_Dump 0x00020000
|
||||
#define ResOpt_DoSubstrate 0x00040000
|
||||
#define ResOpt_GndPlugs 0x00200000
|
||||
#define ResOpt_VddPlugs 0x00400000
|
||||
#define ResOpt_CMOS 0x00800000
|
||||
#define ResOpt_Bipolar 0x01000000
|
||||
#define ResOpt_Box 0x02000000
|
||||
#ifdef LAPLACE
|
||||
#define ResOpt_DoLaplace 0x04000000
|
||||
#define ResOpt_CacheLaplace 0x08000000
|
||||
#define ResOpt_Checkpoint 0x80000000
|
||||
#endif
|
||||
|
||||
#define ResOpt_VDisplay 0x10000000
|
||||
#define ResOpt_IDisplay 0x20000000
|
||||
#define ResOpt_PDisplay 0x40000000
|
||||
#define ResOpt_ExtractAll 0x0001
|
||||
#define ResOpt_Simplify 0x0002
|
||||
#define ResOpt_DoExtFile 0x0004
|
||||
#define ResOpt_DoLumpFile 0x0008
|
||||
#define ResOpt_RunSilent 0x0010
|
||||
#define ResOpt_Stats 0x0020
|
||||
#define ResOpt_Tdi 0x0040
|
||||
#define ResOpt_Signal 0x0080
|
||||
#define ResOpt_Geometry 0x0100
|
||||
#define ResOpt_FastHenry 0x0200
|
||||
#define ResOpt_Blackbox 0x0300
|
||||
#define ResOpt_DoSubstrate 0x0800
|
||||
#define ResOpt_Box 0x1000
|
||||
|
||||
/* Assorted Variables */
|
||||
|
||||
extern RDev *ResRDevList;
|
||||
extern REcell *ResBigEventList;
|
||||
extern int ResOptionsFlags;
|
||||
extern char *ResCurrentNode;
|
||||
extern ResSimNode *ResOriginalNodes;
|
||||
#ifdef ARIEL
|
||||
extern int ResMinEventTime;
|
||||
extern int ResMaxEventTime;
|
||||
typedef float ResCapElement[2];
|
||||
extern ResCapElement *ResCapTableMax;
|
||||
extern ResCapElement *ResCapTableMin;
|
||||
extern HashTable ResPlugTable;
|
||||
#endif
|
||||
extern ResExtNode *ResOriginalNodes;
|
||||
|
||||
extern CellUse *ResUse;
|
||||
extern CellDef *ResDef;
|
||||
|
|
@ -601,39 +502,44 @@ extern resNode *ResNodeList;
|
|||
extern resDevice *ResDevList;
|
||||
extern ResContactPoint *ResContactList;
|
||||
extern resNode *ResNodeQueue;
|
||||
extern resNode *ResOriginNode;
|
||||
extern resNode *ResNodeAtOrigin;
|
||||
extern resNode *resCurrentNode;
|
||||
extern HashTable ResNodeTable;
|
||||
extern HashTable ResSimDevTable;
|
||||
extern HashTable ResExtDevTable;
|
||||
extern ResFixPoint *ResFixList;
|
||||
extern int ResTileCount;
|
||||
extern ResSimNode **ResNodeArray;
|
||||
extern ResExtNode **ResNodeArray;
|
||||
extern CellDef *mainDef;
|
||||
extern TileTypeBitMask ResSDTypesBitMask;
|
||||
extern TileTypeBitMask ResSubTypesBitMask;
|
||||
extern HashTable ResDevTable;
|
||||
extern TileTypeBitMask ResNoMergeMask[NT];
|
||||
extern ResGlobalParams gparams;
|
||||
extern int ResPortIndex;
|
||||
|
||||
extern int ResSimDevice();
|
||||
extern int ResSimCombineParallel();
|
||||
extern int ResSimCapacitor();
|
||||
extern int ResSimResistor();
|
||||
extern int ResSimAttribute();
|
||||
extern int ResSimMerge();
|
||||
extern int ResSimSubckt();
|
||||
/* Routines used by ResReadExt() */
|
||||
|
||||
extern ResisData *ResInit();
|
||||
extern int ResReadDevice();
|
||||
extern int ResReadCapacitor();
|
||||
extern int ResReadResistor();
|
||||
extern int ResReadAttribute();
|
||||
extern int ResReadMerge();
|
||||
extern int ResReadSubckt();
|
||||
|
||||
extern int ResProcessNode();
|
||||
extern int ResExtCombineParallel();
|
||||
extern int dbSrConnectStartFunc();
|
||||
extern int ResEach(),ResAddPlumbing(),ResRemovePlumbing();
|
||||
extern int ResEach();
|
||||
extern int ResAddPlumbing();
|
||||
extern int ResRemovePlumbing();
|
||||
extern float ResCalculateChildCapacitance();
|
||||
extern ResDevTile *DBTreeCopyConnectDCS();
|
||||
extern Tile *ResFindTile();
|
||||
extern resDevice *ResImageAddPlug();
|
||||
extern resDevice *ResGetDevice();
|
||||
extern tileJunk *resAddField();
|
||||
extern resInfo *resAddField();
|
||||
extern int ResCheckPorts();
|
||||
extern int ResCheckBlackbox();
|
||||
extern void ResCheckSimNodes();
|
||||
extern void ResCheckExtNodes();
|
||||
extern void ResSortByGate();
|
||||
extern void ResFixDevName();
|
||||
extern void ResWriteLumpFile();
|
||||
|
|
@ -641,6 +547,14 @@ extern void ResSortBreaks();
|
|||
extern Plane *extResPrepSubstrate();
|
||||
|
||||
/* C99 compat */
|
||||
|
||||
extern void ExtResisForDef(CellDef *celldef, ResisData *resisdata);
|
||||
extern char *ResExtGetAttribute(char *sptr);
|
||||
extern int ResReadFET(int argc, char *argv[]);
|
||||
extern int ResReadPort(int argc, char *argv[]);
|
||||
extern char *ResExtGetAttribute(char *sptr);
|
||||
|
||||
extern ResExtNode *ResExtInitNode();
|
||||
extern void ResAddToQueue();
|
||||
extern bool ResCalcTileResistance();
|
||||
extern void ResCleanNode();
|
||||
|
|
@ -662,10 +576,11 @@ extern void ResPrintReference();
|
|||
extern void ResPrintResistorList();
|
||||
extern void ResPrintStats();
|
||||
extern void ResProcessJunction();
|
||||
extern int ResReadNode();
|
||||
extern int ResReadSim();
|
||||
extern ResExtNode *ResReadNode(int argc, char *argv[]);
|
||||
extern int ResReadExt();
|
||||
extern void ResRemoveFromQueue();
|
||||
extern int ResSimNewNode();
|
||||
extern int ResExtNewNode();
|
||||
extern void ResExtProcessDrivePoints();
|
||||
extern int ResWriteExtFile();
|
||||
extern void ResPrintExtNode();
|
||||
extern void ResPrintExtRes();
|
||||
|
|
@ -681,10 +596,9 @@ extern int resWalkleft();
|
|||
extern int resWalkright();
|
||||
extern int resWalkup();
|
||||
|
||||
/* Macros */
|
||||
|
||||
/* macros */
|
||||
|
||||
#define InitializeNode(node,x,y,why) \
|
||||
#define InitializeResNode(node,x,y,why) \
|
||||
{\
|
||||
(node)->rn_te = NULL;\
|
||||
(node)->rn_id=0;\
|
||||
|
|
@ -701,21 +615,21 @@ extern int resWalkup();
|
|||
(node)->rn_re = (resElement *) NULL;\
|
||||
}
|
||||
|
||||
#define ResJunkInit(Junk) \
|
||||
#define ResInfoInit(Info) \
|
||||
{ \
|
||||
Junk->contactList = (cElement *) NULL; \
|
||||
Junk->deviceList = (resDevice *) NULL; \
|
||||
Junk->junctionList = (ResJunction *) NULL; \
|
||||
Junk->breakList = (Breakpoint *) NULL; \
|
||||
Junk->portList = (resPort *) NULL; \
|
||||
Junk->tj_status = FALSE; \
|
||||
Junk->sourceEdge = 0 ; \
|
||||
Info->contactList = (cElement *) NULL; \
|
||||
Info->deviceList = (resDevice *) NULL; \
|
||||
Info->junctionList = (ResJunction *) NULL; \
|
||||
Info->breakList = (Breakpoint *) NULL; \
|
||||
Info->portList = (resPort *) NULL; \
|
||||
Info->ri_status = FALSE; \
|
||||
Info->sourceEdge = 0 ; \
|
||||
}
|
||||
|
||||
#define NEWBREAK(node,tile,px,py,crect)\
|
||||
{\
|
||||
Breakpoint *bp;\
|
||||
tileJunk *jX_ = (tileJunk *)((tile)->ti_client); \
|
||||
resInfo *jX_ = (resInfo *)((tile)->ti_client); \
|
||||
bp = (Breakpoint *) mallocMagic((unsigned)(sizeof(Breakpoint))); \
|
||||
bp->br_next= jX_->breakList; \
|
||||
bp->br_this = (node); \
|
||||
|
|
@ -728,7 +642,7 @@ extern int resWalkup();
|
|||
#define NEWPORT(node,tile)\
|
||||
{\
|
||||
resPort *rp;\
|
||||
tileJunk *pX_ = (tileJunk *)((tile)->ti_client); \
|
||||
resInfo *pX_ = (resInfo *)((tile)->ti_client); \
|
||||
rp = (resPort *) mallocMagic((unsigned)(sizeof(resPort))); \
|
||||
rp->rp_nextPort = pX_->portList; \
|
||||
rp->rp_bbox = node->rs_bbox; \
|
||||
|
|
|
|||
|
|
@ -321,14 +321,20 @@ selRedisplayCellFunc(scx, window)
|
|||
if (scx->scx_use->cu_def->cd_flags & CDFIXEDBBOX)
|
||||
{
|
||||
bool found;
|
||||
char *propval;
|
||||
PropertyRecord *proprec;
|
||||
|
||||
propval = (char *)DBPropGet(scx->scx_use->cu_def, "FIXED_BBOX", &found);
|
||||
proprec = DBPropGet(scx->scx_use->cu_def, "FIXED_BBOX", &found);
|
||||
if (found)
|
||||
{
|
||||
if (sscanf(propval, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
||||
&bbox.r_xtop, &bbox.r_ytop) == 4)
|
||||
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||
(proprec->prop_len == 4))
|
||||
{
|
||||
bbox.r_xbot = proprec->prop_value.prop_integer[0];
|
||||
bbox.r_ybot = proprec->prop_value.prop_integer[1];
|
||||
bbox.r_xtop = proprec->prop_value.prop_integer[2];
|
||||
bbox.r_ytop = proprec->prop_value.prop_integer[3];
|
||||
GeoTransRect(&scx->scx_trans, &bbox, &tmp);
|
||||
}
|
||||
else
|
||||
found = FALSE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,14 +46,14 @@ proc magic::drccallback {command} {
|
|||
}
|
||||
zoom {
|
||||
if {$value != {}} {
|
||||
set snaptype [snap]
|
||||
snap internal
|
||||
set curunits [units]
|
||||
units internal
|
||||
box values {*}$value
|
||||
magic::suspendall
|
||||
magic::findbox zoom
|
||||
magic::zoom 2
|
||||
magic::resumeall
|
||||
snap $snaptype
|
||||
units {*}$curunits
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -250,10 +250,10 @@ proc magic::change_label {} {
|
|||
setlabel size ${lsize}um
|
||||
}
|
||||
if {$loff != ""} {
|
||||
set oldsnap [snap list]
|
||||
snap internal
|
||||
set oldunits [units]
|
||||
units internal
|
||||
setlabel offset [join $loff]
|
||||
snap $oldsnap
|
||||
units $oldunits
|
||||
}
|
||||
if {$lrot != ""} {
|
||||
setlabel rotate $lrot
|
||||
|
|
|
|||
|
|
@ -10,6 +10,11 @@
|
|||
# Revision 2 (names are hashed from properties)
|
||||
# March 9, 2021
|
||||
# Added spice-to-layout procedure
|
||||
# March 4, 2026
|
||||
# Changed to make use of new "units" command
|
||||
# March 26, 2026
|
||||
# Added behavior to handle ideal devices (resistor, capacitor,
|
||||
# inductor)
|
||||
#--------------------------------------------------------------
|
||||
# Sets up the environment for a toolkit. The toolkit must
|
||||
# supply a namespace that is the "library name". For each
|
||||
|
|
@ -118,6 +123,8 @@ magic::tag add select "magic::gencell_update %1"
|
|||
|
||||
proc magic::move_forward_by_width {instname} {
|
||||
select cell $instname
|
||||
set curunits [units]
|
||||
units internal
|
||||
set anum [lindex [array -list count] 1]
|
||||
set xpitch [lindex [array -list pitch] 0]
|
||||
set bbox [box values]
|
||||
|
|
@ -125,7 +132,8 @@ proc magic::move_forward_by_width {instname} {
|
|||
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
|
||||
box position ${posx} ${posy}
|
||||
units {*}$curunits
|
||||
return [lindex $bbox 3]
|
||||
}
|
||||
|
||||
|
|
@ -141,10 +149,13 @@ proc magic::get_and_move_inst {cellname instname {anum 1}} {
|
|||
if {$newinst == ""} {return}
|
||||
identify $instname
|
||||
if {$anum > 1} {array 1 $anum}
|
||||
set curunits [units]
|
||||
units internal
|
||||
set bbox [box values]
|
||||
set posx [lindex $bbox 2]
|
||||
set posy [lindex $bbox 1]
|
||||
box position ${posx}i ${posy}i
|
||||
box position ${posx} ${posy}
|
||||
units {*}$curunits
|
||||
return [lindex $bbox 3]
|
||||
}
|
||||
|
||||
|
|
@ -155,11 +166,14 @@ proc magic::get_and_move_inst {cellname instname {anum 1}} {
|
|||
# given layer. Otherwise, the pin is created on the m1 layer.
|
||||
|
||||
proc magic::create_new_pin {pinname portnum {layer m1}} {
|
||||
box size 1um 1um
|
||||
set curunits [units]
|
||||
units microns
|
||||
box size 1 1
|
||||
paint $layer
|
||||
label $pinname FreeSans 16 0 0 0 c $layer
|
||||
label $pinname FreeSans 1 0 0 0 c $layer
|
||||
port make $portnum
|
||||
box move s 2um
|
||||
box move s 2
|
||||
units {*}$curunits
|
||||
}
|
||||
|
||||
# generate_layout_add --
|
||||
|
|
@ -172,6 +186,9 @@ proc magic::create_new_pin {pinname portnum {layer m1}} {
|
|||
proc magic::generate_layout_add {subname subpins complist library} {
|
||||
global PDKNAMESPACE
|
||||
|
||||
set curunits [units]
|
||||
units internal
|
||||
|
||||
# Create a new subcircuit.
|
||||
load $subname -quiet
|
||||
|
||||
|
|
@ -241,7 +258,7 @@ proc magic::generate_layout_add {subname subpins complist library} {
|
|||
box size 0 0
|
||||
set posx 0
|
||||
set posy [expr {round(3 / [cif scale out])}]
|
||||
box position ${posx}i ${posy}i
|
||||
box position ${posx} ${posy}
|
||||
|
||||
# Find all instances in the circuit
|
||||
select top cell
|
||||
|
|
@ -267,8 +284,13 @@ proc magic::generate_layout_add {subname subpins complist library} {
|
|||
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.
|
||||
# with models. There are two exceptions, for toolkits which
|
||||
# wish to implement a way to generate unmodeled capacitors,
|
||||
# resistors, or inductors based on value; for example, metal
|
||||
# interdigitated capacitors. For those exceptions, the device
|
||||
# value is recast as a parameter called "value", and the device
|
||||
# is given a model "capacitor", "resistor", or "inductor",
|
||||
# respectively.
|
||||
|
||||
# Parse SPICE line into pins, device name, and parameters. Make
|
||||
# sure parameters incorporate quoted expressions as {} or ''.
|
||||
|
|
@ -312,6 +334,23 @@ proc magic::generate_layout_add {subname subpins complist library} {
|
|||
set devtype [lindex $pinlist end]
|
||||
set pinlist [lrange $pinlist 0 end-1]
|
||||
|
||||
# Ideal device check: "devtype" will start with a digit.
|
||||
# The instname will begin with "c", "r", or "l".
|
||||
|
||||
if {[regexp {^([0-9\.]+.*)} $devtype pval]} {
|
||||
set comptype [string tolower [string range $instname 0 0]]
|
||||
if {$comptype == "c"} {
|
||||
lappend paramlist [list value $pval]
|
||||
set devtype capacitor
|
||||
} elseif {$comptype == "r"} {
|
||||
lappend paramlist [list value $pval]
|
||||
set devtype resistor
|
||||
} elseif {$comptype == "l"} {
|
||||
lappend paramlist [list value $pval]
|
||||
set devtype inductor
|
||||
}
|
||||
}
|
||||
|
||||
set mult 1
|
||||
foreach param $paramlist {
|
||||
set parmname [lindex $param 0]
|
||||
|
|
@ -323,6 +362,27 @@ proc magic::generate_layout_add {subname subpins complist library} {
|
|||
}
|
||||
}
|
||||
|
||||
# Check if devtype has routines by looking for ${devtype}_defaults.
|
||||
# If not found, do a case-insensitive check against all devices
|
||||
# before deciding that devtype is a subcircuit and not a device.
|
||||
# If found by case-insensitive check, then change the device name
|
||||
# to the one used in the library.
|
||||
|
||||
if {$library != ""} {
|
||||
set alldevices [namespace eval ::${library} {info procs}]
|
||||
} else {
|
||||
set alldevices [namespace eval ::${PDKNAMESPACE} {info procs}]
|
||||
}
|
||||
set devdefault [lsearch $alldevices ${devtype}_defaults]
|
||||
if {$devdefault == -1} {
|
||||
set devdefault [lsearch -nocase $alldevices ${devtype}_defaults]
|
||||
if {$devdefault != -1} {
|
||||
set devprocname [lindex $alldevices $devdefault]
|
||||
set devproclist [split $devprocname "_"]
|
||||
set devtype [lindex $devproclist 0]
|
||||
}
|
||||
}
|
||||
|
||||
# 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.
|
||||
|
|
@ -374,6 +434,7 @@ proc magic::generate_layout_add {subname subpins complist library} {
|
|||
}
|
||||
}
|
||||
save $subname
|
||||
units {*}$curunits
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------
|
||||
|
|
@ -485,7 +546,7 @@ proc magic::netlist_to_layout {netfile library} {
|
|||
set subname [lindex $ftokens 1]
|
||||
set subpins [lrange $ftokens 2 end]
|
||||
set insub true
|
||||
} elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \
|
||||
} elseif {[regexp -nocase {^[xmcrldq]([^ \t]+)[ \t](.*)$} $line \
|
||||
valid instname rest]} {
|
||||
lappend toplist $line
|
||||
} elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \
|
||||
|
|
@ -500,7 +561,7 @@ proc magic::netlist_to_layout {netfile library} {
|
|||
set subname ""
|
||||
set subpins ""
|
||||
set complist {}
|
||||
} elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \
|
||||
} elseif {[regexp -nocase {^[xmcrldq]([^ \t]+)[ \t](.*)$} $line \
|
||||
valid instname rest]} {
|
||||
lappend complist $line
|
||||
} elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \
|
||||
|
|
@ -813,8 +874,8 @@ proc magic::gencell_change {instname gencell_type library parameters} {
|
|||
return
|
||||
}
|
||||
|
||||
set snaptype [snap list]
|
||||
snap internal
|
||||
set curunits [units]
|
||||
units internal
|
||||
set savebox [box values]
|
||||
|
||||
catch {setpoint 0 0 $Opts(focus)}
|
||||
|
|
@ -881,7 +942,7 @@ proc magic::gencell_change {instname gencell_type library parameters} {
|
|||
}
|
||||
identify $newinstname
|
||||
eval "box values $savebox"
|
||||
snap $snaptype
|
||||
units {*}$curunits
|
||||
|
||||
# Update window
|
||||
if {$gname != $old_gname} {
|
||||
|
|
@ -940,8 +1001,8 @@ proc magic::gencell_change_orig {instname gencell_type library parameters} {
|
|||
return
|
||||
}
|
||||
|
||||
set snaptype [snap list]
|
||||
snap internal
|
||||
set curunits [units]
|
||||
units internal
|
||||
set savebox [box values]
|
||||
|
||||
catch {setpoint 0 0 $Opts(focus)}
|
||||
|
|
@ -969,7 +1030,7 @@ proc magic::gencell_change_orig {instname gencell_type library parameters} {
|
|||
}
|
||||
identify $newinstname
|
||||
eval "box values $savebox"
|
||||
snap $snaptype
|
||||
units {*}$curunits
|
||||
resumeall
|
||||
redraw
|
||||
}
|
||||
|
|
@ -1092,8 +1153,8 @@ proc magic::gencell_create {gencell_type library parameters {orient 0}} {
|
|||
set parameters [dict remove $parameters gencell]
|
||||
}
|
||||
|
||||
set snaptype [snap list]
|
||||
snap internal
|
||||
set curunits [units]
|
||||
units internal
|
||||
set savebox [box values]
|
||||
|
||||
catch {setpoint 0 0 $Opts(focus)}
|
||||
|
|
@ -1123,7 +1184,7 @@ proc magic::gencell_create {gencell_type library parameters {orient 0}} {
|
|||
identify $newinstname
|
||||
set instname $newinstname
|
||||
}
|
||||
snap $snaptype
|
||||
units {*}$curunits
|
||||
resumeall
|
||||
redraw
|
||||
return $instname
|
||||
|
|
@ -1163,17 +1224,7 @@ proc magic::add_entry {pname ptext parameters} {
|
|||
proc magic::add_check_callbacks {gencell_type library} {
|
||||
set wlist [winfo children .params.body.area.edits]
|
||||
foreach w $wlist {
|
||||
if {[regexp {\.params\.body\.area\.edits\.(.+)_ent} $w valid pname]} {
|
||||
# Add callback on enter or focus out
|
||||
bind $w <Return> \
|
||||
"magic::update_dialog {} $pname $gencell_type $library"
|
||||
bind $w <FocusOut> \
|
||||
"magic::update_dialog {} $pname $gencell_type $library"
|
||||
}
|
||||
if {[regexp {\.params\.body\.area\.edits\.(.+)_sel} $w valid pname]} {
|
||||
magic::add_dependency \{\} $gencell_type $library $pname
|
||||
}
|
||||
if {[regexp {\.params\.body\.area\.edits\.(.+)_chk} $w valid pname]} {
|
||||
if {[regexp {\.params\.body\.area\.edits\.(.+)_.+} $w valid pname]} {
|
||||
magic::add_dependency \{\} $gencell_type $library $pname
|
||||
}
|
||||
}
|
||||
|
|
@ -1192,6 +1243,11 @@ proc magic::add_check_callbacks {gencell_type library} {
|
|||
# dictionary.
|
||||
#
|
||||
# Also handle dependencies on checkboxes and selection lists
|
||||
#
|
||||
# If dependency callbacks exist, then chain them together.
|
||||
# A final default dependency will be added to all entries
|
||||
# to run the "check" procedure for the device. Dependencies
|
||||
# that are more targeted get run first.
|
||||
#----------------------------------------------------------
|
||||
|
||||
proc magic::add_dependency {callback gencell_type library args} {
|
||||
|
|
@ -1206,21 +1262,28 @@ proc magic::add_dependency {callback gencell_type library args} {
|
|||
foreach pname $args {
|
||||
if {[lsearch $clist .params.body.area.edits.${pname}_ent] >= 0} {
|
||||
# Add callback on enter or focus out
|
||||
bind .params.body.area.edits.${pname}_ent <Return> \
|
||||
"magic::update_dialog $callback $pname $gencell_type $library"
|
||||
bind .params.body.area.edits.${pname}_ent <FocusOut> \
|
||||
"magic::update_dialog $callback $pname $gencell_type $library"
|
||||
set oldbind [bind .params.body.area.edits.${pname}_ent <Return>]
|
||||
set newbind "magic::update_dialog $callback $pname $gencell_type $library"
|
||||
if {$oldbind != {}} {set newbind "$oldbind ; $newbind"}
|
||||
bind .params.body.area.edits.${pname}_ent <Return> $newbind
|
||||
set oldbind [bind .params.body.area.edits.${pname}_ent <FocusOut>]
|
||||
set newbind "magic::update_dialog $callback $pname $gencell_type $library"
|
||||
if {$oldbind != {}} {set newbind "$oldbind ; $newbind"}
|
||||
bind .params.body.area.edits.${pname}_ent <FocusOut> $newbind
|
||||
} elseif {[lsearch $clist .params.body.area.edits.${pname}_chk] >= 0} {
|
||||
# Add callback on checkbox change state
|
||||
.params.body.area.edits.${pname}_chk configure -command \
|
||||
"magic::update_dialog $callback $pname $gencell_type $library"
|
||||
set oldcmd [.params.body.area.edits.${pname}_chk cget -command]
|
||||
set newcmd "magic::update_dialog $callback $pname $gencell_type $library"
|
||||
if {$oldcmd != {}} {set newcmd "$oldcmd ; $newcmd"}
|
||||
.params.body.area.edits.${pname}_chk configure -command $newcmd
|
||||
} elseif {[lsearch $clist .params.body.area.edits.${pname}_sel] >= 0} {
|
||||
set smenu .params.body.area.edits.${pname}_sel.menu
|
||||
set sitems [${smenu} index end]
|
||||
for {set idx 0} {$idx <= $sitems} {incr idx} {
|
||||
set curcommand [${smenu} entrycget $idx -command]
|
||||
${smenu} entryconfigure $idx -command "$curcommand ; \
|
||||
magic::update_dialog $callback $pname $gencell_type $library"
|
||||
set oldcmd [${smenu} entrycget $idx -command]
|
||||
set newcmd "magic::update_dialog $callback $pname $gencell_type $library"
|
||||
if {$oldcmd != {}} {set newcmd "$oldcmd ; $newcmd"}
|
||||
${smenu} entryconfigure $idx -command $newcmd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,11 @@ proc magic::pushstack {{name ""}} {
|
|||
if {[catch {lindex $editstack end}]} {
|
||||
set editstack {}
|
||||
}
|
||||
# Protect against changing units by always using internal units
|
||||
set curunits [units]
|
||||
units internal
|
||||
lappend editstack [view get]
|
||||
units {*}$curunits
|
||||
lappend editstack [cellname list window]
|
||||
set ltag [tag load]
|
||||
tag load {}
|
||||
|
|
@ -158,10 +162,11 @@ proc magic::popstack {} {
|
|||
tag load {}
|
||||
suspendall
|
||||
load [lindex $editstack end]
|
||||
set snaptype [snap]
|
||||
snap internal
|
||||
# Protect against changing units by always using internal units
|
||||
set curunits [units]
|
||||
units internal
|
||||
view [lindex $editstack end-1]
|
||||
snap $snaptype
|
||||
units {*}$curunits
|
||||
catch {magic::cellmanager}
|
||||
catch {magic::captions}
|
||||
resumeall
|
||||
|
|
@ -186,8 +191,8 @@ proc magic::clearstack {} {
|
|||
|
||||
proc magic::pushbox {{values {}}} {
|
||||
global boxstack
|
||||
set snaptype [snap list]
|
||||
snap internal
|
||||
set curunits [units]
|
||||
units internal
|
||||
if {[catch {set boxstack}]} {
|
||||
set boxstack {}
|
||||
}
|
||||
|
|
@ -196,7 +201,7 @@ proc magic::pushbox {{values {}}} {
|
|||
} else {
|
||||
lappend boxstack $values
|
||||
}
|
||||
snap $snaptype
|
||||
units {*}$curunits
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -210,8 +215,8 @@ proc magic::pushbox {{values {}}} {
|
|||
|
||||
proc magic::popbox {{type values}} {
|
||||
global boxstack
|
||||
set snaptype [snap list]
|
||||
snap internal
|
||||
set curunits [units]
|
||||
units internal
|
||||
if {[catch {set boxstack}]} {
|
||||
error "No stack"
|
||||
} elseif {$boxstack == {}} {
|
||||
|
|
@ -231,7 +236,7 @@ proc magic::popbox {{type values}} {
|
|||
}
|
||||
}
|
||||
set boxstack [lrange $boxstack 0 end-1]
|
||||
snap $snaptype
|
||||
units {*}$curunits
|
||||
return $b
|
||||
}
|
||||
|
||||
|
|
@ -355,8 +360,8 @@ proc magic::ruler {{text {}} {orient auto}} {
|
|||
set mmx [expr {($llx + $urx) / 2}]
|
||||
set mmy [expr {($lly + $ury) / 2}]
|
||||
|
||||
set snapsave [snap]
|
||||
snap internal
|
||||
set curunits [units]
|
||||
units internal
|
||||
|
||||
if {$orient == "horizontal"} {
|
||||
element add line l1_$Opts(rulers) black $llx $lly $llx $ury
|
||||
|
|
@ -410,7 +415,7 @@ proc magic::ruler {{text {}} {orient auto}} {
|
|||
element configure l3_$Opts(rulers) flags arrowbottom
|
||||
}
|
||||
}
|
||||
snap $snapsave
|
||||
units {*}$curunits
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
|
|
@ -534,6 +539,7 @@ proc magic::enable_tools {} {
|
|||
magic::macro copy pick
|
||||
|
||||
magic::tool wiring
|
||||
macro Control_Button1 "magic::trackwire %W current"
|
||||
macro Button1 "magic::trackwire %W pick"
|
||||
macro Button2 "magic::trackwire %W done"
|
||||
macro Button3 "magic::trackwire %W cancel"
|
||||
|
|
@ -587,6 +593,19 @@ proc magic::trackwire {window {option {}}} {
|
|||
bind ${window} <Motion> [subst {$Opts(motion); *bypass wire show}]
|
||||
if {$Opts(motion) == {}} {set Opts(motion) "null"}
|
||||
cursor 21
|
||||
} elseif {$option == "current"} {
|
||||
puts stdout $window
|
||||
set curunits [units]
|
||||
units internal
|
||||
wire type {*}[wire values]
|
||||
set wiresize [lindex [wire values] 1]
|
||||
box size $wiresize $wiresize
|
||||
box move bl cursor
|
||||
units {*}$curunits
|
||||
set Opts(motion) [bind ${window} <Motion>]
|
||||
bind ${window} <Motion> [subst {$Opts(motion); *bypass wire show}]
|
||||
if {$Opts(motion) == {}} {set Opts(motion) "null"}
|
||||
cursor 21
|
||||
}
|
||||
} else {
|
||||
if {$option != "cancel"} {
|
||||
|
|
|
|||
|
|
@ -576,6 +576,7 @@ set Opts(toolbar) 0
|
|||
set Opts(toolscale) 1.0
|
||||
set Opts(drc) 1
|
||||
set Opts(autobuttontext) 1
|
||||
set Opts(cmdentry) 0
|
||||
|
||||
# Update cell and tech managers in response to a cif or gds read command
|
||||
|
||||
|
|
@ -649,18 +650,20 @@ proc magic::boxview {win {cmdstr ""}} {
|
|||
|
||||
set framename [winfo parent $win]
|
||||
if {$framename == "."} {return}
|
||||
if {[catch {set cr [cif scale out]}]} {return}
|
||||
set curunits [units list]
|
||||
units microns noprint
|
||||
set bval [${win} box values]
|
||||
set bllx [expr {[lindex $bval 0] * $cr }]
|
||||
set blly [expr {[lindex $bval 1] * $cr }]
|
||||
set burx [expr {[lindex $bval 2] * $cr }]
|
||||
set bury [expr {[lindex $bval 3] * $cr }]
|
||||
set bllx [lindex $bval 0]
|
||||
set blly [lindex $bval 1]
|
||||
set burx [lindex $bval 2]
|
||||
set bury [lindex $bval 3]
|
||||
if {[expr {$bllx == int($bllx)}]} {set bllx [expr {int($bllx)}]}
|
||||
if {[expr {$blly == int($blly)}]} {set blly [expr {int($blly)}]}
|
||||
if {[expr {$burx == int($burx)}]} {set burx [expr {int($burx)}]}
|
||||
if {[expr {$bury == int($bury)}]} {set bury [expr {int($bury)}]}
|
||||
set titletext [format "box (%+g %+g) to (%+g %+g) microns" \
|
||||
$bllx $blly $burx $bury]
|
||||
units {*}$curunits
|
||||
${framename}.titlebar.pos configure -text $titletext
|
||||
}
|
||||
}
|
||||
|
|
@ -672,37 +675,30 @@ proc magic::cursorview {win} {
|
|||
}
|
||||
*bypass logcommands suspend
|
||||
set framename [winfo parent $win]
|
||||
if {[catch {set cr [*bypass cif scale out]}]} {
|
||||
*bypass logcommands resume
|
||||
return
|
||||
}
|
||||
if {$cr == 0} {return}
|
||||
set olst [${win} cursor internal]
|
||||
set olst [${win} cursor microns]
|
||||
|
||||
set olstx [lindex $olst 0]
|
||||
set olsty [lindex $olst 1]
|
||||
|
||||
if {$Opts(crosshair)} {
|
||||
*bypass crosshair ${olstx}i ${olsty}i
|
||||
*bypass crosshair ${olstx}um ${olsty}um
|
||||
}
|
||||
|
||||
# Use catch, because occasionally this fails on startup
|
||||
if {[catch {
|
||||
set olstx [expr {$olstx * $cr}]
|
||||
set olsty [expr {$olsty * $cr}]
|
||||
}]} {
|
||||
*bypass logcommands resume
|
||||
return
|
||||
}
|
||||
|
||||
if {[${win} box exists]} {
|
||||
# I do not know why the T/F result gets lost or overridden sometimes
|
||||
set gotbox [${win} box exists]
|
||||
if {$gotbox == {}} {set gotbox false}
|
||||
if {$gotbox} {
|
||||
set curunits [${win} units list]
|
||||
${win} units microns noprint
|
||||
set dlst [${win} box position]
|
||||
set dx [expr {$olstx - ([lindex $dlst 0]) * $cr }]
|
||||
set dy [expr {$olsty - ([lindex $dlst 1]) * $cr }]
|
||||
|
||||
set dx [expr {$olstx - [lindex $dlst 0]}]
|
||||
set dy [expr {$olsty - [lindex $dlst 1]}]
|
||||
if {[expr {$dx == int($dx)}]} {set dx [expr {int($dx)}]}
|
||||
if {[expr {$dy == int($dy)}]} {set dy [expr {int($dy)}]}
|
||||
set titletext [format "(%+g %+g) %+g %+g microns" $olstx $olsty $dx $dy]
|
||||
${framename}.titlebar.pos configure -text $titletext
|
||||
${win} units {*}$curunits
|
||||
} else {
|
||||
set titletext [format "(%+g %+g) microns" $olstx $olsty]
|
||||
${framename}.titlebar.pos configure -text $titletext
|
||||
|
|
@ -832,8 +828,11 @@ proc magic::setscrollvalues {win} {
|
|||
global Opts
|
||||
|
||||
*bypass logcommands suspend
|
||||
set curunits [units list]
|
||||
units internal noprint
|
||||
set svalues [${win} view get]
|
||||
set bvalues [${win} view bbox]
|
||||
units {*}$curunits
|
||||
|
||||
set framename [winfo parent ${win}]
|
||||
if {$framename == "."} {
|
||||
|
|
@ -910,8 +909,11 @@ proc magic::scrollview { w win orient } {
|
|||
set v2 $scale($orient,update)
|
||||
set delta [expr {$v2 - $v1}]
|
||||
|
||||
set curunits [units list]
|
||||
units internal noprint
|
||||
set bvalues [${win} view bbox]
|
||||
set wvalues [${win} windowpositions]
|
||||
units {*}$curunits
|
||||
|
||||
# Note that adding 0.000 in expression forces floating-point
|
||||
|
||||
|
|
@ -1187,8 +1189,12 @@ proc magic::openwrapper {{cell ""} {framename ""}} {
|
|||
bind ${winname} <Motion> "*bypass setpoint %x %y ${winname}; \
|
||||
magic::cursorview ${winname}"
|
||||
|
||||
set Winopts(${framename},toolbar) 1
|
||||
set Winopts(${framename},cmdentry) 0
|
||||
if {[catch {set Winopts(${framename},toolbar)}]} {
|
||||
set Winopts(${framename},toolbar) 1
|
||||
}
|
||||
if {[catch {set Winopts(${framename},cmdentry)}]} {
|
||||
set Winopts(${framename},cmdentry) $Opts(cmdentry)
|
||||
}
|
||||
|
||||
# #################################
|
||||
# File
|
||||
|
|
@ -1294,7 +1300,17 @@ proc magic::openwrapper {{cell ""} {framename ""}} {
|
|||
$m add command -label "Grid off" -command {magic::grid off}
|
||||
$m add command -label "Snap-to-grid on" -command {magic::snap on}
|
||||
$m add command -label "Snap-to-grid off" -command {magic::snap off}
|
||||
$m add command -label "Measure box" -command {magic::box }
|
||||
$m add command -label "Measure box" -command {magic::box}
|
||||
$m add separator
|
||||
$m add command -label "Report internal units" -command {magic::units internal}
|
||||
$m add command -label "Report lambda units" -command {magic::units lambda}
|
||||
$m add command -label "Report micron units" -command {magic::units microns}
|
||||
$m add command -label "Report grid units" -command {magic::units grid}
|
||||
$m add check -label "Display units" -variable Opts(printunits) \
|
||||
-command [subst {if { \$Opts(printunits) } { \
|
||||
magic::units print } else { magic::units noprint } }]
|
||||
|
||||
|
||||
$m add separator
|
||||
$m add command -label "Set grid 0.05um" -command {magic::grid 0.05um}
|
||||
$m add command -label "Set grid 0.10um" -command {magic::grid 0.10um}
|
||||
|
|
@ -1425,6 +1441,11 @@ proc magic::openwrapper {{cell ""} {framename ""}} {
|
|||
grid ${layoutframe}.toolbar -row 1 -column 2 -rowspan 2 -sticky new
|
||||
}
|
||||
|
||||
# If the command entry window is enabled, create it now
|
||||
if { $Winopts(${framename},cmdentry) == 1} {
|
||||
addcommandentry $framename
|
||||
}
|
||||
|
||||
# Remove "open" and "close" macros so they don't generate non-GUI
|
||||
# windows or (worse) blow away the window inside the GUI frame
|
||||
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ RunStatsRealTime(void)
|
|||
while (inct >= 10) { inct -= 10; incs++; }
|
||||
while (incs >= 60) { incs -= 60; incm++; }
|
||||
|
||||
sprintf(buf, "%ld:%02ld.%ld %ld:%02ld.%ld",
|
||||
snprintf(buf, (size_t)50, "%ld:%02ld.%ld %ld:%02ld.%ld",
|
||||
totm, tots, tott, incm, incs, inct);
|
||||
|
||||
lasttime = curtime;
|
||||
|
|
|
|||
30
utils/tech.c
30
utils/tech.c
|
|
@ -432,7 +432,8 @@ TechLoad(filename, initmask)
|
|||
char suffix[20], line[MAXLINESIZE], *realname;
|
||||
char *argv[MAXARGS];
|
||||
SectionID mask, badMask;
|
||||
int argc, s;
|
||||
int argc, s, repeatcount = 0;
|
||||
off_t repeatpos;
|
||||
bool retval, skip;
|
||||
filestack *fstack, *newstack;
|
||||
filestack topfile;
|
||||
|
|
@ -603,6 +604,33 @@ TechLoad(filename, initmask)
|
|||
skip = FALSE;
|
||||
while ((argc = techGetTokens(line, sizeof line, &fstack, argv)) >= 0)
|
||||
{
|
||||
/* Check for end-of-loop */
|
||||
if ((argc == 1) && (!strcmp(argv[0], "endrepeat")))
|
||||
{
|
||||
if (repeatcount > 0)
|
||||
{
|
||||
repeatcount--;
|
||||
fseek(fstack->file, repeatpos, SEEK_SET);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* "repeat <number>" reads the lines until "endrepeat" <number> times */
|
||||
else if ((argc == 2) && (!strcmp(argv[0], "repeat")))
|
||||
{
|
||||
|
||||
if (!StrIsInt(argv[1]))
|
||||
{
|
||||
TechError("Error: \"repeat\" with invalid count %s\n", argv[1]);
|
||||
repeatcount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
repeatcount = atoi(argv[1]) - 1;
|
||||
repeatpos = ftell(fstack->file);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check for file inclusions (can be nested) */
|
||||
if ((argc > 1) && (!strcmp(argv[0], "include")))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -440,23 +440,52 @@ windCrashCmd(w, cmd)
|
|||
* Side effects:
|
||||
* Prints coordinates (non-Tcl version)
|
||||
* Return value set to the cursor position as a list (Tcl version)
|
||||
*
|
||||
* NOTE: "box position {*}[cursor]" will produce the wrong result if
|
||||
* "units" have been left as default, because "cursor" will generate
|
||||
* internal values and "box position" will expect lambda values. Use
|
||||
* "box move bl cursor" instead.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define CURSOR_INTERNAL 0
|
||||
#define CURSOR_LAMBDA 1
|
||||
#define CURSOR_USER 2
|
||||
#define CURSOR_GRID 3
|
||||
#define CURSOR_MICRONS 4
|
||||
#define CURSOR_WINDOW 5
|
||||
#define CURSOR_SCREEN 6
|
||||
|
||||
void
|
||||
windCursorCmd(w, cmd)
|
||||
MagWindow *w;
|
||||
TxCommand *cmd;
|
||||
{
|
||||
Point p_in, p_out;
|
||||
int resulttype = DBW_SNAP_INTERNAL;
|
||||
int resulttype, saveunits, idx;
|
||||
double cursx, cursy, oscale;
|
||||
char *dispx, *dispy;
|
||||
DBWclientRec *crec;
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_Obj *listxy;
|
||||
#endif
|
||||
|
||||
static const char * const cmdCursorOption[] =
|
||||
{ "internal", "lambda", "user", "grid", "microns", "window", "screen",
|
||||
"units", 0 };
|
||||
|
||||
/* The original behavior was to use internal
|
||||
* units by default. This remains the case
|
||||
* unless units are set with the "units"
|
||||
* command, in which case units follow the
|
||||
* specified units.
|
||||
*/
|
||||
if (DBWUnits == DBW_UNITS_DEFAULT)
|
||||
resulttype = DBW_UNITS_INTERNAL;
|
||||
else
|
||||
resulttype = DBWUnits;
|
||||
|
||||
if (cmd->tx_argc == 2)
|
||||
{
|
||||
if (StrIsInt(cmd->tx_argv[1]))
|
||||
|
|
@ -465,31 +494,35 @@ windCursorCmd(w, cmd)
|
|||
(*GrSetCursorPtr)(atoi(cmd->tx_argv[1]));
|
||||
return;
|
||||
}
|
||||
else if (*cmd->tx_argv[1] == 'l')
|
||||
{
|
||||
resulttype = DBW_SNAP_LAMBDA;
|
||||
}
|
||||
else if (*cmd->tx_argv[1] == 'u')
|
||||
{
|
||||
resulttype = DBW_SNAP_USER;
|
||||
}
|
||||
else if (*cmd->tx_argv[1] == 'm')
|
||||
{
|
||||
resulttype = DBW_SNAP_MICRONS;
|
||||
}
|
||||
else if (*cmd->tx_argv[1] == 'w')
|
||||
{
|
||||
resulttype = -1; // Use this value for "window"
|
||||
}
|
||||
else if (*cmd->tx_argv[1] == 's')
|
||||
{
|
||||
resulttype = -2; // Use this value for "screen"
|
||||
}
|
||||
else if (*cmd->tx_argv[1] != 'i')
|
||||
{
|
||||
TxError("Usage: cursor glyphnum\n");
|
||||
TxError(" (or): cursor [internal | lambda | microns | user | window]\n");
|
||||
return;
|
||||
else {
|
||||
idx = Lookup(cmd->tx_argv[1], cmdCursorOption);
|
||||
switch (idx)
|
||||
{
|
||||
case CURSOR_INTERNAL:
|
||||
resulttype = DBW_UNITS_INTERNAL;
|
||||
break;
|
||||
case CURSOR_LAMBDA:
|
||||
resulttype = DBW_UNITS_LAMBDA;
|
||||
break;
|
||||
case CURSOR_USER:
|
||||
case CURSOR_GRID:
|
||||
resulttype = DBW_UNITS_USER;
|
||||
break;
|
||||
case CURSOR_MICRONS:
|
||||
resulttype = DBW_UNITS_MICRONS;
|
||||
break;
|
||||
case CURSOR_WINDOW:
|
||||
resulttype = -1; // Use this value for "window"
|
||||
break;
|
||||
case CURSOR_SCREEN:
|
||||
resulttype = -2; // Use this value for "screen"
|
||||
break;
|
||||
default:
|
||||
TxError("Usage: cursor glyphnum\n");
|
||||
TxError(" (or): cursor [internal | lambda | microns | user"
|
||||
" | window | units]\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -506,54 +539,37 @@ windCursorCmd(w, cmd)
|
|||
WindPointToSurface(w, &p_in, &p_out, (Rect *)NULL);
|
||||
|
||||
/* Snap the cursor position if snap is in effect */
|
||||
if (DBWSnapToGrid != DBW_SNAP_INTERNAL)
|
||||
if (DBWSnapToGrid != DBW_UNITS_INTERNAL)
|
||||
ToolSnapToGrid(w, &p_out, (Rect *)NULL);
|
||||
}
|
||||
|
||||
/* Transform the result to declared units with option "lambda" or "grid" */
|
||||
switch (resulttype) {
|
||||
case -2:
|
||||
case -1:
|
||||
cursx = (double)p_in.p_x;
|
||||
cursy = (double)p_in.p_y;
|
||||
break;
|
||||
case DBW_SNAP_INTERNAL:
|
||||
cursx = (double)p_out.p_x;
|
||||
cursy = (double)p_out.p_y;
|
||||
break;
|
||||
case DBW_SNAP_LAMBDA:
|
||||
cursx = (double)(p_out.p_x * DBLambda[0]) / (double)DBLambda[1];
|
||||
cursy = (double)(p_out.p_y * DBLambda[0]) / (double)DBLambda[1];
|
||||
break;
|
||||
case DBW_SNAP_MICRONS:
|
||||
oscale = (double)CIFGetOutputScale(1000);
|
||||
cursx = (double)(p_out.p_x * oscale);
|
||||
cursy = (double)(p_out.p_y * oscale);
|
||||
break;
|
||||
case DBW_SNAP_USER:
|
||||
crec = (DBWclientRec *)w->w_clientData;
|
||||
cursx = (double)((p_out.p_x - crec->dbw_gridRect.r_xbot)
|
||||
/ (crec->dbw_gridRect.r_xtop - crec->dbw_gridRect.r_xbot));
|
||||
cursy = (double)((p_out.p_y - crec->dbw_gridRect.r_ybot)
|
||||
/ (crec->dbw_gridRect.r_ytop - crec->dbw_gridRect.r_ybot));
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
listxy = Tcl_NewListObj(0, NULL);
|
||||
if ((cursx == round(cursx)) && (cursy == round(cursy)))
|
||||
saveunits = DBWUnits;
|
||||
if (resulttype < 0)
|
||||
{
|
||||
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewIntObj((int)cursx));
|
||||
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewIntObj((int)cursy));
|
||||
/* Not really internal units, but that prints integer units verbatim */
|
||||
DBWUnits = DBW_UNITS_INTERNAL;
|
||||
cursx = (double)p_in.p_x;
|
||||
cursy = (double)p_in.p_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewDoubleObj(cursx));
|
||||
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewDoubleObj(cursy));
|
||||
DBWUnits = resulttype;
|
||||
cursx = (double)p_out.p_x;
|
||||
cursy = (double)p_out.p_y;
|
||||
}
|
||||
|
||||
dispx = DBWPrintValue(cursx, w, TRUE);
|
||||
dispy = DBWPrintValue(cursy, w, FALSE);
|
||||
DBWUnits = saveunits;
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
listxy = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewStringObj(dispx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewStringObj(dispy, -1));
|
||||
Tcl_SetObjResult(magicinterp, listxy);
|
||||
#else
|
||||
TxPrintf("%g %g\n", cursx, cursy);
|
||||
TxPrintf("%s %s\n", dispx, dispy);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue