Compare commits
69 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
06eab7feb6 | |
|
|
9ade4c931e | |
|
|
1bb5316d8d | |
|
|
2f26237b8b | |
|
|
003506ba62 | |
|
|
d659b5e1df | |
|
|
a0afe242c8 | |
|
|
88ca77f6a4 | |
|
|
9d967bdf64 | |
|
|
7fd2ef8100 | |
|
|
e789f18523 | |
|
|
460a357730 | |
|
|
7ceeccef56 | |
|
|
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 |
|
|
@ -138,6 +138,8 @@ jobs:
|
|||
echo "BUILD_GCC_VERSION=$BUILD_GCC_VERSION" >> $GITHUB_ENV
|
||||
echo "BUILD_CLANG_VERSION=$BUILD_CLANG_VERSION" >> $GITHUB_ENV
|
||||
|
||||
sudo apt-get update
|
||||
|
||||
if [ -n "$BUILD_GCC_VERSION" ]
|
||||
then
|
||||
GCCV=$BUILD_GCC_VERSION
|
||||
|
|
|
|||
|
|
@ -33,10 +33,22 @@ jobs:
|
|||
cd emsdk
|
||||
./emsdk install latest
|
||||
./emsdk activate latest
|
||||
- name: Emscripten Diagnostic
|
||||
run: |
|
||||
source ./emsdk/emsdk_env.sh
|
||||
echo "===== gcc -dM -E - ====="
|
||||
echo | gcc -dM -E - | sort
|
||||
echo "===== g++ -dM -E - ====="
|
||||
echo | g++ -dM -E - | sort
|
||||
echo "===== emcc -dM -E - ====="
|
||||
echo | emcc -dM -E - | sort
|
||||
echo "===== em++ -dM -E - ====="
|
||||
echo | em++ -dM -E - | sort
|
||||
- name: Build
|
||||
run: |
|
||||
source ./emsdk/emsdk_env.sh
|
||||
emconfigure ./configure --without-cairo --without-opengl --without-x --disable-readline --disable-compression --target=asmjs-unknown-emscripten
|
||||
# The --without and --disable in these build options is due to no WASM library being available for that feature
|
||||
CFLAGS="--std=c17 -D_DEFAULT_SOURCE=1 -DEMSCRIPTEN=1 -g" emconfigure ./configure --without-cairo --without-opengl --without-x --without-tk --without-tcl --disable-readline --disable-compression --target=asmjs-unknown-emscripten
|
||||
echo "===== defs.mak ====="
|
||||
cat defs.mak
|
||||
echo "===== defs.mak ====="
|
||||
|
|
|
|||
|
|
@ -10,19 +10,6 @@ on:
|
|||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
vezzal:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ubuntu-latest
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
- name: Pulling the docker image
|
||||
run: docker pull vezzal/vezzal:v1
|
||||
|
||||
- name: Start the container with the docker image
|
||||
run: docker run -id --name test_magic vezzal/vezzal:v1 bash | exit
|
||||
|
||||
- name: Run the testing on the container and send the mail
|
||||
run: docker exec test_magic /vezzal/test_magic.sh "lankasaicharan123@gmail.com,tim@opencircuitdesign.com" ${{secrets.MAILING_KEY}}
|
||||
simple_build_linux:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
|
|
@ -45,10 +32,22 @@ jobs:
|
|||
cd emsdk
|
||||
./emsdk install latest
|
||||
./emsdk activate latest
|
||||
- name: Emscripten Diagnostic
|
||||
run: |
|
||||
source ./emsdk/emsdk_env.sh
|
||||
echo "===== gcc -dM -E - ====="
|
||||
echo | gcc -dM -E - | sort
|
||||
echo "===== g++ -dM -E - ====="
|
||||
echo | g++ -dM -E - | sort
|
||||
echo "===== emcc -dM -E - ====="
|
||||
echo | emcc -dM -E - | sort
|
||||
echo "===== em++ -dM -E - ====="
|
||||
echo | em++ -dM -E - | sort
|
||||
- name: Build
|
||||
run: |
|
||||
source ./emsdk/emsdk_env.sh
|
||||
emconfigure ./configure --without-cairo --without-opengl --without-x --disable-readline --disable-compression --target=asmjs-unknown-emscripten
|
||||
# The --without and --disable in these build options is due to no WASM library being available for that feature
|
||||
CFLAGS="--std=c17 -D_DEFAULT_SOURCE=1 -DEMSCRIPTEN=1 -g" emconfigure ./configure --without-cairo --without-opengl --without-x --without-tk --without-tcl --disable-readline --disable-compression --target=asmjs-unknown-emscripten
|
||||
echo "===== defs.mak ====="
|
||||
cat defs.mak
|
||||
echo "===== defs.mak ====="
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
191
cif/CIFrdcl.c
191
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;
|
||||
}
|
||||
|
|
@ -1677,8 +1786,8 @@ CIFReadCellCleanup(
|
|||
}
|
||||
|
||||
/* Do geometrical processing on the top-level cell. */
|
||||
if (filetype == FILE_CIF) CIFPaintCurrent(filetype);
|
||||
|
||||
CIFPaintCurrent(FILE_CIF);
|
||||
DBAdjustLabels(EditCellUse->cu_def, &TiPlaneRect);
|
||||
DBReComputeBbox(EditCellUse->cu_def);
|
||||
DBWAreaChanged(EditCellUse->cu_def, &EditCellUse->cu_def->cd_bbox,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -779,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
|
||||
|
|
|
|||
|
|
@ -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,13 +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 DOUNIQUE 9
|
||||
#define DOEXTRESIST 10
|
||||
#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
|
||||
|
|
@ -974,13 +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",
|
||||
"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",
|
||||
"resistance extract resistance (same as \"do extresist\")",
|
||||
NULL
|
||||
};
|
||||
static const char * const cmdExtLength[] =
|
||||
|
|
@ -1286,7 +1288,7 @@ CmdExtract(
|
|||
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\n", OPTSET(EXT_DOEXTRESIST));
|
||||
TxPrintf("%s resistance (extresist)\n", OPTSET(EXT_DOEXTRESIST));
|
||||
return;
|
||||
#undef OPTSET
|
||||
}
|
||||
|
|
@ -1317,7 +1319,8 @@ CmdExtract(
|
|||
case DOLABELCHECK: option = EXT_DOLABELCHECK; break;
|
||||
case DOALIASES: option = EXT_DOALIASES; break;
|
||||
case DOUNIQUE: option = EXT_DOUNIQUE; break;
|
||||
case DOEXTRESIST: option = EXT_DOEXTRESIST; 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_value.prop_string);
|
||||
break;
|
||||
case PROPERTY_TYPE_INTEGER:
|
||||
TxPrintf("%s = ", name);
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
TxPrintf("%d ", proprec->prop_value.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_value.prop_double[i]);
|
||||
TxPrintf("\n");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0; /* keep the search alive */
|
||||
|
|
|
|||
|
|
@ -2900,6 +2900,29 @@ 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:
|
||||
|
|
|
|||
|
|
@ -156,6 +156,9 @@ cmdScaleCoord(
|
|||
* "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;
|
||||
|
|
@ -163,19 +166,22 @@ cmdScaleCoord(
|
|||
curunits = DBWUnits & DBW_UNITS_TYPE_MASK;
|
||||
|
||||
if ((*endptr == 'l')
|
||||
|| ((*endptr == '\0') && (curunits == DBW_UNITS_LAMBDA)))
|
||||
|| (((*endptr == '\0') || isspace(*endptr))
|
||||
&& (curunits == DBW_UNITS_LAMBDA)))
|
||||
{
|
||||
/* lambda or default units */
|
||||
dval *= (double)DBLambda[1];
|
||||
dval /= (double)DBLambda[0];
|
||||
}
|
||||
else if ((*endptr == 'i')
|
||||
|| ((*endptr == '\0') && (curunits == DBW_UNITS_INTERNAL)))
|
||||
|| (((*endptr == '\0') || isspace(*endptr))
|
||||
&& (curunits == DBW_UNITS_INTERNAL)))
|
||||
{
|
||||
/* internal units */
|
||||
}
|
||||
else if ((*endptr == 'g')
|
||||
|| ((*endptr == '\0') && (curunits == DBW_UNITS_USER)))
|
||||
|| (((*endptr == '\0') || isspace(*endptr))
|
||||
&& (curunits == DBW_UNITS_USER)))
|
||||
{
|
||||
/* grid units */
|
||||
if (w == (MagWindow *)NULL)
|
||||
|
|
@ -203,11 +209,12 @@ cmdScaleCoord(
|
|||
dval += (double)crec->dbw_gridRect.r_ybot;
|
||||
}
|
||||
}
|
||||
else if (*endptr == '\0' && (curunits == DBW_UNITS_MICRONS))
|
||||
else if (((*endptr == '\0') || isspace(*endptr))
|
||||
&& (curunits == DBW_UNITS_MICRONS))
|
||||
{
|
||||
mscale = 1000;
|
||||
}
|
||||
else
|
||||
else if (*endptr != '\0')
|
||||
{
|
||||
/* natural units referred to the current cifoutput style */
|
||||
if (*(endptr + 1) == 'm')
|
||||
|
|
@ -249,7 +256,7 @@ cmdScaleCoord(
|
|||
mscale = -1;
|
||||
}
|
||||
}
|
||||
if ((mscale != -1) && !isspace(*endptr))
|
||||
if (mscale != -1)
|
||||
dval /= CIFGetOutputScale(mscale);
|
||||
curval = round(dval);
|
||||
|
||||
|
|
@ -297,9 +304,13 @@ cmdScaleCoord(
|
|||
parseop = PARSEOP_DIV;
|
||||
endptr++;
|
||||
break;
|
||||
default:
|
||||
case ' ':
|
||||
case '\t':
|
||||
endptr++;
|
||||
break;
|
||||
default:
|
||||
/* Should this flag an error? */
|
||||
return retval;
|
||||
}
|
||||
if (parseop != PARSEOP_NONE) break;
|
||||
}
|
||||
|
|
@ -750,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))
|
||||
|
|
|
|||
|
|
@ -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,6 +1619,7 @@ dbAbutmentUseFunc(selUse, use, transform, data)
|
|||
{
|
||||
Rect bbox, refbox;
|
||||
Transform *trans;
|
||||
PropertyRecord *proprec;
|
||||
char *propvalue;
|
||||
char *refllx, *reflly, *refurx, *refury;
|
||||
bool found;
|
||||
|
|
@ -1643,14 +1643,25 @@ 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -704,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
|
||||
|
|
@ -736,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 */
|
||||
|
|
@ -921,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();
|
||||
|
||||
|
|
@ -1019,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 -------------------------- */
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
130
drc/DRCbasic.c
130
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,26 @@ 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. */
|
||||
|
||||
/* WARNING: This code cannot be enabled until some method is
|
||||
* worked out to determine if any event resulted in a change
|
||||
* to the DRC check plane which would invalidate the current
|
||||
* search. If so, the search must end immediately and the
|
||||
* area being checked must be reinstated. The code was added
|
||||
* to see how it speeds up the response time of magic when
|
||||
* some of the DRC rules are compute-intensive. It speeds up
|
||||
* performance enough that it is worthwhile to implement the
|
||||
* method just mentioned.
|
||||
*/
|
||||
#if 0
|
||||
UndoEnable();
|
||||
while (Tcl_DoOneEvent(TCL_DONT_WAIT));
|
||||
UndoDisable();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
drcCifCheck(&arg);
|
||||
if (arg.dCD_rlist != NULL) freeMagic(arg.dCD_rlist);
|
||||
|
|
@ -727,6 +777,44 @@ 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 != DRC_EXCEPTION_NONE)
|
||||
{
|
||||
PropertyRecord *proprec;
|
||||
bool propfound, isinside = FALSE;
|
||||
char *name;
|
||||
int idx = cptr->drcc_exception & ~DRC_EXCEPTION_MASK;
|
||||
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 & DRC_EXCEPTION_MASK) == 0))
|
||||
continue;
|
||||
if (isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) != 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 +1224,44 @@ 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 != DRC_EXCEPTION_NONE)
|
||||
{
|
||||
PropertyRecord *proprec;
|
||||
bool propfound, isinside = FALSE;
|
||||
char *name;
|
||||
int idx = cptr->drcc_exception & ~DRC_EXCEPTION_MASK;
|
||||
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_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 & DRC_EXCEPTION_MASK) == 0))
|
||||
continue;
|
||||
if (isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) != 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. */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
202
drc/DRCtech.c
202
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 unsigned char drcCurException = 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,63 @@ 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 an unsigned character containing
|
||||
* the index in the lower 7 bits and a high bit indicating if the rule
|
||||
* is an exception (0) or an exemption (1)).
|
||||
*
|
||||
* Side effects:
|
||||
* Adds to the DRCExceptionList if "name" has not been used before.
|
||||
* Calls StrDup() and increments DRCExceptionSize.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned 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 (unsigned char)i;
|
||||
|
||||
/* Note that i cannot be 127 as this is reserved for DRC_EXCEPTION_NONE */
|
||||
if (i > 126)
|
||||
{
|
||||
/* I would be shocked if this code ever got executed. */
|
||||
TxError("Error: Too many rule exceptions! Limit is 126.\n");
|
||||
return 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 (unsigned char)i;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -571,6 +641,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 +735,7 @@ DRCTechStyleInit()
|
|||
}
|
||||
|
||||
drcCifInit();
|
||||
drcCurException = DRC_EXCEPTION_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -955,6 +1028,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 +1105,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 +1756,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 +3695,84 @@ 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 contains the index in
|
||||
* the lower 7 bits, and a flag in the upper bit (0 = exception rule,
|
||||
* 1 = exemption rule). The index can be recovered by masking off
|
||||
* the upper bit.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
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 = 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 = DRC_EXCEPTION_NONE;
|
||||
else
|
||||
drcCurException = drcExceptionCreate(argv[1]) | DRC_EXCEPTION_MASK;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -4119,6 +4258,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. */
|
||||
unsigned 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,11 @@ typedef struct drccookie
|
|||
#define DRC_UNPROCESSED CLIENTDEFAULT
|
||||
#define DRC_PROCESSED 1
|
||||
|
||||
/* drcc_exception defaults to 255 meaning no exceptions/exemptions */
|
||||
#define DRC_EXCEPTION_NONE ((unsigned char)0xff)
|
||||
/* The high bit of the value determines if this is an exception or an exemption. */
|
||||
#define DRC_EXCEPTION_MASK ((unsigned char)0x80)
|
||||
|
||||
/*
|
||||
* Background DRC (DRC Idle proc) for Tcl-based Magic
|
||||
*/
|
||||
|
|
@ -177,6 +183,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;
|
||||
|
||||
|
|
|
|||
|
|
@ -634,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);
|
||||
|
|
@ -1088,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);
|
||||
}
|
||||
|
|
@ -1138,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -648,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;
|
||||
|
|
@ -2103,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)
|
||||
{
|
||||
|
|
@ -2114,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".
|
||||
|
|
@ -2204,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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,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 */
|
||||
|
|
@ -148,6 +150,7 @@ int extTransTileFunc();
|
|||
int extTransPerimFunc();
|
||||
int extTransFindSubs();
|
||||
int extTransFindId();
|
||||
void extTermAPFunc();
|
||||
|
||||
int extAnnularTileFunc();
|
||||
int extResistorTileFunc();
|
||||
|
|
@ -323,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 */
|
||||
|
|
@ -799,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;
|
||||
}
|
||||
|
|
@ -1679,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;
|
||||
|
|
@ -1812,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)
|
||||
|
|
@ -1943,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 */
|
||||
|
|
@ -2169,8 +2222,6 @@ extTransFindTermArea(tile, dinfo, eapd)
|
|||
TileType dinfo;
|
||||
ExtAreaPerimData *eapd;
|
||||
{
|
||||
void extTermAPFunc(); /* Forward declaration */
|
||||
|
||||
extEnumTerminal(tile, dinfo, DBConnectTbl, extTermAPFunc, (ClientData)eapd);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -2258,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;
|
||||
|
|
@ -2282,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;
|
||||
|
|
@ -3912,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)
|
||||
{
|
||||
|
|
@ -3945,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:
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ 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"
|
||||
|
|
@ -51,7 +50,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
|
||||
/* Forward declarations */
|
||||
int extOutputUsesFunc();
|
||||
FILE *extFileOpen();
|
||||
|
||||
Plane* extCellFile();
|
||||
void extHeader();
|
||||
|
|
@ -97,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);
|
||||
|
||||
|
|
@ -116,25 +114,6 @@ ExtCell(def, outName, doLength)
|
|||
savePlane = extCellFile(def, f, doLength);
|
||||
if (f != NULL) fclose(f);
|
||||
|
||||
/* Integrated extresist --- Run "extresist" on the cell def just
|
||||
* extracted and produce an annotation file "<file>.res.ext".
|
||||
*/
|
||||
|
||||
if (ExtOptions & EXT_DOEXTRESIST)
|
||||
{
|
||||
ResisData *resisdata = ResInit();
|
||||
|
||||
UndoDisable();
|
||||
|
||||
ResOptionsFlags |= ResOpt_Signal;
|
||||
resisdata->mainDef = def;
|
||||
resisdata->savePlanes = (struct saveList *)NULL; /* unused */
|
||||
|
||||
ExtResisForDef(def, resisdata);
|
||||
|
||||
UndoEnable();
|
||||
}
|
||||
|
||||
if (extNumErrors > 0 || extNumWarnings > 0)
|
||||
{
|
||||
TxPrintf("%s:", def->cd_name);
|
||||
|
|
@ -152,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
|
||||
|
|
@ -170,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
|
||||
|
|
@ -615,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,6 +794,23 @@ ExtractOneCell(def, outName, doLength)
|
|||
|
||||
savePlane = ExtCell(def, outName, doLength);
|
||||
|
||||
/* 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);
|
||||
|
|
@ -945,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);
|
||||
|
||||
|
|
@ -991,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)
|
||||
{
|
||||
|
|
@ -1027,6 +1040,44 @@ extExtractStack(stack, doExtract, rootDef)
|
|||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
|
|
|
|||
|
|
@ -614,6 +614,7 @@ termtop:
|
|||
|
||||
termdone:
|
||||
/* (continue) */
|
||||
(void)0; /* older compilers need a statement after the label to prevent a compile error */
|
||||
}
|
||||
|
||||
/* Clean up---Put the ClientData entries in the tiles back to
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -113,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();
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <unistd.h>
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "utils/hash.h"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "windows/windows.h"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
#include <signal.h>
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "windows/windows.h"
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#include <X11/Xlib.h>
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
#include "utils/main.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "windows/windows.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "windows/windows.h"
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#include "utils/main.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "windows/windows.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "windows/windows.h"
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
#include "utils/main.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "windows/windows.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "windows/windows.h"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
#include <X11/Xutil.h>
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "textio/txcommands.h"
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#include <X11/Xlib.h>
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
124
resis/ResMain.c
124
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 ResExtNode *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.
|
||||
*
|
||||
|
|
@ -205,7 +204,7 @@ ResMakePortBreakpoints(def)
|
|||
int ResAddBreakpointFunc(); /* Forward Declaration */
|
||||
|
||||
HashStartSearch(&hs);
|
||||
while((entry = HashNext(&ResNodeTable,&hs)) != NULL)
|
||||
while((entry = HashNext(&ResNodeTable, &hs)) != NULL)
|
||||
{
|
||||
node = (ResExtNode *)HashGetValue(entry);
|
||||
if (node->status & PORTNODE)
|
||||
|
|
@ -266,7 +265,7 @@ 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.
|
||||
*
|
||||
|
|
@ -292,7 +291,7 @@ ResMakeLabelBreakpoints(def, resisdata)
|
|||
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 "resisdata" record, then make sure the tile type */
|
||||
|
|
@ -344,7 +343,7 @@ ResMakeLabelBreakpoints(def, resisdata)
|
|||
*
|
||||
* ResAddBreakpointFunc --
|
||||
*
|
||||
* Add a breakpoint to the "tileJunk" structure of the tile
|
||||
* Add a breakpoint to the "resInfo" structure of the tile
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -355,7 +354,7 @@ ResAddBreakpointFunc(tile, dinfo, node)
|
|||
TileType dinfo; /* (unused) */
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -524,7 +523,7 @@ ResProcessTiles(resisdata, 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
|
||||
*/
|
||||
|
|
@ -542,16 +541,14 @@ ResProcessTiles(resisdata, 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -562,16 +559,15 @@ ResProcessTiles(resisdata, 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)
|
||||
{
|
||||
|
|
@ -583,9 +579,7 @@ ResProcessTiles(resisdata, origin)
|
|||
newstatus = FALSE;
|
||||
}
|
||||
}
|
||||
if (merged & ORIGIN) break;
|
||||
}
|
||||
if (merged & ORIGIN) break;
|
||||
cp->cp_status = newstatus;
|
||||
}
|
||||
}
|
||||
|
|
@ -601,15 +595,15 @@ ResProcessTiles(resisdata, 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);
|
||||
|
|
@ -688,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).
|
||||
*
|
||||
|
|
@ -726,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). */
|
||||
|
||||
|
|
@ -1014,7 +1008,7 @@ ResExtractNet(node, resisdata, cellname)
|
|||
ResDevList = NULL;
|
||||
ResNodeQueue = NULL;
|
||||
ResContactList = NULL;
|
||||
ResOriginNode = NULL;
|
||||
ResNodeAtOrigin = NULL;
|
||||
|
||||
/* Pass back network pointers */
|
||||
|
||||
|
|
@ -1169,7 +1163,7 @@ ResExtractNet(node, resisdata, cellname)
|
|||
|
||||
ResDissolveContacts(ResContactList);
|
||||
|
||||
/* Add "junk" fields to tiles */
|
||||
/* Add "resInfo" fields to tiles */
|
||||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
{
|
||||
|
|
@ -1182,10 +1176,17 @@ ResExtractNet(node, resisdata, 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, resisdata);
|
||||
|
||||
/* Finish preprocessing. */
|
||||
|
||||
ResFindNewContactTiles(ResContactList);
|
||||
ResPreProcessDevices(DevTiles, ResDevList, ResUse->cu_def);
|
||||
|
||||
|
|
@ -1309,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.
|
||||
*
|
||||
|
|
@ -1450,8 +1451,9 @@ FindStartTile(resisdata, 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1471,8 +1473,8 @@ FindStartTile(resisdata, 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1492,8 +1494,8 @@ FindStartTile(resisdata, 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1513,8 +1515,8 @@ FindStartTile(resisdata, 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1527,7 +1529,7 @@ FindStartTile(resisdata, 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))
|
||||
{
|
||||
|
|
@ -1554,12 +1556,12 @@ FindStartTile(resisdata, 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1588,12 +1590,12 @@ FindStartTile(resisdata, 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1622,12 +1624,12 @@ FindStartTile(resisdata, 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1656,12 +1658,12 @@ FindStartTile(resisdata, 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1720,7 +1722,7 @@ FindStartTile(resisdata, 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.
|
||||
*
|
||||
|
|
@ -1756,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)))
|
||||
{
|
||||
|
|
@ -1764,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.
|
||||
*/
|
||||
|
||||
|
|
@ -278,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;
|
||||
}
|
||||
|
||||
|
|
@ -309,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);
|
||||
|
|
@ -319,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))
|
||||
|
|
@ -346,7 +346,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
|||
* their nodes.
|
||||
*/
|
||||
|
||||
p2 = junk->breakList;
|
||||
p2 = info->breakList;
|
||||
|
||||
/* Add extra left area to leftmost node */
|
||||
|
||||
|
|
@ -388,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;
|
||||
|
|
@ -449,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);
|
||||
}
|
||||
|
||||
|
|
@ -482,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;
|
||||
|
||||
|
|
@ -491,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);
|
||||
}
|
||||
|
||||
|
|
@ -503,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)
|
||||
{
|
||||
|
|
@ -525,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;
|
||||
|
|
@ -587,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)
|
||||
{
|
||||
|
|
@ -684,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 &&
|
||||
|
|
@ -703,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
|
||||
{
|
||||
|
|
@ -727,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 &&
|
||||
|
|
@ -743,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
|
||||
{
|
||||
|
|
@ -805,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)));
|
||||
|
|
@ -858,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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -242,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;
|
||||
|
|
@ -280,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;
|
||||
|
|
@ -311,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;
|
||||
|
|
@ -345,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;
|
||||
|
|
@ -376,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;
|
||||
|
|
@ -433,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);
|
||||
|
|
@ -531,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;
|
||||
|
|
@ -580,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;
|
||||
|
||||
|
|
@ -637,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);
|
||||
|
|
@ -654,7 +659,7 @@ 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;
|
||||
|
|
@ -680,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;
|
||||
|
|
@ -703,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,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);
|
||||
|
|
@ -859,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:
|
||||
|
|
@ -871,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;
|
||||
{
|
||||
|
|
@ -896,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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,9 +33,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#define MAXNAME 1000
|
||||
#define KV_TO_mV 1000000
|
||||
|
||||
extern ResExtNode *ResInitializeNode();
|
||||
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -58,7 +55,7 @@ ResPrintExtRes(outextfile, resistors, nodename)
|
|||
int nodenum=0;
|
||||
char newname[MAXNAME];
|
||||
HashEntry *entry;
|
||||
ResExtNode *node, *ResInitializeNode();
|
||||
ResExtNode *node;
|
||||
|
||||
for (; resistors != NULL; resistors = resistors->rr_nextResistor)
|
||||
{
|
||||
|
|
@ -73,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;
|
||||
}
|
||||
|
|
@ -81,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;
|
||||
}
|
||||
|
|
@ -222,7 +219,7 @@ ResPrintExtNode(outextfile, nodelist, node)
|
|||
int nodenum = 0;
|
||||
char newname[MAXNAME+32], tmpname[MAXNAME], *cp;
|
||||
HashEntry *entry;
|
||||
ResExtNode *newnode, *ResInitializeNode();
|
||||
ResExtNode *newnode;
|
||||
bool DoKillNode = TRUE;
|
||||
bool NeedFix = FALSE;
|
||||
resNode *snode;
|
||||
|
|
@ -271,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;
|
||||
}
|
||||
|
|
@ -419,16 +416,16 @@ ResPrintFHNodes(fp, nodelist, nodename, nidx, celldef)
|
|||
else
|
||||
{
|
||||
HashEntry *entry;
|
||||
ResExtNode *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 = (ResExtNode *)HashGetValue(entry);
|
||||
if (simnode != NULL)
|
||||
simnode->status |= REDUNDANT;
|
||||
extnode = (ResExtNode *)HashGetValue(entry);
|
||||
if (extnode != NULL)
|
||||
extnode->status |= REDUNDANT;
|
||||
}
|
||||
resWriteNodeName(fp, nodeptr);
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#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
|
||||
|
|
@ -83,8 +84,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
|
||||
#define MAXDIGIT 20
|
||||
|
||||
ResExtNode *ResInitializeNode();
|
||||
|
||||
ResExtNode *ResOriginalNodes; /*Linked List of Nodes */
|
||||
char RDEV_NOATTR[1] = {'0'};
|
||||
ResFixPoint *ResFixList;
|
||||
|
|
@ -102,7 +101,7 @@ ResFixPoint *ResFixList;
|
|||
*/
|
||||
|
||||
int
|
||||
ResReadExt(char *extfile)
|
||||
ResReadExt(CellDef *def)
|
||||
{
|
||||
char *line = NULL, *argv[128];
|
||||
int result, locresult;
|
||||
|
|
@ -111,30 +110,12 @@ ResReadExt(char *extfile)
|
|||
CellDef *dbdef;
|
||||
ResExtNode *curnode;
|
||||
|
||||
/* Search for the .ext fie in the same way that efReadDef() does. */
|
||||
|
||||
fp = PaOpen(extfile, "r", ".ext", EFSearchPath, EFLibPath, (char **)NULL);
|
||||
if ((fp == NULL) && (dbdef = DBCellLookDef(extfile)) != NULL)
|
||||
{
|
||||
char *filepath, *sptr;
|
||||
|
||||
filepath = StrDup((char **)NULL, dbdef->cd_file);
|
||||
sptr = strrchr(filepath, '/');
|
||||
if (sptr)
|
||||
{
|
||||
*sptr = '\0';
|
||||
fp = PaOpen(extfile, "r", ".ext", filepath, EFLibPath, (char **)NULL);
|
||||
}
|
||||
freeMagic(filepath);
|
||||
}
|
||||
|
||||
/* Try with the standard search path */
|
||||
if ((fp == NULL) && (EFSearchPath == NULL))
|
||||
fp = PaOpen(extfile, "r", ".ext", Path, EFLibPath, (char **)NULL);
|
||||
/* 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", extfile, ".ext");
|
||||
TxError("Cannot open file %s%s\n", def->cd_name, ".ext");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -165,6 +146,15 @@ ResReadExt(char *extfile)
|
|||
*/
|
||||
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;
|
||||
|
|
@ -219,11 +209,18 @@ ResReadNode(int argc, char *argv[])
|
|||
ResExtNode *node;
|
||||
|
||||
entry = HashFind(&ResNodeTable, argv[NODES_NODENAME]);
|
||||
node = ResInitializeNode(entry);
|
||||
node = ResExtInitNode(entry);
|
||||
|
||||
node->location.p_x = atoi(argv[NODES_NODEX]);
|
||||
node->location.p_y = atoi(argv[NODES_NODEY]);
|
||||
node->type = DBTechNameType(argv[NODES_NODETYPE]);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
|
|
@ -254,7 +251,7 @@ ResReadPort(int argc,
|
|||
ResExtNode *node;
|
||||
|
||||
entry = HashFind(&ResNodeTable, argv[PORT_NAME]);
|
||||
node = ResInitializeNode(entry);
|
||||
node = ResExtInitNode(entry);
|
||||
|
||||
node->drivepoint.p_x = atoi(argv[PORT_LLX]);
|
||||
node->drivepoint.p_y = atoi(argv[PORT_LLY]);
|
||||
|
|
@ -334,11 +331,11 @@ ResReadDevice(int argc,
|
|||
TileType ttype;
|
||||
HashEntry *entry;
|
||||
ResExtNode *node;
|
||||
ResValue rpersquare;
|
||||
float wval;
|
||||
|
||||
device = (RDev *)mallocMagic((unsigned)(sizeof(RDev)));
|
||||
|
||||
device->resistance = 0; /* Linear resistance from FET line, unused */
|
||||
|
||||
device->status = FALSE;
|
||||
device->nextDev = ResRDevList;
|
||||
|
||||
|
|
@ -364,10 +361,25 @@ ResReadDevice(int argc,
|
|||
device->drain = (ResExtNode *)NULL;
|
||||
device->subs = (ResExtNode *)NULL;
|
||||
|
||||
/* Pass over parameters and find the next argument */
|
||||
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++)
|
||||
if (!StrIsInt(argv[i]) && !(strchr(argv[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)
|
||||
{
|
||||
|
|
@ -375,6 +387,8 @@ ResReadDevice(int argc,
|
|||
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
|
||||
|
|
@ -447,11 +461,11 @@ ResReadFET(int argc,
|
|||
TileType ttype;
|
||||
HashEntry *entry;
|
||||
ResExtNode *node;
|
||||
ResValue rpersquare;
|
||||
float area, perim, wval, lval;
|
||||
|
||||
device = (RDev *)mallocMagic((unsigned)(sizeof(RDev)));
|
||||
|
||||
device->resistance = 0; /* Linear resistance from FET line, unused */
|
||||
|
||||
device->status = FALSE;
|
||||
device->nextDev = ResRDevList;
|
||||
|
||||
|
|
@ -468,11 +482,25 @@ ResReadFET(int argc,
|
|||
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_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]);
|
||||
|
|
@ -522,19 +550,19 @@ ResReadCapacitor(int argc,
|
|||
ResExtNode *node1, *node2;
|
||||
|
||||
entry1 = HashFind(&ResNodeTable, argv[COUPLETERMINAL1]);
|
||||
node1 = ResInitializeNode(entry1);
|
||||
node1 = ResExtInitNode(entry1);
|
||||
|
||||
if (ResOptionsFlags & ResOpt_Signal)
|
||||
{
|
||||
node1->capacitance += MagAtof(argv[COUPLEVALUE]);
|
||||
entry2 = HashFind(&ResNodeTable, argv[COUPLETERMINAL2]);
|
||||
node2 = ResInitializeNode(entry2);
|
||||
node2 = ResExtInitNode(entry2);
|
||||
node2->capacitance += MagAtof(argv[COUPLEVALUE]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
entry2 = HashFind(&ResNodeTable, argv[COUPLETERMINAL2]);
|
||||
node2 = ResInitializeNode(entry2);
|
||||
node2 = ResExtInitNode(entry2);
|
||||
|
||||
node1->cap_couple += MagAtof(argv[COUPLEVALUE]);
|
||||
node2->cap_couple += MagAtof(argv[COUPLEVALUE]);
|
||||
|
|
@ -611,7 +639,7 @@ ResReadAttribute(ResExtNode *node,
|
|||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResInitializeNode --
|
||||
* ResExtInitNode --
|
||||
* Gets the node corresponding to a given hash table entry. If no
|
||||
* such node exists, one is created.
|
||||
*
|
||||
|
|
@ -623,7 +651,7 @@ ResReadAttribute(ResExtNode *node,
|
|||
*/
|
||||
|
||||
ResExtNode *
|
||||
ResInitializeNode(entry)
|
||||
ResExtInitNode(entry)
|
||||
HashEntry *entry;
|
||||
{
|
||||
ResExtNode *node;
|
||||
|
|
@ -637,7 +665,6 @@ ResInitializeNode(entry)
|
|||
node->status = FALSE;
|
||||
node->forward = (ResExtNode *) NULL;
|
||||
node->capacitance = 0;
|
||||
node->cap_vdd = 0;
|
||||
node->cap_couple = 0;
|
||||
node->resistance = 0;
|
||||
node->type = 0;
|
||||
|
|
@ -648,8 +675,6 @@ ResInitializeNode(entry)
|
|||
node->drivepoint.p_y = INFINITY;
|
||||
node->location.p_x = INFINITY;
|
||||
node->location.p_y = INFINITY;
|
||||
node->rs_sublist[0] = NULL;
|
||||
node->rs_sublist[1] = NULL;
|
||||
}
|
||||
while (node->status & FORWARD)
|
||||
{
|
||||
|
|
|
|||
140
resis/ResRex.c
140
resis/ResRex.c
|
|
@ -30,7 +30,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/utils.h"
|
||||
#include "utils/tech.h"
|
||||
#include "textio/txcommands.h"
|
||||
#include "resis/resis.h"
|
||||
#include "commands/commands.h"
|
||||
#include "resis/resis.h"
|
||||
|
||||
#define INITFLATSIZE 1024
|
||||
#define MAXNAME 1000
|
||||
|
|
@ -70,10 +71,6 @@ FILE *ResFHFile;
|
|||
|
||||
int ResPortIndex; /* Port ordering to backannotate into magic */
|
||||
|
||||
/* external declarations */
|
||||
extern ResExtNode *ResInitializeNode();
|
||||
extern CellUse *CmdGetSelectedCell();
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -114,7 +111,7 @@ ExtResisForDef(celldef, resisdata)
|
|||
|
||||
HashInit(&ResNodeTable, INITFLATSIZE, HT_STRINGKEYS);
|
||||
/* Read in the .ext file */
|
||||
result = (ResReadExt(celldef->cd_name) == 0);
|
||||
result = (ResReadExt(celldef) == 0);
|
||||
|
||||
/* Clean up the EFDevTypes table */
|
||||
for (idx = 0; idx < EFDevNumTypes; idx++) freeMagic(EFDevTypes[idx]);
|
||||
|
|
@ -131,7 +128,7 @@ ExtResisForDef(celldef, resisdata)
|
|||
DBIsSubcircuit(celldef))
|
||||
ResCheckExtNodes(celldef, resisdata);
|
||||
|
||||
if (ResOptionsFlags & ResOpt_Stat)
|
||||
if (ResOptionsFlags & ResOpt_Stats)
|
||||
ResPrintStats((ResisData *)NULL, "");
|
||||
}
|
||||
|
||||
|
|
@ -280,10 +277,11 @@ CmdExtResis(win, cmd)
|
|||
"ignore names don't extract these nets",
|
||||
"include names extract only these nets",
|
||||
"box type extract the signal under the box on layer type",
|
||||
"cell cellname extract the network for the cell named cellname",
|
||||
"cell cellname extract the network for the cell named cellname",
|
||||
"blackbox [on/off] treat subcircuits with ports as black boxes",
|
||||
"fasthenry [freq] extract subcircuit network geometry into .fh file",
|
||||
"fasthenry [freq] extract subcircuit network geometry into .fh file",
|
||||
"geometry extract network centerline geometry (experimental)",
|
||||
"stats print extresist statistics",
|
||||
"help print this message",
|
||||
NULL
|
||||
};
|
||||
|
|
@ -293,8 +291,8 @@ typedef enum {
|
|||
RES_THRESH, RES_TOL,
|
||||
RES_SIMP, RES_EXTOUT, RES_LUMPED, RES_SILENT,
|
||||
RES_SKIP, RES_IGNORE, RES_INCLUDE, RES_BOX, RES_CELL,
|
||||
RES_BLACKBOX, RES_FASTHENRY, RES_GEOMETRY, RES_HELP,
|
||||
RES_RUN
|
||||
RES_BLACKBOX, RES_FASTHENRY, RES_GEOMETRY, RES_STATS,
|
||||
RES_HELP, RES_RUN
|
||||
} ResOptions;
|
||||
|
||||
resisdata = ResInit();
|
||||
|
|
@ -324,7 +322,6 @@ typedef enum {
|
|||
switch (option)
|
||||
{
|
||||
case RES_TOL:
|
||||
ResOptionsFlags |= ResOpt_ExplicitRtol;
|
||||
if (cmd->tx_argc > 2)
|
||||
{
|
||||
resisdata->tdiTolerance = MagAtof(cmd->tx_argv[2]);
|
||||
|
|
@ -412,6 +409,23 @@ typedef enum {
|
|||
ResOptionsFlags &= ~ResOpt_Blackbox;
|
||||
}
|
||||
return;
|
||||
case RES_STATS:
|
||||
if (cmd->tx_argc == 2)
|
||||
{
|
||||
value = (ResOptionsFlags & ResOpt_Stats) ?
|
||||
TRUE : FALSE;
|
||||
TxPrintf("%s\n", onOff[value]);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = Lookup(cmd->tx_argv[2], onOff);
|
||||
|
||||
if (value)
|
||||
ResOptionsFlags |= ResOpt_Stats;
|
||||
else
|
||||
ResOptionsFlags &= ~ResOpt_Stats;
|
||||
}
|
||||
return;
|
||||
case RES_SIMP:
|
||||
if (cmd->tx_argc == 2)
|
||||
{
|
||||
|
|
@ -784,7 +798,7 @@ resPortFunc(scx, lab, tpath, result)
|
|||
sprintf(nodename, "%s/%s", scx->scx_use->cu_id, lab->lab_text);
|
||||
|
||||
entry = HashFind(&ResNodeTable, nodename);
|
||||
node = ResInitializeNode(entry);
|
||||
node = ResExtInitNode(entry);
|
||||
|
||||
/* Digital outputs are drivers */
|
||||
if (pclass == PORT_CLASS_OUTPUT) node->status |= FORCE;
|
||||
|
|
@ -916,7 +930,7 @@ ResCheckPorts(cellDef)
|
|||
/* We have to make sure it's listed as a separate node */
|
||||
/* and a drivepoint. */
|
||||
|
||||
node = ResInitializeNode(entry);
|
||||
node = ResExtInitNode(entry);
|
||||
TxPrintf("Port: name = %s is new node %p\n",
|
||||
lab->lab_text, (void *)node);
|
||||
TxPrintf("Location is (%d, %d); drivepoint (%d, %d)\n",
|
||||
|
|
@ -1043,20 +1057,17 @@ ResProcessNode(
|
|||
}
|
||||
}
|
||||
|
||||
/* special handling for FORCE and DRIVELOC labels: */
|
||||
/* set minRes = node->minsizeres if it exists, 0 otherwise */
|
||||
/* Special handling for FORCE and DRIVELOC labels: */
|
||||
/* Set minRes = node->minsizeres if it exists, 0 otherwise. */
|
||||
|
||||
if (node->status & (FORCE|DRIVELOC))
|
||||
{
|
||||
if (node->status & MINSIZE)
|
||||
{
|
||||
minRes = node->minsizeres;
|
||||
}
|
||||
else
|
||||
{
|
||||
minRes = 0;
|
||||
}
|
||||
if (node->status & DRIVELOC)
|
||||
|
||||
if (node->status & DRIVELOC)
|
||||
{
|
||||
resisdata->rg_devloc = &node->drivepoint;
|
||||
resisdata->rg_status |= DRIVEONLY;
|
||||
|
|
@ -1274,42 +1285,44 @@ ResCheckExtNodes(celldef, resisdata)
|
|||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResFixUpConnections-- Changes the connection to a terminal of the sim
|
||||
* device. The new name is formed by appending .t# to the old name.
|
||||
* ResFixUpConnections--
|
||||
* Changes the connection to a terminal of a device.
|
||||
* The new name is formed by appending .t# to the old name.
|
||||
* The new name is added to the hash table of node names.
|
||||
*
|
||||
* Results:none
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side Effects: Allocates new ResExtNodes. Modifies the terminal connections
|
||||
* of ext Devices.
|
||||
* Side Effects:
|
||||
* Allocates new ResExtNodes. Modifies the terminal connections
|
||||
* of devices.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
||||
RDev *simDev;
|
||||
ResFixUpConnections(extDev, layoutDev, extNode, nodename)
|
||||
RDev *extDev;
|
||||
resDevice *layoutDev;
|
||||
ResExtNode *simNode;
|
||||
ResExtNode *extNode;
|
||||
char *nodename;
|
||||
|
||||
{
|
||||
static char newname[MAXNAME], oldnodename[MAXNAME];
|
||||
int notdecremented;
|
||||
resNode *gate, *source, *drain, *subs;
|
||||
|
||||
/* If we aren't doing output (i.e. this is just a statistical run) */
|
||||
/* If we aren't doing output (i.e. this is just a statistical run) */
|
||||
/* don't patch up networks. This cuts down on memory use. */
|
||||
|
||||
if ((ResOptionsFlags & (ResOpt_DoRsmFile | ResOpt_DoExtFile)) == 0)
|
||||
if ((ResOptionsFlags & ResOpt_DoExtFile) == 0)
|
||||
return;
|
||||
|
||||
if (simDev->layout == NULL)
|
||||
if (extDev->layout == NULL)
|
||||
{
|
||||
layoutDev->rd_status |= RES_DEV_SAVE;
|
||||
simDev->layout = layoutDev;
|
||||
extDev->layout = layoutDev;
|
||||
}
|
||||
simDev->status |= TRUE;
|
||||
extDev->status |= TRUE;
|
||||
if (strcmp(nodename, oldnodename) != 0)
|
||||
{
|
||||
strcpy(oldnodename, nodename);
|
||||
|
|
@ -1317,7 +1330,7 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++);
|
||||
notdecremented = TRUE;
|
||||
|
||||
if (simDev->gate == simNode)
|
||||
if (extDev->gate == extNode)
|
||||
{
|
||||
if ((gate = layoutDev->rd_fet_gate) != NULL)
|
||||
{
|
||||
|
|
@ -1329,8 +1342,8 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
notdecremented = FALSE;
|
||||
}
|
||||
|
||||
ResFixDevName(newname, GATE, simDev, gate);
|
||||
gate->rn_name = simDev->gate->name;
|
||||
ResFixDevName(newname, GATE, extDev, gate);
|
||||
gate->rn_name = extDev->gate->name;
|
||||
sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++);
|
||||
}
|
||||
else
|
||||
|
|
@ -1338,10 +1351,10 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
TxError("Missing gate connection of device at (%d %d) on net %s\n",
|
||||
layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
|
||||
nodename);
|
||||
simNode->status |= DONTKILL;
|
||||
extNode->status |= DONTKILL;
|
||||
}
|
||||
}
|
||||
if (simDev->subs == simNode)
|
||||
if (extDev->subs == extNode)
|
||||
{
|
||||
if ((subs = layoutDev->rd_fet_subs) != NULL)
|
||||
{
|
||||
|
|
@ -1350,8 +1363,8 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
resNodeNum--;
|
||||
notdecremented = FALSE;
|
||||
}
|
||||
ResFixDevName(newname, SUBS, simDev, subs);
|
||||
subs->rn_name = simDev->subs->name;
|
||||
ResFixDevName(newname, SUBS, extDev, subs);
|
||||
subs->rn_name = extDev->subs->name;
|
||||
sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++);
|
||||
}
|
||||
else
|
||||
|
|
@ -1359,11 +1372,11 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
TxError("Missing substrate connection of device at (%d %d) on net %s\n",
|
||||
layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
|
||||
nodename);
|
||||
simNode->status |= DONTKILL;
|
||||
extNode->status |= DONTKILL;
|
||||
}
|
||||
}
|
||||
|
||||
if (simDev->source == simNode)
|
||||
if (extDev->source == extNode)
|
||||
{
|
||||
/* Check for devices with only one terminal. If it was cast as drain, */
|
||||
/* then swap it with the source so that the code below handles it */
|
||||
|
|
@ -1375,13 +1388,13 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
layoutDev->rd_fet_drain = (struct resnode *)NULL;
|
||||
}
|
||||
|
||||
if (simDev->drain == simNode)
|
||||
if (extDev->drain == extNode)
|
||||
{
|
||||
if ((layoutDev->rd_fet_source != NULL) &&
|
||||
(layoutDev->rd_fet_drain == NULL))
|
||||
{
|
||||
/* Handle source/drain-tied devices */
|
||||
if (simDev->drain == simDev->source)
|
||||
if (extDev->drain == extDev->source)
|
||||
layoutDev->rd_fet_drain = layoutDev->rd_fet_source;
|
||||
}
|
||||
|
||||
|
|
@ -1393,12 +1406,12 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
resNodeNum--;
|
||||
notdecremented = FALSE;
|
||||
}
|
||||
ResFixDevName(newname, SOURCE, simDev, source);
|
||||
source->rn_name = simDev->source->name;
|
||||
ResFixDevName(newname, SOURCE, extDev, source);
|
||||
source->rn_name = extDev->source->name;
|
||||
(void)sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++);
|
||||
if (drain->rn_name != NULL) resNodeNum--;
|
||||
ResFixDevName(newname, DRAIN, simDev, drain);
|
||||
drain->rn_name = simDev->drain->name;
|
||||
ResFixDevName(newname, DRAIN, extDev, drain);
|
||||
drain->rn_name = extDev->drain->name;
|
||||
/* one to each */
|
||||
}
|
||||
else
|
||||
|
|
@ -1406,7 +1419,7 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
TxError("Missing terminal connection of device at (%d %d) on net %s\n",
|
||||
layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
|
||||
nodename);
|
||||
simNode->status |= DONTKILL;
|
||||
extNode->status |= DONTKILL;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1417,7 +1430,7 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
{
|
||||
if (source != drain)
|
||||
{
|
||||
if (drain->rn_why & RES_NODE_ORIGIN)
|
||||
if (drain->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK))
|
||||
{
|
||||
ResMergeNodes(drain, source, &ResNodeQueue,
|
||||
&ResNodeList);
|
||||
|
|
@ -1443,8 +1456,8 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
notdecremented = FALSE;
|
||||
}
|
||||
}
|
||||
ResFixDevName(newname, SOURCE, simDev, source);
|
||||
source->rn_name = simDev->source->name;
|
||||
ResFixDevName(newname, SOURCE, extDev, source);
|
||||
source->rn_name = extDev->source->name;
|
||||
|
||||
}
|
||||
else
|
||||
|
|
@ -1452,11 +1465,11 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
TxError("Missing terminal connection of device at (%d %d) on net %s\n",
|
||||
layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
|
||||
nodename);
|
||||
simNode->status |= DONTKILL;
|
||||
extNode->status |= DONTKILL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (simDev->drain == simNode)
|
||||
else if (extDev->drain == extNode)
|
||||
{
|
||||
/* Check for devices with only one terminal. If it was cast as source, */
|
||||
/* then swap it with the drain so that the code below handles it */
|
||||
|
|
@ -1474,7 +1487,7 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
{
|
||||
if (drain != source)
|
||||
{
|
||||
if (source->rn_why & ORIGIN)
|
||||
if (source->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK))
|
||||
{
|
||||
ResMergeNodes(source, drain, &ResNodeQueue,
|
||||
&ResNodeList);
|
||||
|
|
@ -1504,15 +1517,15 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename)
|
|||
notdecremented = FALSE;
|
||||
}
|
||||
}
|
||||
ResFixDevName(newname, DRAIN, simDev, drain);
|
||||
drain->rn_name = simDev->drain->name;
|
||||
ResFixDevName(newname, DRAIN, extDev, drain);
|
||||
drain->rn_name = extDev->drain->name;
|
||||
}
|
||||
else
|
||||
{
|
||||
TxError("Missing terminal connection of device at (%d %d) on net %s\n",
|
||||
layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
|
||||
nodename);
|
||||
simNode->status |= DONTKILL;
|
||||
extNode->status |= DONTKILL;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1548,13 +1561,13 @@ ResFixDevName(line, type, device, layoutnode)
|
|||
if (layoutnode->rn_name != NULL)
|
||||
{
|
||||
entry = HashFind(&ResNodeTable, layoutnode->rn_name);
|
||||
node = ResInitializeNode(entry);
|
||||
node = ResExtInitNode(entry);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = HashFind(&ResNodeTable, line);
|
||||
node = ResInitializeNode(entry);
|
||||
node = ResExtInitNode(entry);
|
||||
}
|
||||
tptr = (devPtr *) mallocMagic((unsigned) (sizeof(devPtr)));
|
||||
tptr->thisDev = device;
|
||||
|
|
@ -1825,6 +1838,9 @@ ResWriteExtFile(celldef, node, resisdata, nidx, eidx)
|
|||
node->name, resisdata->rg_Tdi / Z_TO_P, RCdev / Z_TO_P);
|
||||
}
|
||||
}
|
||||
else
|
||||
TxPrintf("Adding %s\n", node->name);
|
||||
|
||||
for (ptr = node->firstDev; ptr != NULL; ptr=ptr->nextDev)
|
||||
{
|
||||
if ((layoutDev = ResGetDevice(&ptr->thisDev->location, ptr->thisDev->rs_ttype)))
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -527,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;
|
||||
|
|
@ -541,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);
|
||||
|
|
@ -640,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;
|
||||
|
|
@ -897,7 +898,7 @@ ResDoSimplify(tolerance,resisdata)
|
|||
------*/
|
||||
}
|
||||
|
||||
if (ResOriginNode == NULL)
|
||||
if (ResNodeAtOrigin == NULL)
|
||||
{
|
||||
TxError("Error: Network simplification: Failed to to get origin node.\n");
|
||||
resisdata->rg_Tdi = 0;
|
||||
|
|
@ -905,12 +906,12 @@ ResDoSimplify(tolerance,resisdata)
|
|||
else if (ResOptionsFlags & ResOpt_Tdi)
|
||||
{
|
||||
if ((resisdata->rg_nodecap != -1) &&
|
||||
(totalcap = ResCalculateChildCapacitance(ResOriginNode)) != -1)
|
||||
(totalcap = ResCalculateChildCapacitance(ResNodeAtOrigin)) != -1)
|
||||
{
|
||||
RCDelayStuff *rc = (RCDelayStuff *) ResNodeList->rn_client;
|
||||
|
||||
resisdata->rg_nodecap = totalcap;
|
||||
ResCalculateTDi(ResOriginNode, (resResistor *)NULL,
|
||||
ResCalculateTDi(ResNodeAtOrigin, (resResistor *)NULL,
|
||||
resisdata->rg_bigdevres);
|
||||
if (rc != (RCDelayStuff *)NULL)
|
||||
resisdata->rg_Tdi = rc->rc_Tdi;
|
||||
|
|
@ -927,7 +928,7 @@ ResDoSimplify(tolerance,resisdata)
|
|||
resisdata->rg_Tdi = rc->rc_Tdi;
|
||||
}
|
||||
}
|
||||
slownode->rn_status |= RN_MAXTDI;
|
||||
slownode->rn_status |= RES_MAXTDI;
|
||||
}
|
||||
else
|
||||
resisdata->rg_Tdi = -1;
|
||||
|
|
@ -957,11 +958,11 @@ ResDoSimplify(tolerance,resisdata)
|
|||
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. */
|
||||
|
|
@ -970,22 +971,22 @@ ResDoSimplify(tolerance,resisdata)
|
|||
resisdata->rg_Tdi != -1 &&
|
||||
rctol != 0)
|
||||
{
|
||||
ResPruneTree(ResOriginNode, (rctol + 1) *
|
||||
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);
|
||||
|
||||
|
|
@ -1022,16 +1023,16 @@ ResSetPathRes(ResisData *resisdata)
|
|||
{
|
||||
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(resisdata->rg_devloc, resisdata->rg_ttype);
|
||||
if (res == (resDevice *)NULL)
|
||||
|
|
@ -1042,12 +1043,12 @@ ResSetPathRes(ResisData *resisdata)
|
|||
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow *)NULL, FALSE));
|
||||
return;
|
||||
}
|
||||
ResOriginNode = res->rd_fet_source;
|
||||
ResOriginNode->rn_why = RES_NODE_ORIGIN;
|
||||
ResOriginNode->rn_noderes = 0;
|
||||
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);
|
||||
}
|
||||
|
|
@ -1058,7 +1059,7 @@ ResSetPathRes(ResisData *resisdata)
|
|||
*
|
||||
* 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.
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -1070,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;
|
||||
|
|
@ -1078,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);
|
||||
}
|
||||
|
|
@ -1114,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;
|
||||
}
|
||||
|
|
|
|||
423
resis/resis.h
423
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 */
|
||||
|
|
@ -81,7 +70,7 @@ 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 */
|
||||
|
|
@ -91,8 +80,8 @@ typedef struct device
|
|||
} 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
|
||||
{
|
||||
|
|
@ -104,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
|
||||
|
|
@ -117,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
|
||||
{
|
||||
|
|
@ -153,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;
|
||||
|
|
@ -194,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
|
||||
{
|
||||
|
|
@ -208,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
|
||||
{
|
||||
|
|
@ -244,9 +234,11 @@ typedef struct resdevtile
|
|||
int overlap;
|
||||
} ResDevTile;
|
||||
|
||||
/* 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. */
|
||||
/*
|
||||
* 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;
|
||||
|
|
@ -292,8 +284,7 @@ typedef struct rcdelaystuff
|
|||
float rc_Tdi; /* Tdi for node */
|
||||
} RCDelayStuff;
|
||||
|
||||
|
||||
/* Type declarations */
|
||||
/* More type declarations */
|
||||
|
||||
typedef struct rdev
|
||||
{
|
||||
|
|
@ -319,45 +310,38 @@ typedef struct rdev
|
|||
|
||||
typedef struct resextnode
|
||||
{
|
||||
struct resextnode *nextnode; /* next node in OriginalNodes */
|
||||
struct resextnode *nextnode; /* next node in OriginalNodes */
|
||||
/* linked list. */
|
||||
int status;
|
||||
struct resextnode *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 */
|
||||
} 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
|
||||
{
|
||||
|
|
@ -378,144 +362,129 @@ typedef struct resfixpoint /* Keeps track of where voltage sources are */
|
|||
char fp_name[1];
|
||||
} ResFixPoint;
|
||||
|
||||
/*
|
||||
* 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_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
|
||||
/* 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) */
|
||||
|
||||
/* 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_CMOS 0x00800000
|
||||
#define ResOpt_Bipolar 0x01000000
|
||||
#define ResOpt_Box 0x02000000
|
||||
|
||||
#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 */
|
||||
|
||||
|
|
@ -533,7 +502,7 @@ 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 ResExtDevTable;
|
||||
|
|
@ -548,6 +517,7 @@ extern TileTypeBitMask ResNoMergeMask[NT];
|
|||
extern int ResPortIndex;
|
||||
|
||||
/* Routines used by ResReadExt() */
|
||||
|
||||
extern ResisData *ResInit();
|
||||
extern int ResReadDevice();
|
||||
extern int ResReadCapacitor();
|
||||
|
|
@ -559,12 +529,14 @@ 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 *ResGetDevice();
|
||||
extern tileJunk *resAddField();
|
||||
extern resInfo *resAddField();
|
||||
extern int ResCheckPorts();
|
||||
extern int ResCheckBlackbox();
|
||||
extern void ResCheckExtNodes();
|
||||
|
|
@ -575,12 +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();
|
||||
|
|
@ -622,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;\
|
||||
|
|
@ -642,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); \
|
||||
|
|
@ -669,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
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -684,7 +684,10 @@ proc magic::cursorview {win} {
|
|||
*bypass crosshair ${olstx}um ${olsty}um
|
||||
}
|
||||
|
||||
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]
|
||||
|
|
@ -825,9 +828,9 @@ proc magic::setscrollvalues {win} {
|
|||
global Opts
|
||||
|
||||
*bypass logcommands suspend
|
||||
set svalues [${win} view get]
|
||||
set curunits [units list]
|
||||
units internal noprint
|
||||
set svalues [${win} view get]
|
||||
set bvalues [${win} view bbox]
|
||||
units {*}$curunits
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
#ifndef _MAGIC__TEXTIO__TEXTIO_H
|
||||
#define _MAGIC__TEXTIO__TEXTIO_H
|
||||
|
||||
#include <stdarg.h> /* va_list */
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/dqueue.h" /* DQueue */
|
||||
|
||||
|
|
|
|||
|
|
@ -42,20 +42,6 @@ typedef struct {
|
|||
#define TX_PROMPT '>'
|
||||
#define TX_CMD_PROMPT ":"
|
||||
|
||||
/* all of the state associated with a tty terminal */
|
||||
#if !defined(SYSV) && !defined(CYGWIN) && !defined(__OpenBSD__) && !defined(EMSCRIPTEN)
|
||||
#if defined(HAVE_SYS_IOCTL_COMPAT_H) || defined(HAVE_SGTTY_H)
|
||||
#if defined(HAVE_SYS_IOCTL_COMPAT_H)
|
||||
#include <sys/ioctl_compat.h> /* replaced sgtty.h */
|
||||
#elif defined(HAVE_SGTTY_H)
|
||||
#include <sgtty.h>/* legacy - struct sgttyb{} defn */
|
||||
#endif
|
||||
typedef struct {
|
||||
struct sgttyb tx_i_sgtty;
|
||||
struct tchars tx_i_tchars;
|
||||
} txTermState;
|
||||
#endif /* HAVE_SYS_IOCTL_COMPAT_H || HAVE_SGTTY_H */
|
||||
#endif /* SYSV */
|
||||
|
||||
extern bool TxGetInputEvent(bool block, bool returnOnSigWinch);
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ static char rcsid[] __attribute__ ((unused)) ="$Header: /usr/cvsroot/magic-8.0/t
|
|||
#endif
|
||||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/magic.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
|
|
|
|||
125
textio/txInput.c
125
textio/txInput.c
|
|
@ -32,14 +32,13 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <dirent.h>
|
||||
|
||||
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/main.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "textio/txcommands.h"
|
||||
#include "textio/textioInt.h"
|
||||
#include "utils/magsgtty.h" /* txTermState */
|
||||
#include "utils/dqueue.h"
|
||||
#include "utils/macros.h"
|
||||
#include "utils/hash.h"
|
||||
|
|
@ -1225,36 +1224,21 @@ TxGetLine(
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#if defined(SYSV) || defined(CYGWIN)
|
||||
|
||||
void
|
||||
txGetTermState(
|
||||
struct termio *buf)
|
||||
{
|
||||
ioctl( fileno( stdin ), TCGETA, buf);
|
||||
}
|
||||
|
||||
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
|
||||
void
|
||||
txGetTermState(
|
||||
struct termios *buf)
|
||||
{
|
||||
(void) tcgetattr(fileno(stdin), buf);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void
|
||||
txGetTermState(
|
||||
txTermState *buf)
|
||||
{
|
||||
#if defined(HAVE_TERMIOS_H)
|
||||
(void) tcgetattr(fileno(stdin), &buf->termios);
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
ioctl(fileno(stdin), TCGETA, &buf->termio);
|
||||
#else /* sgtty */
|
||||
ASSERT(TxStdinIsatty, "txGetTermState");
|
||||
/* save the current terminal characteristics */
|
||||
(void) ioctl(fileno(stdin), TIOCGETP, (char *) &(buf->tx_i_sgtty) );
|
||||
(void) ioctl(fileno(stdin), TIOCGETC, (char *) &(buf->tx_i_tchars) );
|
||||
(void) ioctl(fileno(stdin), TIOCGETP, (char *) &buf->tx_i_sgtty);
|
||||
(void) ioctl(fileno(stdin), TIOCGETC, (char *) &buf->tx_i_tchars);
|
||||
#endif
|
||||
}
|
||||
#endif /* SYSV */
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -1273,24 +1257,17 @@ txGetTermState(
|
|||
|
||||
void
|
||||
txSetTermState(
|
||||
#if defined(SYSV) || defined(CYGWIN)
|
||||
struct termio *buf
|
||||
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
struct termios *buf
|
||||
#else
|
||||
txTermState *buf
|
||||
#endif /* SYSV */
|
||||
)
|
||||
txTermState *buf)
|
||||
{
|
||||
#if defined(SYSV) || defined(CYGWIN)
|
||||
ioctl( fileno(stdin), TCSETAF, buf );
|
||||
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
(void) tcsetattr( fileno(stdin), TCSANOW, buf );
|
||||
#else
|
||||
#if defined(HAVE_TERMIOS_H)
|
||||
(void) tcsetattr(fileno(stdin), TCSANOW, &buf->termios);
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
ioctl(fileno(stdin), TCSETAF, &buf->termio);
|
||||
#else /* sgtty */
|
||||
/* set the current terminal characteristics */
|
||||
(void) ioctl(fileno(stdin), TIOCSETN, (char *) &(buf->tx_i_sgtty) );
|
||||
(void) ioctl(fileno(stdin), TIOCSETC, (char *) &(buf->tx_i_tchars) );
|
||||
#endif /* SYSV */
|
||||
(void) ioctl(fileno(stdin), TIOCSETN, (char *) &buf->tx_i_sgtty);
|
||||
(void) ioctl(fileno(stdin), TIOCSETC, (char *) &buf->tx_i_tchars);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1313,37 +1290,27 @@ txSetTermState(
|
|||
|
||||
void
|
||||
txInitTermRec(
|
||||
#if defined(SYSV) || defined(CYGWIN)
|
||||
struct termio *buf
|
||||
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
struct termios *buf
|
||||
#else
|
||||
txTermState *buf
|
||||
#endif /* SYSV */
|
||||
)
|
||||
txTermState *buf)
|
||||
{
|
||||
#if defined(SYSV) || defined(CYGWIN) || defined(__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
buf->c_lflag = ISIG; /* raw: no echo and no processing, allow signals */
|
||||
buf->c_cc[ VMIN ] = 1;
|
||||
buf->c_cc[ VTIME ] = 0;
|
||||
#else
|
||||
#if defined(HAVE_TERMIOS_H)
|
||||
buf->termios.c_lflag = ISIG; /* raw: no echo and no processing, allow signals */
|
||||
buf->termios.c_cc[ VMIN ] = 1;
|
||||
buf->termios.c_cc[ VTIME ] = 0;
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
buf->termio.c_lflag = ISIG; /* raw: no echo and no processing, allow signals */
|
||||
buf->termio.c_cc[ VMIN ] = 1;
|
||||
buf->termio.c_cc[ VTIME ] = 0;
|
||||
#else /* sgtty */
|
||||
/* set things up for us, turn off echo, turn on cbreak, no EOF */
|
||||
buf->tx_i_sgtty.sg_flags |= CBREAK;
|
||||
buf->tx_i_sgtty.sg_flags &= ~ECHO;
|
||||
buf->tx_i_tchars.t_eofc = -1;
|
||||
|
||||
#endif /* SYSV */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if defined(SYSV) || defined(CYGWIN)
|
||||
struct termio closeTermState;
|
||||
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
struct termios closeTermState;
|
||||
#else
|
||||
static txTermState closeTermState;
|
||||
#endif /* SYSV */
|
||||
|
||||
static bool haveCloseState = FALSE;
|
||||
|
||||
|
|
@ -1366,21 +1333,21 @@ static bool haveCloseState = FALSE;
|
|||
void
|
||||
txSaveTerm(void)
|
||||
{
|
||||
#if defined(SYSV) || defined(CYGWIN)
|
||||
ioctl( fileno( stdin ), TCGETA, &closeTermState);
|
||||
txEraseChar = closeTermState.c_cc[VERASE];
|
||||
txKillChar = closeTermState.c_cc[VKILL];
|
||||
TxEOFChar = closeTermState.c_cc[VEOF];
|
||||
TxInterruptChar = closeTermState.c_cc[VINTR];
|
||||
#if defined(HAVE_TERMIOS_H)
|
||||
(void) tcgetattr(fileno(stdin), &closeTermState.termios);
|
||||
txEraseChar = closeTermState.termios.c_cc[VERASE];
|
||||
txKillChar = closeTermState.termios.c_cc[VKILL];
|
||||
TxEOFChar = closeTermState.termios.c_cc[VEOF];
|
||||
TxInterruptChar = closeTermState.termios.c_cc[VINTR];
|
||||
haveCloseState = TRUE;
|
||||
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
(void) tcgetattr( fileno( stdin ), &closeTermState);
|
||||
txEraseChar = closeTermState.c_cc[VERASE];
|
||||
txKillChar = closeTermState.c_cc[VKILL];
|
||||
TxEOFChar = closeTermState.c_cc[VEOF];
|
||||
TxInterruptChar = closeTermState.c_cc[VINTR];
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
ioctl(fileno(stdin), TCGETA, &closeTermState.termio);
|
||||
txEraseChar = closeTermState.termio.c_cc[VERASE];
|
||||
txKillChar = closeTermState.termio.c_cc[VKILL];
|
||||
TxEOFChar = closeTermState.termio.c_cc[VEOF];
|
||||
TxInterruptChar = closeTermState.termio.c_cc[VINTR];
|
||||
haveCloseState = TRUE;
|
||||
#else
|
||||
#else /* sgtty */
|
||||
struct ltchars lt;
|
||||
txGetTermState(&closeTermState);
|
||||
(void) ioctl(fileno(stdin), TIOCGLTC, (char *) <);
|
||||
|
|
@ -1393,7 +1360,7 @@ txSaveTerm(void)
|
|||
TxEOFChar = closeTermState.tx_i_tchars.t_eofc;
|
||||
TxInterruptChar = closeTermState.tx_i_tchars.t_intrc;
|
||||
haveCloseState = TRUE;
|
||||
#endif /* SYSV */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1414,13 +1381,7 @@ txSaveTerm(void)
|
|||
void
|
||||
TxSetTerminal(void)
|
||||
{
|
||||
#if defined(SYSV) || defined(CYGWIN)
|
||||
struct termio buf;
|
||||
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
struct termios buf;
|
||||
#else
|
||||
txTermState buf;
|
||||
#endif /* SYSV */
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
/* If using Tk console, don't mess with the terminal settings; */
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/magic.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/magic.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
|
|
|
|||
|
|
@ -21,44 +21,54 @@
|
|||
#ifndef _MAGIC__UTILS__MAGSGTTY_H
|
||||
#define _MAGIC__UTILS__MAGSGTTY_H
|
||||
|
||||
/* maybe this can be #ifndef HAVE_TERMIO_H */
|
||||
#if !defined(SYSV) && !defined(CYGWIN)
|
||||
|
||||
# ifdef ALPHA
|
||||
# undef MAX
|
||||
# undef MIN
|
||||
# endif
|
||||
|
||||
/* unclear what platform requires this OpenBSD/FreeBSD ? */
|
||||
# ifndef COMPAT_43TTY
|
||||
# define COMPAT_43TTY
|
||||
# endif
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_TERMIOS_H)
|
||||
#include <termios.h>
|
||||
#elif defined(HAVE_SYS_IOCTL_COMPAT_H)
|
||||
/* unclear which platform(s) require <sys/ioctl_compat.h> and the structure
|
||||
* of this file is such that it will try to include it by default, better
|
||||
* to invert the #if and only select this on the known platforms that need
|
||||
* it so that <termios.h> goes by default, which exists on MacOSX, Linux, etc..
|
||||
* many possible solutions to make this work by default:
|
||||
* HAVE_SYS_IOCTL_COMPAT_H ? HAVE_TERMIOS_H ? !defined(linux) at top (MaxOSX is BSD type)
|
||||
*/
|
||||
#include <sys/ioctl_compat.h> /* replaced sgtty.h */
|
||||
#elif defined(HAVE_SGTTY_H)
|
||||
#include <sgtty.h> /* legacy - struct sgttyb{} defn */
|
||||
/* In modern times everything has POSIX */
|
||||
#include <termios.h>
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
/* Linux glibx 2.x - present
|
||||
* FreeBSD 14.3-RELEASE - present
|
||||
* Solaris 11.4 - present
|
||||
*/
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
/* Linux glibx 2.x - present (just includes termios.h & sys/ioctl.h)
|
||||
* Linux glibc 2.45+ - not present
|
||||
* FreeBSD 14.3-RELEASE - not present
|
||||
* Solaris 11.4 - present
|
||||
*/
|
||||
#include <termio.h>
|
||||
#else /* sgtty */
|
||||
#if defined(HAVE_SYS_IOCTL_COMPAT_H)
|
||||
/* Linux glibc2.x - not present
|
||||
* FreeBSD 14.3-RELEASE - not present
|
||||
* Solaris 11.4 - not present
|
||||
*/
|
||||
#include <sys/ioctl_compat.h> /* replaced sgtty.h */
|
||||
#elif defined(HAVE_SGTTY_H)
|
||||
/* Linux glibc2.x - present (includes sys/ioctl.h)
|
||||
* FreeBSD 14.3-RELEASE - not present
|
||||
* Solaris 11.4 - present
|
||||
*/
|
||||
#include <sgtty.h> /* legacy - struct sgttyb{} defn */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#if defined(HAVE_TERMIO_H)
|
||||
#include <termio.h>
|
||||
/* all of the state associated with a tty terminal */
|
||||
typedef struct {
|
||||
#if defined(HAVE_TERMIOS_H)
|
||||
struct termios termios;
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
struct termio termio;
|
||||
#else /* sgtty */
|
||||
struct sgttyb tx_i_sgtty;
|
||||
struct tchars tx_i_tchars;
|
||||
#endif
|
||||
} txTermState;
|
||||
|
||||
#endif /* !SYSV && !CYGWIN */
|
||||
|
||||
#endif /* _MAGIC__UTILS__MAGSGTTY_H */
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/main.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/hash.h"
|
||||
#include "utils/macros.h"
|
||||
#include "textio/textio.h"
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/main.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "utils/signals.h"
|
||||
|
|
|
|||
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")))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -820,22 +820,27 @@ windViewCmd(w, cmd)
|
|||
|
||||
if (!strncmp(cmd->tx_argv[1], "get", 3))
|
||||
{
|
||||
char *vllx, *vlly, *vurx, *vury;
|
||||
|
||||
vllx = DBWPrintValue(w->w_surfaceArea.r_xbot, w, TRUE);
|
||||
vlly = DBWPrintValue(w->w_surfaceArea.r_ybot, w, FALSE);
|
||||
vurx = DBWPrintValue(w->w_surfaceArea.r_xtop, w, TRUE);
|
||||
vury = DBWPrintValue(w->w_surfaceArea.r_ytop, w, FALSE);
|
||||
|
||||
/* NOTE: The surface area is in screen (pixel) coordinates
|
||||
* and so does not follow the "units" display type.
|
||||
*/
|
||||
#ifndef MAGIC_WRAPPER
|
||||
TxPrintf("(%d, %d) to (%d, %d)\n",
|
||||
w->w_surfaceArea.r_xbot, w->w_surfaceArea.r_ybot,
|
||||
w->w_surfaceArea.r_xtop, w->w_surfaceArea.r_ytop);
|
||||
TxPrintf("(%s, %s) to (%s, %s)\n", vllx, vlly, vurx, vury);
|
||||
#else
|
||||
Tcl_ListObjAppendElement(magicinterp, listxy,
|
||||
Tcl_NewIntObj((int)w->w_surfaceArea.r_xbot));
|
||||
Tcl_NewStringObj(vllx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, listxy,
|
||||
Tcl_NewIntObj((int)w->w_surfaceArea.r_ybot));
|
||||
Tcl_NewStringObj(vlly, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, listxy,
|
||||
Tcl_NewIntObj((int)w->w_surfaceArea.r_xtop));
|
||||
Tcl_NewStringObj(vurx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, listxy,
|
||||
Tcl_NewIntObj((int)w->w_surfaceArea.r_ytop));
|
||||
Tcl_NewStringObj(vury, -1));
|
||||
Tcl_SetObjResult(magicinterp, listxy);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue