Compare commits
90 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
d157eea7f3 | |
|
|
67c6ed9395 | |
|
|
f15f0dabbb | |
|
|
ae6d26578e | |
|
|
cb1653b157 | |
|
|
a3f5e665d1 | |
|
|
2eea849c06 | |
|
|
6e295d030e | |
|
|
ceba050a21 | |
|
|
f7cceed5e3 | |
|
|
5d35ae38b5 | |
|
|
05561b90f3 | |
|
|
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 | |
|
|
55eadcfb90 | |
|
|
b4f62abb40 | |
|
|
deefe0e3a3 | |
|
|
57c33c48c7 | |
|
|
76f97c90e5 | |
|
|
297a05c4ed | |
|
|
b768fcc3f9 | |
|
|
4943da5ce4 | |
|
|
512400e39f |
|
|
@ -138,6 +138,8 @@ jobs:
|
||||||
echo "BUILD_GCC_VERSION=$BUILD_GCC_VERSION" >> $GITHUB_ENV
|
echo "BUILD_GCC_VERSION=$BUILD_GCC_VERSION" >> $GITHUB_ENV
|
||||||
echo "BUILD_CLANG_VERSION=$BUILD_CLANG_VERSION" >> $GITHUB_ENV
|
echo "BUILD_CLANG_VERSION=$BUILD_CLANG_VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
|
||||||
if [ -n "$BUILD_GCC_VERSION" ]
|
if [ -n "$BUILD_GCC_VERSION" ]
|
||||||
then
|
then
|
||||||
GCCV=$BUILD_GCC_VERSION
|
GCCV=$BUILD_GCC_VERSION
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,22 @@ jobs:
|
||||||
cd emsdk
|
cd emsdk
|
||||||
./emsdk install latest
|
./emsdk install latest
|
||||||
./emsdk activate 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
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
source ./emsdk/emsdk_env.sh
|
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 ====="
|
echo "===== defs.mak ====="
|
||||||
cat defs.mak
|
cat defs.mak
|
||||||
echo "===== 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
|
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||||
jobs:
|
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:
|
simple_build_linux:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
|
|
@ -45,10 +32,22 @@ jobs:
|
||||||
cd emsdk
|
cd emsdk
|
||||||
./emsdk install latest
|
./emsdk install latest
|
||||||
./emsdk activate 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
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
source ./emsdk/emsdk_env.sh
|
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 ====="
|
echo "===== defs.mak ====="
|
||||||
cat defs.mak
|
cat defs.mak
|
||||||
echo "===== defs.mak ====="
|
echo "===== defs.mak ====="
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ int calmaNonManhattan;
|
||||||
int CalmaFlattenLimit = 10;
|
int CalmaFlattenLimit = 10;
|
||||||
int NameConvertErrors = 0;
|
int NameConvertErrors = 0;
|
||||||
bool CalmaRewound = FALSE;
|
bool CalmaRewound = FALSE;
|
||||||
|
bool CalmaRecordPaths = FALSE;
|
||||||
TileTypeBitMask *CalmaMaskHints = NULL;
|
TileTypeBitMask *CalmaMaskHints = NULL;
|
||||||
|
|
||||||
extern HashTable calmaDefInitHash;
|
extern HashTable calmaDefInitHash;
|
||||||
|
|
@ -505,28 +506,33 @@ calmaParseStructure(
|
||||||
|
|
||||||
if (CalmaReadOnly || predefined)
|
if (CalmaReadOnly || predefined)
|
||||||
{
|
{
|
||||||
|
PropertyRecord *proprec;
|
||||||
char cstring[1024];
|
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 */
|
/* Substitute variable for PDK path or ~ for home directory */
|
||||||
/* the same way that cell references are handled in .mag files. */
|
/* the same way that cell references are handled in .mag files. */
|
||||||
DBPathSubstitute(filename, cstring, cifReadCellDef);
|
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);
|
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)
|
if (predefined)
|
||||||
{
|
{
|
||||||
|
|
@ -783,8 +789,8 @@ calmaElementSref(
|
||||||
char *filename)
|
char *filename)
|
||||||
{
|
{
|
||||||
int nbytes, rtype, cols, rows, nref, n, i, savescale;
|
int nbytes, rtype, cols, rows, nref, n, i, savescale;
|
||||||
int xlo, ylo, xhi, yhi, xsep, ysep;
|
int xlo, ylo, xhi, yhi, xsep, ysep, angle;
|
||||||
bool madeinst = FALSE;
|
bool madeinst = FALSE, rotated = FALSE;
|
||||||
char *sname = NULL;
|
char *sname = NULL;
|
||||||
bool isArray = FALSE;
|
bool isArray = FALSE;
|
||||||
bool dolookahead = FALSE;
|
bool dolookahead = FALSE;
|
||||||
|
|
@ -984,17 +990,73 @@ calmaElementSref(
|
||||||
refarray[2].p_x = refarray[2].p_y = 0;
|
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
|
/* If this is a cell reference, then we scale to magic coordinates
|
||||||
* and place the cell in the magic database. However, if this is
|
* 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
|
* a cell to be flattened a la "gds flatten", then we keep the GDS
|
||||||
* coordinates, and don't scale to the magic database.
|
* 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++)
|
for (n = 0; n < nref; n++)
|
||||||
{
|
{
|
||||||
savescale = cifCurReadStyle->crs_scaleFactor;
|
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);
|
refarray[n].p_x = CIFScaleCoord(refarray[n].p_x, COORD_EXACT);
|
||||||
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
||||||
{
|
{
|
||||||
|
|
@ -1015,9 +1077,6 @@ calmaElementSref(
|
||||||
}
|
}
|
||||||
refarray[n].p_x *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
refarray[n].p_x *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FEOF(calmaInputFile))
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip remainder */
|
/* Skip remainder */
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,8 @@ calmaInputRescale(
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
* calmaReadX ---
|
||||||
|
* calmaReadY ---
|
||||||
* calmaReadPoint ---
|
* calmaReadPoint ---
|
||||||
*
|
*
|
||||||
* Read a point from the input.
|
* Read a point from the input.
|
||||||
|
|
@ -132,11 +134,17 @@ calmaInputRescale(
|
||||||
* encountered, then everything in the GDS planes is rescaled
|
* encountered, then everything in the GDS planes is rescaled
|
||||||
* to match.
|
* 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
|
void
|
||||||
calmaReadPoint(
|
calmaReadX(
|
||||||
Point *p,
|
Point *p,
|
||||||
int iscale)
|
int iscale)
|
||||||
{
|
{
|
||||||
|
|
@ -163,6 +171,15 @@ calmaReadPoint(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p->p_x /= calmaReadScale2;
|
p->p_x /= calmaReadScale2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
calmaReadY(
|
||||||
|
Point *p,
|
||||||
|
int iscale)
|
||||||
|
{
|
||||||
|
int rescale;
|
||||||
|
|
||||||
READI4((p)->p_y);
|
READI4((p)->p_y);
|
||||||
p->p_y *= (calmaReadScale1 * iscale);
|
p->p_y *= (calmaReadScale1 * iscale);
|
||||||
|
|
@ -188,6 +205,15 @@ calmaReadPoint(
|
||||||
p->p_y /= calmaReadScale2;
|
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,
|
CIFPaintWirePath(pathheadp, width,
|
||||||
(pathtype == CALMAPATH_SQUAREFLUSH || pathtype == CALMAPATH_CUSTOM) ?
|
(pathtype == CALMAPATH_SQUAREFLUSH || pathtype == CALMAPATH_CUSTOM) ?
|
||||||
FALSE : TRUE, plane, CIFPaintTable, (PaintUndoInfo *)NULL);
|
FALSE : TRUE, plane, CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||||
|
|
|
||||||
|
|
@ -528,7 +528,7 @@ calmaDumpStructure(
|
||||||
|
|
||||||
/* Is view abstract? */
|
/* Is view abstract? */
|
||||||
DBPropGet(edef, "LEFview", &isAbstract);
|
DBPropGet(edef, "LEFview", &isAbstract);
|
||||||
chklibname = (char *)DBPropGet(edef, "GDS_FILE", &isReadOnly);
|
chklibname = DBPropGetString(edef, "GDS_FILE", &isReadOnly);
|
||||||
|
|
||||||
if (isAbstract && isReadOnly)
|
if (isAbstract && isReadOnly)
|
||||||
{
|
{
|
||||||
|
|
@ -738,7 +738,7 @@ calmaFullDump(
|
||||||
* names in the GDS file do not shadow any names in the database.
|
* 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")))
|
if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
|
||||||
{
|
{
|
||||||
/* Generate a SHORT name for this cell (else it is easy to run into the
|
/* Generate a SHORT name for this cell (else it is easy to run into the
|
||||||
|
|
@ -918,7 +918,7 @@ calmaProcessDef(
|
||||||
DBPropGet(def, "GDS_END", &hasGDSEnd);
|
DBPropGet(def, "GDS_END", &hasGDSEnd);
|
||||||
DBPropGet(def, "CIFhier", &needHier);
|
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 */
|
/* When used with "calma addendum true", don't output the read-only */
|
||||||
/* cells. This makes the library incomplete and dependent on the */
|
/* cells. This makes the library incomplete and dependent on the */
|
||||||
|
|
@ -1033,13 +1033,12 @@ calmaProcessDef(
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
offptr = (char *)DBPropGet(def, "GDS_END", NULL);
|
cval = DBPropGetDouble(def, "GDS_END", NULL);
|
||||||
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
|
|
||||||
cellend = (off_t)cval;
|
cellend = (off_t)cval;
|
||||||
offptr = (char *)DBPropGet(def, "GDS_BEGIN", &oldStyle);
|
cval = DBPropGetDouble(def, "GDS_BEGIN", &oldStyle);
|
||||||
if (!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 */
|
/* Write our own header and string name, to ensure */
|
||||||
/* that the magic cell name and GDS name match. */
|
/* that the magic cell name and GDS name match. */
|
||||||
|
|
@ -1056,7 +1055,6 @@ calmaProcessDef(
|
||||||
calmaOutStructName(CALMA_STRNAME, def, outf);
|
calmaOutStructName(CALMA_STRNAME, def, outf);
|
||||||
}
|
}
|
||||||
|
|
||||||
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
|
|
||||||
cellstart = (off_t)cval;
|
cellstart = (off_t)cval;
|
||||||
|
|
||||||
/* GDS_START has been defined as the start of data after the cell */
|
/* GDS_START has been defined as the start of data after the cell */
|
||||||
|
|
@ -1263,7 +1261,7 @@ calmaOutFunc(
|
||||||
int dbunits;
|
int dbunits;
|
||||||
calmaOutputStruct cos;
|
calmaOutputStruct cos;
|
||||||
bool propfound;
|
bool propfound;
|
||||||
char *propvalue;
|
PropertyRecord *proprec;
|
||||||
|
|
||||||
cos.f = f;
|
cos.f = f;
|
||||||
cos.area = (cliprect == &TiPlaneRect) ? NULL : cliprect;
|
cos.area = (cliprect == &TiPlaneRect) ? NULL : cliprect;
|
||||||
|
|
@ -1323,14 +1321,20 @@ calmaOutFunc(
|
||||||
|
|
||||||
/* Include any fixed bounding box as part of the area to process, */
|
/* Include any fixed bounding box as part of the area to process, */
|
||||||
/* in case the fixed bounding box is larger than the geometry. */
|
/* 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)
|
if (propfound)
|
||||||
{
|
{
|
||||||
Rect bbox;
|
Rect bbox;
|
||||||
|
|
||||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||||
&bbox.r_xtop, &bbox.r_ytop) == 4)
|
(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);
|
GeoInclude(&bbox, &bigArea);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CIFErrorDef = def;
|
CIFErrorDef = def;
|
||||||
|
|
|
||||||
|
|
@ -508,7 +508,7 @@ calmaDumpStructureZ(
|
||||||
|
|
||||||
/* Is view abstract? */
|
/* Is view abstract? */
|
||||||
DBPropGet(edef, "LEFview", &isAbstract);
|
DBPropGet(edef, "LEFview", &isAbstract);
|
||||||
chklibname = (char *)DBPropGet(edef, "GDS_FILE", &isReadOnly);
|
chklibname = DBPropGetString(edef, "GDS_FILE", &isReadOnly);
|
||||||
|
|
||||||
if (isAbstract && isReadOnly)
|
if (isAbstract && isReadOnly)
|
||||||
{
|
{
|
||||||
|
|
@ -716,7 +716,7 @@ calmaFullDumpZ(
|
||||||
* names in the GDS file do not shadow any names in the database.
|
* 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")))
|
if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
|
||||||
{
|
{
|
||||||
/* Generate a SHORT name for this cell (else it is easy to run into the
|
/* Generate a SHORT name for this cell (else it is easy to run into the
|
||||||
|
|
@ -870,7 +870,7 @@ calmaProcessDefZ(
|
||||||
DBPropGet(def, "GDS_START", &hasContent);
|
DBPropGet(def, "GDS_START", &hasContent);
|
||||||
DBPropGet(def, "GDS_END", &hasGDSEnd);
|
DBPropGet(def, "GDS_END", &hasGDSEnd);
|
||||||
DBPropGet(def, "CIFhier", &needHier);
|
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 */
|
/* When used with "calma addendum true", don't output the read-only */
|
||||||
/* cells. This makes the library incomplete and dependent on the */
|
/* cells. This makes the library incomplete and dependent on the */
|
||||||
|
|
@ -985,13 +985,12 @@ calmaProcessDefZ(
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
offptr = (char *)DBPropGet(def, "GDS_END", NULL);
|
cval = DBPropGetDouble(def, "GDS_END", NULL);
|
||||||
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
|
|
||||||
cellend = (z_off_t)cval;
|
cellend = (z_off_t)cval;
|
||||||
offptr = (char *)DBPropGet(def, "GDS_BEGIN", &oldStyle);
|
cval = DBPropGetDouble(def, "GDS_BEGIN", &oldStyle);
|
||||||
if (!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 */
|
/* Write our own header and string name, to ensure */
|
||||||
/* that the magic cell name and GDS name match. */
|
/* that the magic cell name and GDS name match. */
|
||||||
|
|
@ -1008,7 +1007,6 @@ calmaProcessDefZ(
|
||||||
calmaOutStructNameZ(CALMA_STRNAME, def, outf);
|
calmaOutStructNameZ(CALMA_STRNAME, def, outf);
|
||||||
}
|
}
|
||||||
|
|
||||||
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
|
|
||||||
cellstart = (z_off_t)cval;
|
cellstart = (z_off_t)cval;
|
||||||
|
|
||||||
/* GDS_START has been defined as the start of data after the cell */
|
/* GDS_START has been defined as the start of data after the cell */
|
||||||
|
|
@ -1186,6 +1184,7 @@ calmaOutFuncZ(
|
||||||
int dbunits;
|
int dbunits;
|
||||||
calmaOutputStructZ cos;
|
calmaOutputStructZ cos;
|
||||||
bool propfound;
|
bool propfound;
|
||||||
|
PropertyRecord *proprec;
|
||||||
char *propvalue;
|
char *propvalue;
|
||||||
extern int compport(const void *one, const void *two); /* Forward declaration */
|
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, */
|
/* Include any fixed bounding box as part of the area to process, */
|
||||||
/* in case the fixed bounding box is larger than the geometry. */
|
/* 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)
|
if (propfound)
|
||||||
{
|
{
|
||||||
Rect bbox;
|
Rect bbox;
|
||||||
|
|
||||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||||
&bbox.r_xtop, &bbox.r_ytop) == 4)
|
(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);
|
GeoInclude(&bbox, &bigArea);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CIFErrorDef = def;
|
CIFErrorDef = def;
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ extern TileTypeBitMask *CalmaMaskHints;
|
||||||
extern bool CalmaMergeTiles;
|
extern bool CalmaMergeTiles;
|
||||||
extern bool CalmaFlattenArrays;
|
extern bool CalmaFlattenArrays;
|
||||||
extern bool CalmaNoDRCCheck;
|
extern bool CalmaNoDRCCheck;
|
||||||
|
extern bool CalmaRecordPaths;
|
||||||
extern bool CalmaFlattenUses;
|
extern bool CalmaFlattenUses;
|
||||||
extern int CalmaFlattenLimit;
|
extern int CalmaFlattenLimit;
|
||||||
extern float CalmaMagScale;
|
extern float CalmaMagScale;
|
||||||
|
|
@ -81,6 +82,8 @@ extern int calmaProcessDefZ(CellDef *def, gzFile outf, bool do_library);
|
||||||
#endif
|
#endif
|
||||||
extern bool calmaReadI2Record(int type, int *pvalue);
|
extern bool calmaReadI2Record(int type, int *pvalue);
|
||||||
extern bool calmaReadI4Record(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 void calmaReadPoint(Point *p, int iscale);
|
||||||
extern bool calmaReadR8(double *pd);
|
extern bool calmaReadR8(double *pd);
|
||||||
extern bool calmaReadStampRecord(int type, int *stampptr);
|
extern bool calmaReadStampRecord(int type, int *stampptr);
|
||||||
|
|
|
||||||
378
cif/CIFgen.c
378
cif/CIFgen.c
|
|
@ -25,6 +25,7 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
|
||||||
#include <stdlib.h> /* for abs() */
|
#include <stdlib.h> /* for abs() */
|
||||||
#include <math.h> /* for ceil() and sqrt() */
|
#include <math.h> /* for ceil() and sqrt() */
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <string.h> /* for strcmp() */
|
||||||
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
|
|
@ -1500,6 +1501,7 @@ cifBloatAllFunc(
|
||||||
|
|
||||||
while (!StackEmpty(BloatStack))
|
while (!StackEmpty(BloatStack))
|
||||||
{
|
{
|
||||||
|
Rect cifarea;
|
||||||
TileType tt;
|
TileType tt;
|
||||||
|
|
||||||
POPTILE(t, dinfo, BloatStack);
|
POPTILE(t, dinfo, BloatStack);
|
||||||
|
|
@ -1516,8 +1518,6 @@ cifBloatAllFunc(
|
||||||
|
|
||||||
if (op->co_distance > 0)
|
if (op->co_distance > 0)
|
||||||
{
|
{
|
||||||
Rect cifarea;
|
|
||||||
|
|
||||||
cifarea.r_xbot = area.r_xbot;
|
cifarea.r_xbot = area.r_xbot;
|
||||||
cifarea.r_ybot = area.r_ybot;
|
cifarea.r_ybot = area.r_ybot;
|
||||||
cifarea.r_xtop = area.r_xtop;
|
cifarea.r_xtop = area.r_xtop;
|
||||||
|
|
@ -1555,40 +1555,42 @@ cifBloatAllFunc(
|
||||||
{
|
{
|
||||||
tt = TiGetTypeExact(t);
|
tt = TiGetTypeExact(t);
|
||||||
if (op->co_distance > 0)
|
if (op->co_distance > 0)
|
||||||
GeoClip(&area, &clipArea);
|
DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &cifarea,
|
||||||
DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &area,
|
CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||||
|
else
|
||||||
|
DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &area,
|
||||||
CIFPaintTable, (PaintUndoInfo *) NULL);
|
CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Top */
|
/* Top */
|
||||||
for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
|
if ((op->co_distance == 0) || (area.r_ytop < clipArea.r_ytop))
|
||||||
if (TTMaskHasType(connect, TiGetBottomType(tp)))
|
for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
|
||||||
PUSHTILE(tp,
|
if (TTMaskHasType(connect, TiGetBottomType(tp)))
|
||||||
(SplitDirection(tp) == ((tt & TT_DIRECTION) ? 1 : 0)) ?
|
PUSHTILE(tp, (SplitDirection(tp) == ((tt & TT_DIRECTION) ? 1 : 0)) ?
|
||||||
(TileType)0 : (TileType)TT_SIDE,
|
(TileType)0 : (TileType)TT_SIDE, BloatStack);
|
||||||
BloatStack);
|
|
||||||
|
|
||||||
/* Left */
|
/* Left */
|
||||||
for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
|
if ((op->co_distance == 0) || (area.r_xbot > clipArea.r_xbot))
|
||||||
if (TTMaskHasType(connect, TiGetRightType(tp)))
|
for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
|
||||||
PUSHTILE(tp, (TileType)TT_SIDE, BloatStack);
|
if (TTMaskHasType(connect, TiGetRightType(tp)))
|
||||||
|
PUSHTILE(tp, (TileType)TT_SIDE, BloatStack);
|
||||||
|
|
||||||
/* Bottom */
|
/* Bottom */
|
||||||
for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
|
if ((op->co_distance == 0) || (area.r_ybot > clipArea.r_ybot))
|
||||||
if (TTMaskHasType(connect, TiGetTopType(tp)))
|
for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
|
||||||
PUSHTILE(tp,
|
if (TTMaskHasType(connect, TiGetTopType(tp)))
|
||||||
(SplitDirection(tp) == ((tt & TT_DIRECTION) ? 1 : 0)) ?
|
PUSHTILE(tp, (SplitDirection(tp) == ((tt & TT_DIRECTION) ? 1 : 0)) ?
|
||||||
(TileType)TT_SIDE : (TileType)0,
|
(TileType)TT_SIDE : (TileType)0, BloatStack);
|
||||||
BloatStack);
|
|
||||||
|
|
||||||
/* Right */
|
/* Right */
|
||||||
for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
|
if ((op->co_distance == 0) || (area.r_xtop < clipArea.r_xtop))
|
||||||
if (TTMaskHasType(connect, TiGetLeftType(tp)))
|
for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
|
||||||
PUSHTILE(tp, (TileType)0, BloatStack);
|
if (TTMaskHasType(connect, TiGetLeftType(tp)))
|
||||||
|
PUSHTILE(tp, (TileType)0, BloatStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear self */
|
/* Clear self */
|
||||||
TiSetClient(tile, CIF_UNPROCESSED);
|
// TiSetClient(tile, CIF_UNPROCESSED);
|
||||||
|
|
||||||
/* NOTE: Tiles must be cleared after the bloat-all function has
|
/* NOTE: Tiles must be cleared after the bloat-all function has
|
||||||
* completed. However, for bloat-all with a limiting distance,
|
* completed. However, for bloat-all with a limiting distance,
|
||||||
|
|
@ -4458,14 +4460,16 @@ bridgeErase(
|
||||||
maskBits = DBPlaneTypes[i];
|
maskBits = DBPlaneTypes[i];
|
||||||
TTMaskAndMask(&maskBits, &brlims->co_paintMask);
|
TTMaskAndMask(&maskBits, &brlims->co_paintMask);
|
||||||
if (!TTMaskEqual(&maskBits, &DBZeroTypeBits))
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (t = 0; t < TT_MAXTYPES; t++, temps++)
|
for (t = 0; t < TT_MAXTYPES; t++, temps++)
|
||||||
{
|
{
|
||||||
if (TTMaskHasType(&brlims->co_cifMask, t))
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4766,6 +4770,106 @@ cifBridgeLimFunc2(
|
||||||
return 0;
|
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.
|
* None.
|
||||||
*
|
*
|
||||||
* Side effects:
|
* 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;
|
CIFSquaresInfo csi;
|
||||||
SearchContext scx;
|
SearchContext scx;
|
||||||
TileType ttype;
|
TileType ttype;
|
||||||
char *netname;
|
char *netname, *text;
|
||||||
|
Label *label;
|
||||||
BloatStruct bls;
|
BloatStruct bls;
|
||||||
BridgeStruct brs;
|
BridgeStruct brs;
|
||||||
BridgeLimStruct brlims;
|
BridgeLimStruct brlims;
|
||||||
BridgeData *bridge;
|
BridgeData *bridge;
|
||||||
BloatData *bloats;
|
BloatData *bloats, locbloat;
|
||||||
bool hstop = FALSE;
|
bool hstop = FALSE;
|
||||||
|
PropertyRecord *proprec;
|
||||||
char *propvalue;
|
char *propvalue;
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
|
|
@ -5314,9 +5462,12 @@ CIFGenLayer(
|
||||||
(ClientData)NULL);
|
(ClientData)NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
TTMaskSetMask(&bls.connect, &op->co_paintMask);
|
||||||
DBSrPaintArea((Tile *)NULL, cellDef->cd_planes[bloats->bl_plane],
|
DBSrPaintArea((Tile *)NULL, cellDef->cd_planes[bloats->bl_plane],
|
||||||
&TiPlaneRect, &bls.connect, cifProcessResetFunc,
|
&TiPlaneRect, &bls.connect, cifProcessResetFunc,
|
||||||
(ClientData)NULL);
|
(ClientData)NULL);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -5395,7 +5546,6 @@ CIFGenLayer(
|
||||||
nextPlane = temp;
|
nextPlane = temp;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case CIFOP_MAXRECT:
|
case CIFOP_MAXRECT:
|
||||||
cifPlane = curPlane;
|
cifPlane = curPlane;
|
||||||
|
|
||||||
|
|
@ -5418,6 +5568,19 @@ CIFGenLayer(
|
||||||
nextPlane = temp;
|
nextPlane = temp;
|
||||||
break;
|
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:
|
case CIFOP_NET:
|
||||||
if (hier)
|
if (hier)
|
||||||
{
|
{
|
||||||
|
|
@ -5443,6 +5606,108 @@ CIFGenLayer(
|
||||||
}
|
}
|
||||||
break;
|
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
|
||||||
|
{
|
||||||
|
TTMaskSetMask(&bls.connect, &op->co_paintMask);
|
||||||
|
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:
|
case CIFOP_BOUNDARY:
|
||||||
if (hier)
|
if (hier)
|
||||||
{
|
{
|
||||||
|
|
@ -5454,10 +5719,17 @@ CIFGenLayer(
|
||||||
|
|
||||||
if (origDef && (origDef->cd_flags & CDFIXEDBBOX))
|
if (origDef && (origDef->cd_flags & CDFIXEDBBOX))
|
||||||
{
|
{
|
||||||
propvalue = (char *)DBPropGet(origDef, "FIXED_BBOX", &found);
|
proprec = DBPropGet(origDef, "FIXED_BBOX", &found);
|
||||||
if (!found) break;
|
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;
|
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
|
||||||
bbox.r_xbot *= cifScale;
|
bbox.r_xbot *= cifScale;
|
||||||
|
|
@ -5519,46 +5791,22 @@ CIFGenLayer(
|
||||||
|
|
||||||
case CIFOP_MASKHINTS:
|
case CIFOP_MASKHINTS:
|
||||||
{
|
{
|
||||||
int j, numfound;
|
int n;
|
||||||
char propname[512];
|
char propname[512];
|
||||||
char *propptr;
|
|
||||||
char *layername = (char *)op->co_client;
|
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 */
|
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)
|
ASSERT (proprec->prop_type == PROPERTY_TYPE_PLANE, "CIFGenLayer");
|
||||||
{
|
t = PlaneGetHint(proprec->prop_value.prop_plane);
|
||||||
/* To do: Allow keyword "rect", "tri", or "poly"
|
DBSrPaintArea(t, proprec->prop_value.prop_plane,
|
||||||
* at the start of the list and parse accordingly.
|
&TiPlaneRect, &CIFSolidBits,
|
||||||
* For now, this only flags an error.
|
cifCopyPropPlaneFunc, (ClientData)curPlane);
|
||||||
*/
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
166
cif/CIFhier.c
166
cif/CIFhier.c
|
|
@ -209,52 +209,41 @@ typedef struct _maskHintsData
|
||||||
{
|
{
|
||||||
Transform *mh_trans;
|
Transform *mh_trans;
|
||||||
CellDef *mh_def;
|
CellDef *mh_def;
|
||||||
|
Plane *mh_plane;
|
||||||
} MaskHintsData;
|
} MaskHintsData;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* cifMaskHints --
|
* cifCopyMaskHintFunc --
|
||||||
*
|
*
|
||||||
* Copy a mask hint into a target cell by adding it to the
|
* Callback function used by cifFlatMaskHints. Transforms a tile
|
||||||
* property list of the target cell. If the target cell already
|
* from the original plane and paints it into the target plane,
|
||||||
* has the same mask hint key, then the mask hint value is
|
* both of which are properties.
|
||||||
* appended to the property in the target cell def.
|
|
||||||
*
|
*
|
||||||
* Returns:
|
* Results:
|
||||||
* 0 to keep the search going.
|
* Zero to keep the search going.
|
||||||
*
|
*
|
||||||
* Side effects:
|
* Side effects:
|
||||||
* Modifies properties of the target cell def.
|
* Paints geometry into the target plane.
|
||||||
*
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* DEPRECATED */
|
|
||||||
int
|
int
|
||||||
cifMaskHints(
|
cifCopyMaskHintFunc(Tile *tile,
|
||||||
char *name,
|
TileType dinfo,
|
||||||
char *value,
|
ClientData cdata)
|
||||||
CellDef *targetDef)
|
|
||||||
{
|
{
|
||||||
char *propvalue, *newval;
|
MaskHintsData *mhd = (MaskHintsData *)cdata;
|
||||||
bool propfound;
|
Rect r, newr;
|
||||||
|
|
||||||
if (!strncmp(name, "MASKHINTS_", 10))
|
TiToRect(tile, &r);
|
||||||
{
|
|
||||||
/* Check if name exists already in the flattened cell */
|
/* Transform tile area to coordinates of mhd->mh_plane and paint */
|
||||||
propvalue = (char *)DBPropGet(targetDef, name, &propfound);
|
GeoTransRect(mhd->mh_trans, &r, &newr);
|
||||||
if (propfound)
|
DBPaintPlane(mhd->mh_plane, &newr, CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||||
{
|
|
||||||
/* Append value to the property */
|
|
||||||
newval = mallocMagic(strlen(value) + strlen(propvalue) + 2);
|
|
||||||
sprintf(newval, "%s %s", propvalue, value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
newval = StrDup((char **)NULL, value);
|
|
||||||
|
|
||||||
DBPropPut(targetDef, name, newval);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,8 +253,8 @@ cifMaskHints(
|
||||||
* cifFlatMaskHints --
|
* cifFlatMaskHints --
|
||||||
*
|
*
|
||||||
* Copy a mask hint into a flattened cell by transforming it into the
|
* Copy a mask hint into a flattened cell by transforming it into the
|
||||||
* coordinate system of the flattened cell, and adding it to the
|
* coordinate system of the flattened cell, and painting it into the
|
||||||
* property list of the flattened cell.
|
* property plane of the flattened cell.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* 0 to keep the search going.
|
* 0 to keep the search going.
|
||||||
|
|
@ -279,67 +268,40 @@ cifMaskHints(
|
||||||
int
|
int
|
||||||
cifFlatMaskHints(
|
cifFlatMaskHints(
|
||||||
char *name,
|
char *name,
|
||||||
char *value,
|
PropertyRecord *proprec,
|
||||||
MaskHintsData *mhd)
|
MaskHintsData *mhd)
|
||||||
{
|
{
|
||||||
Rect r, newr;
|
Rect r, newr;
|
||||||
char *vptr, *newval, *lastval, *propvalue;
|
char *vptr, *newval, *lastval, *propvalue;
|
||||||
bool propfound;
|
bool propfound;
|
||||||
int lastlen, numvals;
|
int i, lastlen, numvals;
|
||||||
|
PropertyRecord *newproprec, *oldproprec;
|
||||||
|
Plane *plane;
|
||||||
|
|
||||||
if (!strncmp(name, "MASKHINTS_", 10))
|
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 */
|
/* 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)
|
if (propfound)
|
||||||
{
|
{
|
||||||
/* Append newval to the property */
|
ASSERT(oldproprec->prop_value.prop_type == PROPERTY_TYPE_PLANE,
|
||||||
lastval = newval;
|
"cifFlatMaskHints");
|
||||||
newval = mallocMagic(strlen(lastval) + strlen(propvalue) + 2);
|
plane = oldproprec->prop_value.prop_plane;
|
||||||
sprintf(newval, "%s %s", propvalue, lastval);
|
|
||||||
freeMagic(lastval);
|
|
||||||
}
|
}
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -350,9 +312,10 @@ cifFlatMaskHints(
|
||||||
* CIFCopyMaskHints --
|
* CIFCopyMaskHints --
|
||||||
*
|
*
|
||||||
* Callback function to copy mask hints from one cell into another.
|
* Callback function to copy mask hints from one cell into another.
|
||||||
|
* (Occasionally called as a standalone function, not as a callback.)
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* None.
|
* Return 0 to keep the search going.
|
||||||
*
|
*
|
||||||
* Side effects:
|
* Side effects:
|
||||||
* May modify properties in the target cell.
|
* May modify properties in the target cell.
|
||||||
|
|
@ -360,7 +323,7 @@ cifFlatMaskHints(
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
int
|
||||||
CIFCopyMaskHints(
|
CIFCopyMaskHints(
|
||||||
SearchContext *scx,
|
SearchContext *scx,
|
||||||
CellDef *targetDef)
|
CellDef *targetDef)
|
||||||
|
|
@ -370,38 +333,9 @@ CIFCopyMaskHints(
|
||||||
CellDef *sourceDef = scx->scx_use->cu_def;
|
CellDef *sourceDef = scx->scx_use->cu_def;
|
||||||
mhd.mh_trans = &scx->scx_trans;
|
mhd.mh_trans = &scx->scx_trans;
|
||||||
mhd.mh_def = targetDef;
|
mhd.mh_def = targetDef;
|
||||||
|
mhd.mh_plane = (Plane *)NULL;
|
||||||
|
|
||||||
DBPropEnum(sourceDef, cifFlatMaskHints, &mhd);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -526,7 +460,7 @@ cifHierCellFunc(
|
||||||
|
|
||||||
/* Flatten mask hints in the area of interest */
|
/* Flatten mask hints in the area of interest */
|
||||||
CIFCopyMaskHints(scx, CIFComponentDef);
|
CIFCopyMaskHints(scx, CIFComponentDef);
|
||||||
DBTreeSrCells(&newscx, 0, cifHierCopyMaskHints,
|
DBTreeSrCells(&newscx, 0, CIFCopyMaskHints,
|
||||||
(ClientData)CIFComponentDef);
|
(ClientData)CIFComponentDef);
|
||||||
|
|
||||||
/* Set CIFErrorDef to NULL to ignore errors here... these will
|
/* Set CIFErrorDef to NULL to ignore errors here... these will
|
||||||
|
|
@ -854,7 +788,7 @@ CIFGenSubcells(
|
||||||
cifHierCopyFunc, (ClientData) CIFTotalDef);
|
cifHierCopyFunc, (ClientData) CIFTotalDef);
|
||||||
/* Flatten mask hints in the area of interest */
|
/* Flatten mask hints in the area of interest */
|
||||||
CIFCopyMaskHints(&scx, CIFTotalDef);
|
CIFCopyMaskHints(&scx, CIFTotalDef);
|
||||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||||
(ClientData)CIFTotalDef);
|
(ClientData)CIFTotalDef);
|
||||||
|
|
||||||
CIFErrorDef = def;
|
CIFErrorDef = def;
|
||||||
|
|
@ -1032,14 +966,14 @@ cifHierElementFunc(
|
||||||
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
||||||
cifHierCopyFunc, (ClientData) CIFTotalDef);
|
cifHierCopyFunc, (ClientData) CIFTotalDef);
|
||||||
CIFCopyMaskHints(&scx, CIFTotalDef);
|
CIFCopyMaskHints(&scx, CIFTotalDef);
|
||||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||||
(ClientData)CIFTotalDef);
|
(ClientData)CIFTotalDef);
|
||||||
|
|
||||||
DBCellClearDef(CIFComponentDef);
|
DBCellClearDef(CIFComponentDef);
|
||||||
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
||||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||||
(ClientData)CIFComponentDef);
|
(ClientData)CIFComponentDef);
|
||||||
|
|
||||||
CIFErrorDef = (CellDef *) NULL;
|
CIFErrorDef = (CellDef *) NULL;
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,8 @@ typedef struct cifop
|
||||||
* CIFOP_BRIDGE - Added 6/11/20---Bridge across catecorner gaps
|
* 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_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_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
|
#define CIFOP_AND 1
|
||||||
|
|
@ -172,6 +174,8 @@ typedef struct cifop
|
||||||
#define CIFOP_BRIDGE 23
|
#define CIFOP_BRIDGE 23
|
||||||
#define CIFOP_BRIDGELIM 24
|
#define CIFOP_BRIDGELIM 24
|
||||||
#define CIFOP_MASKHINTS 25
|
#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 */
|
/* Definitions of bit fields used in the value of co_client for CIFOP_INTERACT */
|
||||||
#define CIFOP_INT_NOT 0x1 /* Inverted sense (not interacting) */
|
#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);
|
bool hier, ClientData clientdata);
|
||||||
extern void CIFInitCells(void);
|
extern void CIFInitCells(void);
|
||||||
extern int cifHierCopyFunc(Tile *tile, TileType dinfo, TreeContext *cxp);
|
extern int cifHierCopyFunc(Tile *tile, TileType dinfo, TreeContext *cxp);
|
||||||
extern int cifHierCopyMaskHints(SearchContext *scx, ClientData clientData);
|
|
||||||
extern void CIFLoadStyle(char *stylename);
|
extern void CIFLoadStyle(char *stylename);
|
||||||
extern void CIFCopyMaskHints(SearchContext *scx, CellDef *targetDef);
|
extern int CIFCopyMaskHints(SearchContext *scx, CellDef *targetDef);
|
||||||
|
|
||||||
/* C99 compat */
|
/* C99 compat */
|
||||||
extern void CIFCoverageLayer(CellDef *rootDef, Rect *area, char *layer, bool dolist);
|
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;
|
CIFOp *op;
|
||||||
|
|
||||||
plane = CIFGenLayer(cifCurReadStyle->crs_layers[i]->crl_ops,
|
plane = CIFGenLayer(cifCurReadStyle->crs_layers[i]->crl_ops,
|
||||||
&TiPlaneRect, (CellDef *)NULL, (CellDef *)NULL,
|
&TiPlaneRect, cifReadCellDef, cifReadCellDef,
|
||||||
cifCurReadPlanes, FALSE, (ClientData)NULL);
|
cifCurReadPlanes, FALSE, (ClientData)NULL);
|
||||||
|
|
||||||
/* Generate a paint/erase table, then paint from the CIF
|
/* Generate a paint/erase table, then paint from the CIF
|
||||||
|
|
@ -688,6 +688,8 @@ CIFPaintCurrent(
|
||||||
}
|
}
|
||||||
else if (op == NULL)
|
else if (op == NULL)
|
||||||
{
|
{
|
||||||
|
LinkedRect *lrec = NULL, *lsrch;
|
||||||
|
|
||||||
/* Handle boundary layer */
|
/* Handle boundary layer */
|
||||||
|
|
||||||
op = cifCurReadStyle->crs_layers[i]->crl_ops;
|
op = cifCurReadStyle->crs_layers[i]->crl_ops;
|
||||||
|
|
@ -702,6 +704,102 @@ CIFPaintCurrent(
|
||||||
(ClientData)NULL) == 1))
|
(ClientData)NULL) == 1))
|
||||||
DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
|
DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
|
||||||
&CIFSolidBits, cifMakeBoundaryFunc, INT2CD(filetype));
|
&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 */
|
/* Swap planes */
|
||||||
|
|
@ -790,9 +888,7 @@ CIFPaintCurrent(
|
||||||
|
|
||||||
for (i = 0; i < cifNReadLayers; i++)
|
for (i = 0; i < cifNReadLayers; i++)
|
||||||
{
|
{
|
||||||
LinkedRect *lrec = NULL;
|
LinkedRect *lrec = NULL, *lsrch;
|
||||||
char *propstr = NULL;
|
|
||||||
char locstr[512];
|
|
||||||
Plane *tempp;
|
Plane *tempp;
|
||||||
|
|
||||||
if (!TTMaskHasType(CalmaMaskHints, i)) continue;
|
if (!TTMaskHasType(CalmaMaskHints, i)) continue;
|
||||||
|
|
@ -817,53 +913,55 @@ CIFPaintCurrent(
|
||||||
(CellDef *)NULL, CIFPlanes, FALSE, (ClientData)NULL);
|
(CellDef *)NULL, CIFPlanes, FALSE, (ClientData)NULL);
|
||||||
|
|
||||||
/* Scan the resulting plane and generate linked Rect structures for
|
/* 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,
|
DBSrPaintArea((Tile *)NULL, presult, &TiPlaneRect, &CIFSolidBits,
|
||||||
cifMaskHintFunc, (ClientData)&lrec);
|
cifMaskHintFunc, (ClientData)&lrec);
|
||||||
|
|
||||||
if (lrec != NULL)
|
if (lrec != NULL)
|
||||||
{
|
{
|
||||||
|
PropertyRecord *proprec;
|
||||||
|
bool propfound;
|
||||||
char *propname;
|
char *propname;
|
||||||
|
Plane *plane;
|
||||||
|
|
||||||
propname = (char *)mallocMagic(11 + strlen(cifReadLayers[i]));
|
propname = (char *)mallocMagic(11 + strlen(cifReadLayers[i]));
|
||||||
sprintf(propname, "MASKHINTS_%s", cifReadLayers[i]);
|
sprintf(propname, "MASKHINTS_%s", cifReadLayers[i]);
|
||||||
|
|
||||||
propstr = (char *)NULL;
|
/* Paint all linked Rects into a mask-hints property plane
|
||||||
|
* in the target cell.
|
||||||
/* Turn all linked Rects into a mask-hints property 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)
|
while (lrec != NULL)
|
||||||
{
|
{
|
||||||
char *newstr;
|
lrec->r_r.r_xbot /= CIFCurStyle->cs_scaleFactor;
|
||||||
sprintf(locstr, "%d %d %d %d",
|
lrec->r_r.r_ybot /= CIFCurStyle->cs_scaleFactor;
|
||||||
lrec->r_r.r_xbot / CIFCurStyle->cs_scaleFactor,
|
lrec->r_r.r_xtop /= CIFCurStyle->cs_scaleFactor;
|
||||||
lrec->r_r.r_ybot / CIFCurStyle->cs_scaleFactor,
|
lrec->r_r.r_ytop /= 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,
|
||||||
if (propstr == NULL)
|
(PaintUndoInfo *)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;
|
|
||||||
free_magic1_t mm1 = freeMagic1_init();
|
free_magic1_t mm1 = freeMagic1_init();
|
||||||
freeMagic1(&mm1, lrec);
|
freeMagic1(&mm1, lrec);
|
||||||
lrec = lrec->r_next;
|
lrec = lrec->r_next;
|
||||||
freeMagic1_end(&mm1);
|
freeMagic1_end(&mm1);
|
||||||
}
|
}
|
||||||
/* NOTE: propstr is transferred to the CellDef and should
|
|
||||||
* not be free'd here.
|
|
||||||
*/
|
|
||||||
DBPropPut(cifReadCellDef, propname, propstr);
|
|
||||||
freeMagic(propname);
|
freeMagic(propname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -902,6 +1000,7 @@ cifMakeBoundaryFunc(
|
||||||
/* If there are multiple rectangles defined with the boundary */
|
/* If there are multiple rectangles defined with the boundary */
|
||||||
/* layer, then the last one defines the FIXED_BBOX property. */
|
/* layer, then the last one defines the FIXED_BBOX property. */
|
||||||
|
|
||||||
|
PropertyRecord *proprec;
|
||||||
Rect area;
|
Rect area;
|
||||||
char propertyvalue[128], *storedvalue;
|
char propertyvalue[128], *storedvalue;
|
||||||
int savescale;
|
int savescale;
|
||||||
|
|
@ -933,19 +1032,24 @@ cifMakeBoundaryFunc(
|
||||||
|
|
||||||
if (cifReadCellDef->cd_flags & CDFIXEDBBOX)
|
if (cifReadCellDef->cd_flags & CDFIXEDBBOX)
|
||||||
{
|
{
|
||||||
char *propvalue;
|
PropertyRecord *proprec;
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
/* Only flag a warning if the redefined boundary was */
|
/* Only flag a warning if the redefined boundary was */
|
||||||
/* different from the original. */
|
/* different from the original. */
|
||||||
|
|
||||||
propvalue = (char *)DBPropGet(cifReadCellDef, "FIXED_BBOX", &found);
|
proprec = DBPropGet(cifReadCellDef, "FIXED_BBOX", &found);
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
Rect bbox;
|
Rect bbox;
|
||||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||||
&bbox.r_xtop, &bbox.r_ytop) == 4)
|
(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) ||
|
if ((bbox.r_xbot != area.r_xbot) ||
|
||||||
(bbox.r_ybot != area.r_ybot) ||
|
(bbox.r_ybot != area.r_ybot) ||
|
||||||
(bbox.r_xtop != area.r_xtop) ||
|
(bbox.r_xtop != area.r_xtop) ||
|
||||||
|
|
@ -962,10 +1066,15 @@ cifMakeBoundaryFunc(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(propertyvalue, "%d %d %d %d",
|
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) + 2 * sizeof(int));
|
||||||
area.r_xbot, area.r_ybot, area.r_xtop, area.r_ytop);
|
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||||
storedvalue = StrDup((char **)NULL, propertyvalue);
|
proprec->prop_len = 4;
|
||||||
DBPropPut(cifReadCellDef, "FIXED_BBOX", storedvalue);
|
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;
|
cifReadCellDef->cd_flags |= CDFIXEDBBOX;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1677,8 +1786,8 @@ CIFReadCellCleanup(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do geometrical processing on the top-level cell. */
|
/* Do geometrical processing on the top-level cell. */
|
||||||
|
if (filetype == FILE_CIF) CIFPaintCurrent(filetype);
|
||||||
|
|
||||||
CIFPaintCurrent(FILE_CIF);
|
|
||||||
DBAdjustLabels(EditCellUse->cu_def, &TiPlaneRect);
|
DBAdjustLabels(EditCellUse->cu_def, &TiPlaneRect);
|
||||||
DBReComputeBbox(EditCellUse->cu_def);
|
DBReComputeBbox(EditCellUse->cu_def);
|
||||||
DBWAreaChanged(EditCellUse->cu_def, &EditCellUse->cu_def->cd_bbox,
|
DBWAreaChanged(EditCellUse->cu_def, &EditCellUse->cu_def->cd_bbox,
|
||||||
|
|
|
||||||
|
|
@ -244,40 +244,61 @@ CIFPropRecordPath(
|
||||||
{
|
{
|
||||||
extern float CIFGetOutputScale(int convert);
|
extern float CIFGetOutputScale(int convert);
|
||||||
CIFPath *pathp;
|
CIFPath *pathp;
|
||||||
char *pathstr, *sptr;
|
char *namestr = NULL;
|
||||||
int components;
|
int components, i, x, y, mult, pathnum;
|
||||||
float x, y, oscale, mult;
|
PropertyRecord *proprec;
|
||||||
|
bool propfound;
|
||||||
|
|
||||||
oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */
|
/* If "name" is a property, then append a suffix to it to ensure uniqueness */
|
||||||
if (oscale == 0.0) oscale = 1.0;
|
DBPropGet(def, propname, &propfound);
|
||||||
mult = (iswire == TRUE) ? 0.5 : 1.0;
|
if (propfound)
|
||||||
|
{
|
||||||
|
pathnum = 0;
|
||||||
|
namestr = mallocMagic(strlen(propname) + 10);
|
||||||
|
while (propfound)
|
||||||
|
{
|
||||||
|
sprintf(namestr, "%s_%d", propname, pathnum);
|
||||||
|
DBPropGet(def, namestr, &propfound);
|
||||||
|
pathnum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pathp = pathheadp;
|
mult = (iswire == TRUE) ? 1 : 0;
|
||||||
components = 0;
|
|
||||||
|
|
||||||
/* Count the number of components in the path */
|
/* Count the number of components in the path */
|
||||||
|
pathp = pathheadp;
|
||||||
|
components = 0;
|
||||||
while (pathp != NULL)
|
while (pathp != NULL)
|
||||||
{
|
{
|
||||||
pathp = pathp->cifp_next;
|
|
||||||
components++;
|
components++;
|
||||||
|
pathp = pathp->cifp_next;
|
||||||
}
|
}
|
||||||
/* Allocate enough space to hold 2 * N points at "infinity" */
|
/* Allocate enough space to hold 2 * N points. */
|
||||||
pathstr = (char *)mallocMagic(components * 40);
|
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||||
|
((components - 1) * 2) * sizeof(int));
|
||||||
|
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||||
|
proprec->prop_len = components * 2;
|
||||||
|
|
||||||
pathp = pathheadp;
|
pathp = pathheadp;
|
||||||
sptr = pathstr;
|
i = 0;
|
||||||
while (pathp != NULL)
|
while (pathp != NULL)
|
||||||
{
|
{
|
||||||
x = (float)pathp->cifp_x * oscale * mult;
|
x = pathp->cifp_x >> mult;
|
||||||
y = (float)pathp->cifp_y * oscale * mult;
|
y = pathp->cifp_y >> mult;
|
||||||
sprintf(sptr, "%.3f %.3f ", x, y);
|
|
||||||
sptr = sptr + strlen(sptr);
|
proprec->prop_value.prop_integer[i] = x;
|
||||||
|
proprec->prop_value.prop_integer[i + 1] = y;
|
||||||
|
|
||||||
|
i += 2;
|
||||||
pathp = pathp->cifp_next;
|
pathp = pathp->cifp_next;
|
||||||
}
|
}
|
||||||
|
if (namestr)
|
||||||
/* Reallocate pathstr to be no larger than needed to hold the path contents */
|
{
|
||||||
StrDup(&pathstr, pathstr);
|
DBPropPut(def, namestr, proprec);
|
||||||
DBPropPut(def, propname, (ClientData)pathstr);
|
freeMagic(namestr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
DBPropPut(def, propname, proprec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -324,14 +324,19 @@ cifNewReadStyle(void)
|
||||||
{
|
{
|
||||||
/* Destroy old style and free all memory allocated to it */
|
/* 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];
|
layer = cifCurReadStyle->crs_layers[i];
|
||||||
if (layer != NULL)
|
if (layer != NULL)
|
||||||
{
|
{
|
||||||
free_magic1_t mm1 = freeMagic1_init();
|
free_magic1_t mm1 = freeMagic1_init();
|
||||||
for (op = layer->crl_ops; op != NULL; op = op->co_next)
|
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(&mm1, (char *)op);
|
||||||
|
}
|
||||||
freeMagic1_end(&mm1);
|
freeMagic1_end(&mm1);
|
||||||
freeMagic((char *)layer);
|
freeMagic((char *)layer);
|
||||||
}
|
}
|
||||||
|
|
@ -990,6 +995,12 @@ CIFReadTechLine(
|
||||||
newOp->co_opcode = CIFOP_COPYUP;
|
newOp->co_opcode = CIFOP_COPYUP;
|
||||||
else if (strcmp(argv[0], "boundary") == 0)
|
else if (strcmp(argv[0], "boundary") == 0)
|
||||||
newOp->co_opcode = CIFOP_BOUNDARY;
|
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
|
else
|
||||||
{
|
{
|
||||||
TechError("Unknown statement \"%s\".\n", argv[0]);
|
TechError("Unknown statement \"%s\".\n", argv[0]);
|
||||||
|
|
@ -1016,6 +1027,15 @@ CIFReadTechLine(
|
||||||
goto errorReturn;
|
goto errorReturn;
|
||||||
}
|
}
|
||||||
break;
|
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. */
|
/* Link the new CIFOp onto the list. */
|
||||||
|
|
@ -1099,6 +1119,7 @@ CIFReadTechFinal(void)
|
||||||
*
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
CIFReadLoadStyle(
|
CIFReadLoadStyle(
|
||||||
char *stylename)
|
char *stylename)
|
||||||
|
|
|
||||||
18
cif/CIFsee.c
18
cif/CIFsee.c
|
|
@ -166,9 +166,9 @@ CIFPaintLayer(
|
||||||
scx.scx_use = CIFDummyUse;
|
scx.scx_use = CIFDummyUse;
|
||||||
scx.scx_trans = GeoIdentityTransform;
|
scx.scx_trans = GeoIdentityTransform;
|
||||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||||
(ClientData)CIFComponentDef);
|
(ClientData)CIFComponentDef);
|
||||||
|
|
||||||
oldCount = DBWFeedbackCount;
|
oldCount = DBWFeedbackCount;
|
||||||
|
|
@ -287,9 +287,9 @@ CIFSeeLayer(
|
||||||
scx.scx_use = CIFDummyUse;
|
scx.scx_use = CIFDummyUse;
|
||||||
scx.scx_trans = GeoIdentityTransform;
|
scx.scx_trans = GeoIdentityTransform;
|
||||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||||
(ClientData)CIFComponentDef);
|
(ClientData)CIFComponentDef);
|
||||||
|
|
||||||
oldCount = DBWFeedbackCount;
|
oldCount = DBWFeedbackCount;
|
||||||
|
|
@ -459,9 +459,9 @@ CIFCoverageLayer(
|
||||||
scx.scx_use = CIFDummyUse;
|
scx.scx_use = CIFDummyUse;
|
||||||
scx.scx_trans = GeoIdentityTransform;
|
scx.scx_trans = GeoIdentityTransform;
|
||||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||||
(ClientData)CIFComponentDef);
|
(ClientData)CIFComponentDef);
|
||||||
|
|
||||||
CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE,
|
CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE,
|
||||||
|
|
@ -504,10 +504,10 @@ CIFCoverageLayer(
|
||||||
}
|
}
|
||||||
else
|
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);
|
"Cell", btotal);
|
||||||
TxPrintf("Layer Bounding Area = %lld CIF units^2\n", atotal);
|
TxPrintf("Layer Bounding Area = %"DLONG_PREFIX"d CIF units^2\n", atotal);
|
||||||
TxPrintf("Layer Total Area = %lld CIF units^2\n", cstats.coverage);
|
TxPrintf("Layer Total Area = %"DLONG_PREFIX"d CIF units^2\n", cstats.coverage);
|
||||||
TxPrintf("Coverage in %s = %1.1f%%\n", doBox ? "box" :
|
TxPrintf("Coverage in %s = %1.1f%%\n", doBox ? "box" :
|
||||||
"cell", 100.0 * fcover);
|
"cell", 100.0 * fcover);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1107,6 +1107,8 @@ CIFTechLine(
|
||||||
newOp->co_opcode = CIFOP_BBOX;
|
newOp->co_opcode = CIFOP_BBOX;
|
||||||
else if (strcmp(argv[0], "net") == 0)
|
else if (strcmp(argv[0], "net") == 0)
|
||||||
newOp->co_opcode = CIFOP_NET;
|
newOp->co_opcode = CIFOP_NET;
|
||||||
|
else if (strcmp(argv[0], "tagged") == 0)
|
||||||
|
newOp->co_opcode = CIFOP_TAGGED;
|
||||||
else if (strcmp(argv[0], "maxrect") == 0)
|
else if (strcmp(argv[0], "maxrect") == 0)
|
||||||
newOp->co_opcode = CIFOP_MAXRECT;
|
newOp->co_opcode = CIFOP_MAXRECT;
|
||||||
else if (strcmp(argv[0], "boundary") == 0)
|
else if (strcmp(argv[0], "boundary") == 0)
|
||||||
|
|
@ -1117,6 +1119,8 @@ CIFTechLine(
|
||||||
newOp->co_opcode = CIFOP_CLOSE;
|
newOp->co_opcode = CIFOP_CLOSE;
|
||||||
else if (strcmp(argv[0], "orthogonal") == 0)
|
else if (strcmp(argv[0], "orthogonal") == 0)
|
||||||
newOp->co_opcode = CIFOP_MANHATTAN;
|
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)
|
else if (strcmp(argv[0], "bridge") == 0)
|
||||||
newOp->co_opcode = CIFOP_BRIDGE;
|
newOp->co_opcode = CIFOP_BRIDGE;
|
||||||
else if (strcmp(argv[0], "bridge-lim") == 0)
|
else if (strcmp(argv[0], "bridge-lim") == 0)
|
||||||
|
|
@ -1355,6 +1359,7 @@ bloatCheck:
|
||||||
bloatDone: break;
|
bloatDone: break;
|
||||||
|
|
||||||
case CIFOP_NET:
|
case CIFOP_NET:
|
||||||
|
case CIFOP_TAGGED:
|
||||||
if (argc != 3) goto wrongNumArgs;
|
if (argc != 3) goto wrongNumArgs;
|
||||||
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
|
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
|
||||||
cifParseLayers(argv[2], CIFCurStyle, &newOp->co_paintMask,
|
cifParseLayers(argv[2], CIFCurStyle, &newOp->co_paintMask,
|
||||||
|
|
@ -1669,12 +1674,12 @@ cifComputeRadii(
|
||||||
|
|
||||||
for (op = layer->cl_ops; op != NULL; op = op->co_next)
|
for (op = layer->cl_ops; op != NULL; op = op->co_next)
|
||||||
{
|
{
|
||||||
/* BBOX, NET, and MASKHINTS operators should never be used */
|
/* BBOX, NET, TAGGED, and MASKHINTS operators should never be */
|
||||||
/* hierarchically so ignore any grow/shrink operators that */
|
/* used hierarchically so ignore any grow/shrink operators that */
|
||||||
/* come after them. */
|
/* come after them. */
|
||||||
|
|
||||||
if (op->co_opcode == CIFOP_BBOX || op->co_opcode == CIFOP_NET ||
|
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;
|
break;
|
||||||
|
|
||||||
/* If CIF layers are used, switch to the max of current
|
/* 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 */
|
/* Presence of op->co_opcode in CIFOP_OR indicates a copy */
|
||||||
/* of the SquaresData pointer from a following operator. */
|
/* of the SquaresData pointer from a following operator. */
|
||||||
/* CIFOP_BBOX and CIFOP_MAXRECT uses the co_client field */
|
/* CIFOP_BBOX and CIFOP_MAXRECT uses the co_client field */
|
||||||
/* as a flag field, while CIFOP_NET and CIFOP_MASKHINTS */
|
/* as a flag field, while CIFOP_NET, CIFOP_MASKHINTS, and */
|
||||||
/* uses it for a string. */
|
/* CIFOP_TAGGED use it for a string. */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (op->co_opcode)
|
switch (op->co_opcode)
|
||||||
|
|
@ -1999,6 +2004,7 @@ CIFTechFinal(void)
|
||||||
case CIFOP_MAXRECT:
|
case CIFOP_MAXRECT:
|
||||||
case CIFOP_MANHATTAN:
|
case CIFOP_MANHATTAN:
|
||||||
case CIFOP_NET:
|
case CIFOP_NET:
|
||||||
|
case CIFOP_TAGGED:
|
||||||
break;
|
break;
|
||||||
case CIFOP_BRIDGELIM:
|
case CIFOP_BRIDGELIM:
|
||||||
case CIFOP_BRIDGE:
|
case CIFOP_BRIDGE:
|
||||||
|
|
@ -2534,6 +2540,7 @@ CIFTechOutputScale(
|
||||||
case CIFOP_MAXRECT:
|
case CIFOP_MAXRECT:
|
||||||
case CIFOP_MANHATTAN:
|
case CIFOP_MANHATTAN:
|
||||||
case CIFOP_NET:
|
case CIFOP_NET:
|
||||||
|
case CIFOP_TAGGED:
|
||||||
case CIFOP_INTERACT:
|
case CIFOP_INTERACT:
|
||||||
break;
|
break;
|
||||||
case CIFOP_BRIDGELIM:
|
case CIFOP_BRIDGELIM:
|
||||||
|
|
@ -2649,8 +2656,8 @@ CIFTechOutputScale(
|
||||||
default:
|
default:
|
||||||
/* op->co_opcode in CIFOP_OR is a pointer copy, */
|
/* op->co_opcode in CIFOP_OR is a pointer copy, */
|
||||||
/* in CIFOP_BBOX and CIFOP_MAXRECT is a flag, */
|
/* in CIFOP_BBOX and CIFOP_MAXRECT is a flag, */
|
||||||
/* and in CIFOP_NET and CIFOP_MASKHINTS is a */
|
/* and in CIFOP_NET, CIFOP_MASKHINTS, and */
|
||||||
/* string. */
|
/* CIFOP_TAGGED is a string. */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -779,8 +779,8 @@ CmdBox(
|
||||||
break;
|
break;
|
||||||
case BOX_EXISTS:
|
case BOX_EXISTS:
|
||||||
#ifdef MAGIC_WRAPPER
|
#ifdef MAGIC_WRAPPER
|
||||||
Tcl_SetResult(magicinterp, ToolGetBox(NULL, NULL) ? "1" : "0",
|
Tcl_SetObjResult(magicinterp,
|
||||||
NULL);
|
Tcl_NewBooleanObj(ToolGetBox(NULL, NULL) ? TRUE : FALSE));
|
||||||
#else
|
#else
|
||||||
TxPrintf("%s\n", ToolGetBox(NULL, NULL) ? "True" : "False");
|
TxPrintf("%s\n", ToolGetBox(NULL, NULL) ? "True" : "False");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -117,12 +117,13 @@ bool cmdDumpParseArgs(char *cmdName, MagWindow *w, TxCommand *cmd, CellUse *dumm
|
||||||
#define CALMA_READ 19
|
#define CALMA_READ 19
|
||||||
#define CALMA_READONLY 20
|
#define CALMA_READONLY 20
|
||||||
#define CALMA_RESCALE 21
|
#define CALMA_RESCALE 21
|
||||||
#define CALMA_WARNING 22
|
#define CALMA_SAVEPATHS 22
|
||||||
#define CALMA_WRITE 23
|
#define CALMA_WARNING 23
|
||||||
#define CALMA_POLYS 24
|
#define CALMA_WRITE 24
|
||||||
#define CALMA_PATHS 25
|
#define CALMA_POLYS 25
|
||||||
#define CALMA_UNDEFINED 26
|
#define CALMA_PATHS 26
|
||||||
#define CALMA_UNIQUE 27
|
#define CALMA_UNDEFINED 27
|
||||||
|
#define CALMA_UNIQUE 28
|
||||||
|
|
||||||
#define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */
|
#define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */
|
||||||
|
|
||||||
|
|
@ -175,6 +176,7 @@ CmdCalma(
|
||||||
" into edit cell",
|
" into edit cell",
|
||||||
"readonly [yes|no] set cell as read-only and generate output from GDS file",
|
"readonly [yes|no] set cell as read-only and generate output from GDS file",
|
||||||
"rescale [yes|no] allow or disallow internal grid subdivision",
|
"rescale [yes|no] allow or disallow internal grid subdivision",
|
||||||
|
"savepaths [yes|no] save path centerlines as cell properties",
|
||||||
"warning [option] set warning information level",
|
"warning [option] set warning information level",
|
||||||
"write file output Calma GDS-II format to \"file\"\n"
|
"write file output Calma GDS-II format to \"file\"\n"
|
||||||
" for the window's root cell",
|
" for the window's root cell",
|
||||||
|
|
@ -738,6 +740,27 @@ CmdCalma(
|
||||||
CalmaSubcellPolygons = (unsigned char)option;
|
CalmaSubcellPolygons = (unsigned char)option;
|
||||||
return;
|
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:
|
case CALMA_NO_DUP:
|
||||||
if (cmd->tx_argc == 2)
|
if (cmd->tx_argc == 2)
|
||||||
{
|
{
|
||||||
|
|
@ -1300,7 +1323,7 @@ CmdCellname(
|
||||||
if (cellDef == (CellDef *) NULL)
|
if (cellDef == (CellDef *) NULL)
|
||||||
TxError("Unknown cell %s\n", cellname);
|
TxError("Unknown cell %s\n", cellname);
|
||||||
else
|
else
|
||||||
CmdDoProperty(cellDef, cmd, 3 + ((dolist) ? 1 : 0));
|
CmdDoProperty(cellDef, w, cmd, 3 + ((dolist) ? 1 : 0));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IDX_DELETE:
|
case IDX_DELETE:
|
||||||
|
|
@ -4991,15 +5014,20 @@ cmdDumpParseArgs(
|
||||||
bbox = def->cd_bbox;
|
bbox = def->cd_bbox;
|
||||||
if (def->cd_flags & CDFIXEDBBOX)
|
if (def->cd_flags & CDFIXEDBBOX)
|
||||||
{
|
{
|
||||||
char *propvalue;
|
PropertyRecord *proprec;
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &found);
|
proprec = DBPropGet(def, "FIXED_BBOX", &found);
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||||
&bbox.r_xtop, &bbox.r_ytop) != 4)
|
(proprec->prop_len == 4))
|
||||||
bbox = def->cd_bbox;
|
{
|
||||||
|
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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
172
commands/CmdE.c
172
commands/CmdE.c
|
|
@ -781,39 +781,82 @@ cmdEraseCellsFunc(
|
||||||
* Implement the "expand" command.
|
* Implement the "expand" command.
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* expand
|
* expand [selection|surround|overlap|all] [toggle]
|
||||||
* expand toggle
|
*
|
||||||
|
* "selection" expands cells in the selection. All other options
|
||||||
|
* expand cells in the layout. "all" expands all cells in the
|
||||||
|
* layout. "surround" expands cells which the cursor box
|
||||||
|
* surrounds completely, and "overlap" expands cells which the
|
||||||
|
* cursor box overlaps.
|
||||||
|
*
|
||||||
|
* If "toggle" is specified, flips the expanded/unexpanded status.
|
||||||
|
* Cells which were expanded are unexpanded, and cells which were
|
||||||
|
* unexpanded are expanded.
|
||||||
|
*
|
||||||
|
* For backwards compatibility:
|
||||||
|
* "expand" alone implements "expand overlap".
|
||||||
|
* "expand toggle" implements "expand selection toggle".
|
||||||
|
*
|
||||||
|
* Also see: CmdUnexpand
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* None.
|
* None.
|
||||||
*
|
*
|
||||||
* Side effects:
|
* Side effects:
|
||||||
* If "toggle" is specified, flips the expanded/unexpanded status
|
* Expansion state of cells is changed. May read cells in from
|
||||||
* of all selected cells. Otherwise, aren't any unexpanded cells
|
* disk, and update bounding boxes that have changed.
|
||||||
* left under the box. May read cells in from disk, and updates
|
|
||||||
* bounding boxes that have changed.
|
|
||||||
*
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define EXPAND_SELECTION 0
|
||||||
|
#define EXPAND_SURROUND 1
|
||||||
|
#define EXPAND_OVERLAP 2
|
||||||
|
#define EXPAND_ALL 3
|
||||||
|
#define EXPAND_HELP 4
|
||||||
|
|
||||||
void
|
void
|
||||||
CmdExpand(
|
CmdExpand(
|
||||||
MagWindow *w,
|
MagWindow *w,
|
||||||
TxCommand *cmd)
|
TxCommand *cmd)
|
||||||
{
|
{
|
||||||
int windowMask, boxMask, d;
|
int windowMask, boxMask, d, option;
|
||||||
|
bool doToggle = FALSE;
|
||||||
|
const char * const *msg;
|
||||||
Rect rootRect;
|
Rect rootRect;
|
||||||
CellUse *rootBoxUse;
|
CellUse *rootBoxUse;
|
||||||
CellDef *rootBoxDef;
|
CellDef *rootBoxDef;
|
||||||
|
|
||||||
int cmdExpandFunc(CellUse *use, int windowMask); /* Forward reference. */
|
int cmdExpandFunc(CellUse *use, int windowMask); /* Forward reference. */
|
||||||
|
|
||||||
if (cmd->tx_argc > 2 || (cmd->tx_argc == 2
|
static const char * const cmdExpandOption[] = {
|
||||||
&& (strncmp(cmd->tx_argv[1], "toggle", strlen(cmd->tx_argv[1])) != 0)))
|
"selection expand cell instances in the selection",
|
||||||
|
"surround expand cell instances which the cursor box surrounds",
|
||||||
|
"overlap expand cell instances which the cursor box overlaps",
|
||||||
|
"all expand all cell instances",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
if (cmd->tx_argc > 1)
|
||||||
{
|
{
|
||||||
TxError("Usage: %s or %s toggle\n", cmd->tx_argv[0], cmd->tx_argv[0]);
|
if (!strncmp(cmd->tx_argv[cmd->tx_argc - 1], "toggle",
|
||||||
return;
|
strlen(cmd->tx_argv[cmd->tx_argc - 1])))
|
||||||
|
{
|
||||||
|
doToggle = TRUE;
|
||||||
|
cmd->tx_argc--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmd->tx_argc > 1)
|
||||||
|
{
|
||||||
|
option = Lookup(cmd->tx_argv[1], cmdExpandOption);
|
||||||
|
if (option < 0) option = EXPAND_HELP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
option = EXPAND_OVERLAP;
|
||||||
|
|
||||||
|
if (option == EXPAND_HELP) goto badusage;
|
||||||
|
|
||||||
windCheckOnlyWindow(&w, DBWclientID);
|
windCheckOnlyWindow(&w, DBWclientID);
|
||||||
if (w == (MagWindow *) NULL)
|
if (w == (MagWindow *) NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -844,23 +887,95 @@ CmdExpand(
|
||||||
WindScale(d, 1);
|
WindScale(d, 1);
|
||||||
TxPrintf("expand: rescaled by %d\n", d);
|
TxPrintf("expand: rescaled by %d\n", d);
|
||||||
d = DBLambda[1];
|
d = DBLambda[1];
|
||||||
if (cmd->tx_argc == 2) break; /* Don't toggle twice */
|
if (doToggle) break; /* Don't toggle twice */
|
||||||
}
|
}
|
||||||
(void) ToolGetBoxWindow(&rootRect, &boxMask);
|
(void) ToolGetBoxWindow(&rootRect, &boxMask);
|
||||||
|
|
||||||
if (cmd->tx_argc == 2)
|
if (option != EXPAND_SELECTION)
|
||||||
SelectExpand(windowMask);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if ((boxMask & windowMask) != windowMask)
|
if ((boxMask & windowMask) != windowMask)
|
||||||
{
|
{
|
||||||
TxError("The box isn't in the same window as the cursor.\n");
|
TxError("The box isn't in the same window as the cursor.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
}
|
||||||
TRUE, cmdExpandFunc, (ClientData)(pointertype) windowMask);
|
|
||||||
|
switch (option)
|
||||||
|
{
|
||||||
|
case EXPAND_SELECTION:
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
(doToggle) ? DB_EXPAND_TOGGLE : DB_EXPAND,
|
||||||
|
(Rect *)NULL, FALSE);
|
||||||
|
break;
|
||||||
|
case EXPAND_OVERLAP:
|
||||||
|
if (doToggle)
|
||||||
|
{
|
||||||
|
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
||||||
|
DB_EXPAND_TOGGLE | DB_EXPAND_OVERLAP,
|
||||||
|
cmdExpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_EXPAND_TOGGLE | DB_EXPAND_OVERLAP,
|
||||||
|
&rootRect, FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
cmdExpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
&rootRect, FALSE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EXPAND_SURROUND:
|
||||||
|
if (doToggle)
|
||||||
|
{
|
||||||
|
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
||||||
|
DB_EXPAND_TOGGLE | DB_EXPAND_SURROUND,
|
||||||
|
cmdExpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_EXPAND_TOGGLE | DB_EXPAND_SURROUND,
|
||||||
|
&rootRect, TRUE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_SURROUND,
|
||||||
|
cmdExpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_SURROUND,
|
||||||
|
&rootRect, TRUE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EXPAND_ALL:
|
||||||
|
if (doToggle)
|
||||||
|
{
|
||||||
|
DBExpandAll(rootBoxUse, &TiPlaneRect, windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
cmdExpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
(Rect *)NULL, FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBExpandAll(rootBoxUse, &TiPlaneRect, windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
cmdExpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
(Rect *)NULL, FALSE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} while (d != DBLambda[1]);
|
} while (d != DBLambda[1]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
badusage:
|
||||||
|
for (msg = &(cmdExpandOption[0]); *msg != NULL; msg++)
|
||||||
|
TxPrintf(" %s\n", *msg);
|
||||||
|
TxPrintf(" toggle Toggle the visibility of cell instances.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is called for each cell whose expansion status changed.
|
/* This function is called for each cell whose expansion status changed.
|
||||||
|
|
@ -925,12 +1040,14 @@ cmdExpandFunc(
|
||||||
#define DOALL 1
|
#define DOALL 1
|
||||||
#define DOCAPACITANCE 2
|
#define DOCAPACITANCE 2
|
||||||
#define DOCOUPLING 3
|
#define DOCOUPLING 3
|
||||||
#define DOLENGTH 4
|
#define DOEXTRESIST 4
|
||||||
#define DOLOCAL 5
|
#define DOLENGTH 5
|
||||||
#define DORESISTANCE 6
|
#define DOLOCAL 6
|
||||||
#define DOLABELCHECK 7
|
#define DORESISTANCE 7
|
||||||
#define DOALIASES 8
|
#define DOLABELCHECK 8
|
||||||
#define DOUNIQUE 9
|
#define DOALIASES 9
|
||||||
|
#define DOUNIQUE 10
|
||||||
|
#define DOEXTRESIST2 11
|
||||||
|
|
||||||
#define LENCLEAR 0
|
#define LENCLEAR 0
|
||||||
#define LENDRIVER 1
|
#define LENDRIVER 1
|
||||||
|
|
@ -973,12 +1090,14 @@ CmdExtract(
|
||||||
"all all options",
|
"all all options",
|
||||||
"capacitance extract substrate capacitance",
|
"capacitance extract substrate capacitance",
|
||||||
"coupling extract coupling capacitance",
|
"coupling extract coupling capacitance",
|
||||||
|
"extresist extract resistance",
|
||||||
"length compute driver-receiver pathlengths",
|
"length compute driver-receiver pathlengths",
|
||||||
"local put all generated files in the current directory",
|
"local put all generated files in the current directory",
|
||||||
"resistance estimate resistance",
|
"lumped estimate lumped resistance",
|
||||||
"labelcheck check for connections through sticky labels",
|
"labelcheck check for connections through sticky labels",
|
||||||
"aliases output all net name aliases",
|
"aliases output all net name aliases",
|
||||||
"unique ensure unique node names during extraction",
|
"unique ensure unique node names during extraction",
|
||||||
|
"resistance extract resistance (same as \"do extresist\")",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static const char * const cmdExtLength[] =
|
static const char * const cmdExtLength[] =
|
||||||
|
|
@ -1280,10 +1399,11 @@ CmdExtract(
|
||||||
TxPrintf("%s capacitance\n", OPTSET(EXT_DOCAPACITANCE));
|
TxPrintf("%s capacitance\n", OPTSET(EXT_DOCAPACITANCE));
|
||||||
TxPrintf("%s coupling\n", OPTSET(EXT_DOCOUPLING));
|
TxPrintf("%s coupling\n", OPTSET(EXT_DOCOUPLING));
|
||||||
TxPrintf("%s length\n", OPTSET(EXT_DOLENGTH));
|
TxPrintf("%s length\n", OPTSET(EXT_DOLENGTH));
|
||||||
TxPrintf("%s resistance\n", OPTSET(EXT_DORESISTANCE));
|
TxPrintf("%s lumped R\n", OPTSET(EXT_DORESISTANCE));
|
||||||
TxPrintf("%s label check\n", OPTSET(EXT_DOLABELCHECK));
|
TxPrintf("%s label check\n", OPTSET(EXT_DOLABELCHECK));
|
||||||
TxPrintf("%s aliases\n", OPTSET(EXT_DOALIASES));
|
TxPrintf("%s aliases\n", OPTSET(EXT_DOALIASES));
|
||||||
TxPrintf("%s unique\n", OPTSET(EXT_DOUNIQUE));
|
TxPrintf("%s unique\n", OPTSET(EXT_DOUNIQUE));
|
||||||
|
TxPrintf("%s resistance (extresist)\n", OPTSET(EXT_DOEXTRESIST));
|
||||||
return;
|
return;
|
||||||
#undef OPTSET
|
#undef OPTSET
|
||||||
}
|
}
|
||||||
|
|
@ -1314,6 +1434,8 @@ CmdExtract(
|
||||||
case DOLABELCHECK: option = EXT_DOLABELCHECK; break;
|
case DOLABELCHECK: option = EXT_DOLABELCHECK; break;
|
||||||
case DOALIASES: option = EXT_DOALIASES; break;
|
case DOALIASES: option = EXT_DOALIASES; break;
|
||||||
case DOUNIQUE: option = EXT_DOUNIQUE; break;
|
case DOUNIQUE: option = EXT_DOUNIQUE; break;
|
||||||
|
case DOEXTRESIST:
|
||||||
|
case DOEXTRESIST2: option = EXT_DOEXTRESIST; break;
|
||||||
case DOLOCAL:
|
case DOLOCAL:
|
||||||
/* "extract do local" and "extract no local" are kept for
|
/* "extract do local" and "extract no local" are kept for
|
||||||
* backwards compatibility, but now effectively implement
|
* backwards compatibility, but now effectively implement
|
||||||
|
|
|
||||||
590
commands/CmdLQ.c
590
commands/CmdLQ.c
|
|
@ -45,9 +45,8 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
|
||||||
#include "utils/undo.h"
|
#include "utils/undo.h"
|
||||||
#include "select/select.h"
|
#include "select/select.h"
|
||||||
#include "netmenu/netmenu.h"
|
#include "netmenu/netmenu.h"
|
||||||
|
|
||||||
/* C99 compat */
|
|
||||||
#include "cif/cif.h"
|
#include "cif/cif.h"
|
||||||
|
#include "cif/CIFint.h"
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
|
|
||||||
|
|
@ -518,14 +517,14 @@ CmdLoad(
|
||||||
|
|
||||||
DBExpandAll(topuse, &(topuse->cu_bbox),
|
DBExpandAll(topuse, &(topuse->cu_bbox),
|
||||||
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
||||||
TRUE, keepGoing, NULL);
|
DB_EXPAND, keepGoing, NULL);
|
||||||
|
|
||||||
DBExpandAll(topuse, &(topuse->cu_bbox),
|
DBExpandAll(topuse, &(topuse->cu_bbox),
|
||||||
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
||||||
FALSE, keepGoing, NULL);
|
DB_UNEXPAND, keepGoing, NULL);
|
||||||
DBExpand(topuse,
|
DBExpand(topuse,
|
||||||
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
||||||
TRUE);
|
DB_EXPAND);
|
||||||
|
|
||||||
/* We don't want to save and restore DBLambda, because */
|
/* We don't want to save and restore DBLambda, because */
|
||||||
/* loading the file may change their values. Instead, we */
|
/* loading the file may change their values. Instead, we */
|
||||||
|
|
@ -2296,6 +2295,8 @@ parsepositions:
|
||||||
editDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
|
editDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define PROPERTY_TYPE_COMPAT 4 /* Last entry in cmdPropertyType */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -2319,47 +2320,448 @@ parsepositions:
|
||||||
void
|
void
|
||||||
CmdDoProperty(
|
CmdDoProperty(
|
||||||
CellDef *def,
|
CellDef *def,
|
||||||
|
MagWindow *w,
|
||||||
TxCommand *cmd,
|
TxCommand *cmd,
|
||||||
int argstart)
|
int argstart)
|
||||||
{
|
{
|
||||||
int printPropertiesFunc();
|
PropertyRecord *proprec;
|
||||||
char *value;
|
char *value;
|
||||||
bool propfound;
|
bool propfound, dolist;
|
||||||
|
int proptype, proplen, propvalue, i;
|
||||||
|
dlong dvalue;
|
||||||
int locargc = cmd->tx_argc - argstart + 1;
|
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)
|
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 */
|
/* print all properties and their values */
|
||||||
DBPropEnum(def, printPropertiesFunc, NULL);
|
DBPropEnum(def, printPropertiesFunc, (ClientData)w);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (locargc == 2)
|
else if (locargc == 2)
|
||||||
{
|
{
|
||||||
/* print the value of the indicated property */
|
/* If the property type was "compat", then give the state of the
|
||||||
value = (char *)DBPropGet(def, cmd->tx_argv[argstart], &propfound);
|
* compatibility flag and return.
|
||||||
if (propfound)
|
*/
|
||||||
|
if (proptype == PROPERTY_TYPE_COMPAT)
|
||||||
|
{
|
||||||
#ifdef MAGIC_WRAPPER
|
#ifdef MAGIC_WRAPPER
|
||||||
Tcl_SetResult(magicinterp, value, NULL);
|
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(DBPropCompat));
|
||||||
#else
|
#else
|
||||||
TxPrintf("%s", value);
|
TxPrintf("%s\n", (DBPropCompat == TRUE) ? "True" : "False");
|
||||||
#endif
|
#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 {
|
else {
|
||||||
#ifdef MAGIC_WRAPPER
|
#ifdef MAGIC_WRAPPER
|
||||||
/* If the command was "cellname list property ...", then */
|
/* If the command was "cellname list property ...", then */
|
||||||
/* just return NULL if the property was not found. */
|
/* just return NULL if the property was not found. */
|
||||||
if (strcmp(cmd->tx_argv[1], "list"))
|
if (!dolist)
|
||||||
#endif
|
#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)
|
if (strlen(cmd->tx_argv[argstart + 1]) == 0)
|
||||||
DBPropPut(def, cmd->tx_argv[argstart], NULL);
|
DBPropPut(def, cmd->tx_argv[argstart], NULL);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
value = StrDup((char **)NULL, cmd->tx_argv[argstart + 1]);
|
if (proptype == PROPERTY_TYPE_STRING)
|
||||||
DBPropPut(def, cmd->tx_argv[argstart], value);
|
{
|
||||||
|
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);
|
def->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
|
||||||
}
|
}
|
||||||
|
|
@ -2380,10 +2782,14 @@ CmdDoProperty(
|
||||||
* defined in database/DBprop.c.
|
* defined in database/DBprop.c.
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* property [name] [value]
|
* property [string|integer|dimension] [name] [value]
|
||||||
*
|
*
|
||||||
* "name" is a unique string tag for the property, and "value" is its
|
* If the first argument is present, it must be one of the known
|
||||||
* string value.
|
* 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:
|
* Results:
|
||||||
* None.
|
* None.
|
||||||
|
|
@ -2410,9 +2816,62 @@ CmdProperty(
|
||||||
else
|
else
|
||||||
def = ((CellUse *) w->w_surfaceID)->cu_def;
|
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
|
* Callback function for printing a single property key:value pair
|
||||||
|
|
@ -2422,27 +2881,84 @@ CmdProperty(
|
||||||
int
|
int
|
||||||
printPropertiesFunc(
|
printPropertiesFunc(
|
||||||
const char *name,
|
const char *name,
|
||||||
ClientData value,
|
PropertyRecord *proprec,
|
||||||
ClientData cdata) /* not used */
|
MagWindow *w)
|
||||||
{
|
{
|
||||||
#ifdef MAGIC_WRAPPER
|
int i;
|
||||||
char *keyvalue;
|
|
||||||
|
|
||||||
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);
|
case PROPERTY_TYPE_STRING:
|
||||||
sprintf(keyvalue, "%s {}", name);
|
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
|
Tcl_ListObjAppendElement(magicinterp, tobj, lobj);
|
||||||
{
|
Tcl_SetObjResult(magicinterp, tobj);
|
||||||
keyvalue = (char *)mallocMagic(strlen(name) + strlen((const char *)value) + 2);
|
|
||||||
sprintf(keyvalue, "%s %s", name, (const char *)value);
|
|
||||||
}
|
|
||||||
Tcl_AppendElement(magicinterp, keyvalue);
|
|
||||||
freeMagic(keyvalue);
|
|
||||||
|
|
||||||
#else
|
#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
|
#endif
|
||||||
|
|
||||||
return 0; /* keep the search alive */
|
return 0; /* keep the search alive */
|
||||||
|
|
|
||||||
133
commands/CmdRS.c
133
commands/CmdRS.c
|
|
@ -1801,13 +1801,18 @@ cmdLabelSizeFunc(
|
||||||
|
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
{
|
{
|
||||||
|
char *labsize;
|
||||||
|
MagWindow *w;
|
||||||
|
|
||||||
|
windCheckOnlyWindow(&w, DBWclientID);
|
||||||
|
labsize = DBWPrintValue(label->lab_size / 8, w, FALSE);
|
||||||
|
|
||||||
#ifdef MAGIC_WRAPPER
|
#ifdef MAGIC_WRAPPER
|
||||||
lobj = Tcl_GetObjResult(magicinterp);
|
lobj = Tcl_GetObjResult(magicinterp);
|
||||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_NewStringObj(labsize, -1));
|
||||||
Tcl_NewDoubleObj((double)label->lab_size / 8.0));
|
|
||||||
Tcl_SetObjResult(magicinterp, lobj);
|
Tcl_SetObjResult(magicinterp, lobj);
|
||||||
#else
|
#else
|
||||||
TxPrintf("%g\n", (double)label->lab_size / 8.0);
|
TxPrintf("%s\n", labsize);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (label->lab_size != *value)
|
else if (label->lab_size != *value)
|
||||||
|
|
@ -1952,18 +1957,22 @@ cmdLabelOffsetFunc(
|
||||||
|
|
||||||
if (point == NULL)
|
if (point == NULL)
|
||||||
{
|
{
|
||||||
|
char *laboffx, *laboffy;
|
||||||
|
MagWindow *w;
|
||||||
|
|
||||||
|
windCheckOnlyWindow(&w, DBWclientID);
|
||||||
|
laboffx = DBWPrintValue(label->lab_offset.p_x / 8, w, TRUE);
|
||||||
|
laboffy = DBWPrintValue(label->lab_offset.p_x / 8, w, FALSE);
|
||||||
|
|
||||||
#ifdef MAGIC_WRAPPER
|
#ifdef MAGIC_WRAPPER
|
||||||
lobj = Tcl_GetObjResult(magicinterp);
|
lobj = Tcl_GetObjResult(magicinterp);
|
||||||
pobj = Tcl_NewListObj(0, NULL);
|
pobj = Tcl_NewListObj(0, NULL);
|
||||||
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
|
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
|
||||||
Tcl_ListObjAppendElement(magicinterp, pobj,
|
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laboffx, -1));
|
||||||
Tcl_NewDoubleObj((double)label->lab_offset.p_x / 8.0));
|
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laboffy, -1));
|
||||||
Tcl_ListObjAppendElement(magicinterp, pobj,
|
|
||||||
Tcl_NewDoubleObj((double)label->lab_offset.p_y / 8.0));
|
|
||||||
Tcl_SetObjResult(magicinterp, lobj);
|
Tcl_SetObjResult(magicinterp, lobj);
|
||||||
#else
|
#else
|
||||||
TxPrintf("%g %g\n", (double)(label->lab_offset.p_x) / 8.0,
|
TxPrintf("%s %s\n", laboffx, laboffy);
|
||||||
(double)(label->lab_offset.p_y) / 8.0);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (!GEO_SAMEPOINT(label->lab_offset, *point))
|
else if (!GEO_SAMEPOINT(label->lab_offset, *point))
|
||||||
|
|
@ -2212,9 +2221,13 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelTextFunc, (locargc == 3) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)cmd->tx_argv[argstart + 1] : (ClientData)NULL);
|
cmdLabelTextFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelTextFunc,
|
||||||
|
(ClientData)cmd->tx_argv[argstart + 1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2280,9 +2293,12 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelFontFunc, (locargc == 3) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)&font : (ClientData)NULL);
|
cmdLabelFontFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelFontFunc, (ClientData)&font);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -2310,9 +2326,12 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelJustFunc, (locargc == 3) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)&pos : (ClientData)NULL);
|
cmdLabelJustFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelJustFunc, (ClientData)&pos);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2341,9 +2360,12 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelSizeFunc, (locargc == 3) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)&size : (ClientData)NULL);
|
cmdLabelSizeFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelSizeFunc, (ClientData)&size);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2393,9 +2415,12 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelOffsetFunc, (locargc != 2) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)&offset : (ClientData)NULL);
|
cmdLabelOffsetFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelOffsetFunc, (ClientData)&offset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2459,10 +2484,12 @@ CmdSetLabel(
|
||||||
rect.r_ytop = cmdScaleCoord(w, cmd->tx_argv[argstart + 4],
|
rect.r_ytop = cmdScaleCoord(w, cmd->tx_argv[argstart + 4],
|
||||||
TRUE, FALSE, 1);
|
TRUE, FALSE, 1);
|
||||||
}
|
}
|
||||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if ((locargc == 3) || (locargc == 6))
|
||||||
cmdLabelRectFunc,
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
((locargc == 6) || (locargc == 3)) ?
|
cmdLabelRectFunc, (ClientData)&rect);
|
||||||
(ClientData)&rect : (ClientData)NULL);
|
else
|
||||||
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelRectFunc, (ClientData)NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2488,9 +2515,12 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelRotateFunc, (locargc == 3) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)&rotate : (ClientData)NULL);
|
cmdLabelRotateFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelRotateFunc, (ClientData)&rotate);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2522,9 +2552,12 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelStickyFunc, (locargc == 3) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)&flags : (ClientData)NULL);
|
cmdLabelStickyFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelStickyFunc, (ClientData)&flags);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2563,9 +2596,12 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelLayerFunc, (locargc == 3) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)&ttype : (ClientData)NULL);
|
cmdLabelLayerFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelLayerFunc, (ClientData)&ttype);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2900,6 +2936,29 @@ CmdSnap(
|
||||||
TxPrintf("Usage: snap [internal | lambda | user]\n");
|
TxPrintf("Usage: snap [internal | lambda | user]\n");
|
||||||
return;
|
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)
|
switch (n)
|
||||||
{
|
{
|
||||||
case SNAP_OFF: case SNAP_INTERNAL:
|
case SNAP_OFF: case SNAP_INTERNAL:
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,9 @@ cmdScaleCoord(
|
||||||
* "snap" setting. This behavior remains in effect until the "units"
|
* "snap" setting. This behavior remains in effect until the "units"
|
||||||
* command is used, in which case units follow the selected units
|
* command is used, in which case units follow the selected units
|
||||||
* value indepedendently of the snap setting.
|
* 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)
|
if (DBWUnits == DBW_UNITS_DEFAULT)
|
||||||
curunits = DBWSnapToGrid;
|
curunits = DBWSnapToGrid;
|
||||||
|
|
@ -163,19 +166,22 @@ cmdScaleCoord(
|
||||||
curunits = DBWUnits & DBW_UNITS_TYPE_MASK;
|
curunits = DBWUnits & DBW_UNITS_TYPE_MASK;
|
||||||
|
|
||||||
if ((*endptr == 'l')
|
if ((*endptr == 'l')
|
||||||
|| ((*endptr == '\0') && (curunits == DBW_UNITS_LAMBDA)))
|
|| (((*endptr == '\0') || isspace(*endptr))
|
||||||
|
&& (curunits == DBW_UNITS_LAMBDA)))
|
||||||
{
|
{
|
||||||
/* lambda or default units */
|
/* lambda or default units */
|
||||||
dval *= (double)DBLambda[1];
|
dval *= (double)DBLambda[1];
|
||||||
dval /= (double)DBLambda[0];
|
dval /= (double)DBLambda[0];
|
||||||
}
|
}
|
||||||
else if ((*endptr == 'i')
|
else if ((*endptr == 'i')
|
||||||
|| ((*endptr == '\0') && (curunits == DBW_UNITS_INTERNAL)))
|
|| (((*endptr == '\0') || isspace(*endptr))
|
||||||
|
&& (curunits == DBW_UNITS_INTERNAL)))
|
||||||
{
|
{
|
||||||
/* internal units */
|
/* internal units */
|
||||||
}
|
}
|
||||||
else if ((*endptr == 'g')
|
else if ((*endptr == 'g')
|
||||||
|| ((*endptr == '\0') && (curunits == DBW_UNITS_USER)))
|
|| (((*endptr == '\0') || isspace(*endptr))
|
||||||
|
&& (curunits == DBW_UNITS_USER)))
|
||||||
{
|
{
|
||||||
/* grid units */
|
/* grid units */
|
||||||
if (w == (MagWindow *)NULL)
|
if (w == (MagWindow *)NULL)
|
||||||
|
|
@ -203,11 +209,12 @@ cmdScaleCoord(
|
||||||
dval += (double)crec->dbw_gridRect.r_ybot;
|
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;
|
mscale = 1000;
|
||||||
}
|
}
|
||||||
else
|
else if (*endptr != '\0')
|
||||||
{
|
{
|
||||||
/* natural units referred to the current cifoutput style */
|
/* natural units referred to the current cifoutput style */
|
||||||
if (*(endptr + 1) == 'm')
|
if (*(endptr + 1) == 'm')
|
||||||
|
|
@ -249,7 +256,7 @@ cmdScaleCoord(
|
||||||
mscale = -1;
|
mscale = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((mscale != -1) && !isspace(*endptr))
|
if (mscale != -1)
|
||||||
dval /= CIFGetOutputScale(mscale);
|
dval /= CIFGetOutputScale(mscale);
|
||||||
curval = round(dval);
|
curval = round(dval);
|
||||||
|
|
||||||
|
|
@ -297,9 +304,13 @@ cmdScaleCoord(
|
||||||
parseop = PARSEOP_DIV;
|
parseop = PARSEOP_DIV;
|
||||||
endptr++;
|
endptr++;
|
||||||
break;
|
break;
|
||||||
default:
|
case ' ':
|
||||||
|
case '\t':
|
||||||
endptr++;
|
endptr++;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
/* Should this flag an error? */
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
if (parseop != PARSEOP_NONE) break;
|
if (parseop != PARSEOP_NONE) break;
|
||||||
}
|
}
|
||||||
|
|
@ -750,13 +761,16 @@ cmdSaveCell(
|
||||||
if (!tryRename || (fileName == NULL) || (strcmp(cellDef->cd_name, fileName) == 0))
|
if (!tryRename || (fileName == NULL) || (strcmp(cellDef->cd_name, fileName) == 0))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* Rename the cell */
|
/* Rename the cell, unless fileName is a .tcl file (scripted output) */
|
||||||
if (!DBCellRenameDef(cellDef, fileName))
|
if ((strlen(fileName) <= 4) || strcmp(fileName + strlen(fileName) - 4, ".tcl"))
|
||||||
{
|
{
|
||||||
/* This should never happen */
|
if (!DBCellRenameDef(cellDef, fileName))
|
||||||
TxError("Magic error: there is already a cell named \"%s\"\n",
|
{
|
||||||
|
/* This should never happen */
|
||||||
|
TxError("Magic error: there is already a cell named \"%s\"\n",
|
||||||
fileName);
|
fileName);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EditCellUse && (cellDef == EditCellUse->cu_def))
|
if (EditCellUse && (cellDef == EditCellUse->cu_def))
|
||||||
|
|
@ -1225,7 +1239,7 @@ cmdExpandOneLevel(
|
||||||
extern int cmdExpand1func(CellUse *cu, ClientData bitmask);
|
extern int cmdExpand1func(CellUse *cu, ClientData bitmask);
|
||||||
|
|
||||||
/* first, expand this cell use */
|
/* first, expand this cell use */
|
||||||
DBExpand(cu, bitmask, expand);
|
DBExpand(cu, bitmask, expand ? DB_EXPAND : DB_UNEXPAND);
|
||||||
|
|
||||||
/* now, unexpand its direct children (ONE LEVEL ONLY) */
|
/* now, unexpand its direct children (ONE LEVEL ONLY) */
|
||||||
if (expand)
|
if (expand)
|
||||||
|
|
@ -1237,7 +1251,7 @@ cmdExpand1func(
|
||||||
CellUse *cu,
|
CellUse *cu,
|
||||||
ClientData bitmask)
|
ClientData bitmask)
|
||||||
{
|
{
|
||||||
DBExpand(cu, (int)CD2INT(bitmask), FALSE);
|
DBExpand(cu, (int)CD2INT(bitmask), DB_UNEXPAND);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -702,32 +702,62 @@ CmdTool(
|
||||||
* Implement the "unexpand" command.
|
* Implement the "unexpand" command.
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* unexpand
|
* unexpand [selection|surround|overlap|all]
|
||||||
|
*
|
||||||
|
* "selection" unexpands (hides) cells in the selection. All
|
||||||
|
* other options unexpand cells in the layout. "all" unexpands
|
||||||
|
* all cells in the layout. "surround" unexpannds cells which
|
||||||
|
* the cursor box surrounds completely, and "overlap" unexpands
|
||||||
|
* cells which the cursor box overlaps.
|
||||||
|
*
|
||||||
|
* For backwards compatibility:
|
||||||
|
* "unexpand" alone implements "unexpand surround".
|
||||||
|
*
|
||||||
|
* Also see: CmdExpand
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* None.
|
* None.
|
||||||
*
|
*
|
||||||
* Side effects:
|
* Side effects:
|
||||||
* Unexpands all cells under the box that don't completely
|
* Changes the expansion state of cells.
|
||||||
* contain the box.
|
|
||||||
*
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define UNEXPAND_SELECTION 0
|
||||||
|
#define UNEXPAND_SURROUND 1
|
||||||
|
#define UNEXPAND_OVERLAP 2
|
||||||
|
#define UNEXPAND_ALL 3
|
||||||
|
#define UNEXPAND_HELP 4
|
||||||
|
|
||||||
void
|
void
|
||||||
CmdUnexpand(
|
CmdUnexpand(
|
||||||
MagWindow *w,
|
MagWindow *w,
|
||||||
TxCommand *cmd)
|
TxCommand *cmd)
|
||||||
{
|
{
|
||||||
int windowMask, boxMask;
|
int windowMask, boxMask, option;
|
||||||
|
const char * const *msg;
|
||||||
Rect rootRect;
|
Rect rootRect;
|
||||||
|
|
||||||
int cmdUnexpandFunc(CellUse *use, int windowMask); /* Forward reference. */
|
int cmdUnexpandFunc(CellUse *use, int windowMask); /* Forward reference. */
|
||||||
|
|
||||||
if (cmd->tx_argc != 1)
|
static const char * const cmdUnexpandOption[] = {
|
||||||
|
"selection expand cell instances in the selection",
|
||||||
|
"surround expand cell instances which the cursor box surrounds",
|
||||||
|
"overlap expand cell instances which the cursor box overlaps",
|
||||||
|
"all expand all cell instances",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
if (cmd->tx_argc > 1)
|
||||||
{
|
{
|
||||||
TxError("Usage: %s\n", cmd->tx_argv[0]);
|
option = Lookup(cmd->tx_argv[1], cmdUnexpandOption);
|
||||||
return;
|
if (option < 0) option = UNEXPAND_HELP;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
option = UNEXPAND_SURROUND;
|
||||||
|
|
||||||
|
if (option == UNEXPAND_HELP) goto badusage;
|
||||||
|
|
||||||
windCheckOnlyWindow(&w, DBWclientID);
|
windCheckOnlyWindow(&w, DBWclientID);
|
||||||
if (w == (MagWindow *) NULL)
|
if (w == (MagWindow *) NULL)
|
||||||
|
|
@ -743,8 +773,42 @@ CmdUnexpand(
|
||||||
TxError("The box isn't in the same window as the cursor.\n");
|
TxError("The box isn't in the same window as the cursor.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DBExpandAll(((CellUse *) w->w_surfaceID), &rootRect, windowMask,
|
|
||||||
FALSE, cmdUnexpandFunc, (ClientData)(pointertype) windowMask);
|
switch (option)
|
||||||
|
{
|
||||||
|
case UNEXPAND_SELECTION:
|
||||||
|
SelectExpand(windowMask, DB_UNEXPAND, (Rect *)NULL, FALSE);
|
||||||
|
break;
|
||||||
|
case UNEXPAND_OVERLAP:
|
||||||
|
DBExpandAll(((CellUse *)w->w_surfaceID), &rootRect, windowMask,
|
||||||
|
DB_UNEXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
cmdUnexpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_UNEXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
&rootRect, FALSE);
|
||||||
|
break;
|
||||||
|
case UNEXPAND_SURROUND:
|
||||||
|
DBExpandAll(((CellUse *)w->w_surfaceID), &rootRect, windowMask,
|
||||||
|
DB_UNEXPAND | DB_EXPAND_SURROUND,
|
||||||
|
cmdUnexpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_UNEXPAND | DB_EXPAND_SURROUND,
|
||||||
|
&rootRect, TRUE);
|
||||||
|
break;
|
||||||
|
case UNEXPAND_ALL:
|
||||||
|
DBExpandAll(((CellUse *)w->w_surfaceID), &TiPlaneRect, windowMask,
|
||||||
|
DB_UNEXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
cmdUnexpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_UNEXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
(Rect *)NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
badusage:
|
||||||
|
for (msg = &(cmdUnexpandOption[0]); *msg != NULL; msg++)
|
||||||
|
TxPrintf(" %s\n", *msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is called for each cell whose expansion status changed.
|
/* This function is called for each cell whose expansion status changed.
|
||||||
|
|
@ -1887,10 +1951,10 @@ CmdWire(
|
||||||
wdisp = DBWPrintValue(width, w, TRUE);
|
wdisp = DBWPrintValue(width, w, TRUE);
|
||||||
#ifdef MAGIC_WRAPPER
|
#ifdef MAGIC_WRAPPER
|
||||||
lobj = Tcl_NewListObj(0, NULL);
|
lobj = Tcl_NewListObj(0, NULL);
|
||||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
|
||||||
Tcl_NewStringObj(wdisp, -1));
|
|
||||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||||
Tcl_NewStringObj(DBTypeLongNameTbl[type], -1));
|
Tcl_NewStringObj(DBTypeLongNameTbl[type], -1));
|
||||||
|
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||||
|
Tcl_NewStringObj(wdisp, -1));
|
||||||
Tcl_SetObjResult(magicinterp, lobj);
|
Tcl_SetObjResult(magicinterp, lobj);
|
||||||
#else
|
#else
|
||||||
TxPrintf("Wire layer %s, width %s\n",
|
TxPrintf("Wire layer %s, width %s\n",
|
||||||
|
|
|
||||||
|
|
@ -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 cmdSaveCell(CellDef *cellDef, char *newName, bool noninteractive, bool tryRename);
|
||||||
extern void CmdInit(void);
|
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);
|
extern void CmdPaintEraseButton(MagWindow *w, Point *refPoint, bool isPaint, bool isScreen);
|
||||||
|
|
||||||
#endif /* _MAGIC__COMMANDS__COMMANDS_H */
|
#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 "windows/windows.h"
|
||||||
#include "dbwind/dbwind.h"
|
#include "dbwind/dbwind.h"
|
||||||
#include "commands/commands.h"
|
#include "commands/commands.h"
|
||||||
|
|
||||||
/* C99 compat */
|
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
#include "cif/CIFint.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following variable points to the tables currently used for
|
* The following variable points to the tables currently used for
|
||||||
|
|
@ -357,9 +356,43 @@ DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func)
|
||||||
struct propUseDefStruct {
|
struct propUseDefStruct {
|
||||||
CellDef *puds_source;
|
CellDef *puds_source;
|
||||||
CellDef *puds_dest;
|
CellDef *puds_dest;
|
||||||
|
Plane *puds_plane; /* Mask hint plane in dest */
|
||||||
Transform *puds_trans; /* Transform from source use to 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
|
int
|
||||||
dbCopyMaskHintsFunc(key, value, puds)
|
dbCopyMaskHintsFunc(key, proprec, puds)
|
||||||
char *key;
|
char *key;
|
||||||
ClientData value;
|
PropertyRecord *proprec;
|
||||||
struct propUseDefStruct *puds;
|
struct propUseDefStruct *puds;
|
||||||
{
|
{
|
||||||
CellDef *dest = puds->puds_dest;
|
CellDef *dest = puds->puds_dest;
|
||||||
Transform *trans = puds->puds_trans;
|
Transform *trans = puds->puds_trans;
|
||||||
char *propstr = (char *)value;
|
Rect *clip = puds->puds_area;
|
||||||
|
PropertyRecord *parentproprec, *newproprec;
|
||||||
char *parentprop, *newvalue, *vptr;
|
char *parentprop, *newvalue, *vptr;
|
||||||
Rect r, rnew;
|
Rect r, rnew;
|
||||||
bool propfound;
|
bool propfound;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
if (!strncmp(key, "MASKHINTS_", 10))
|
if (!strncmp(key, "MASKHINTS_", 10))
|
||||||
{
|
{
|
||||||
char *vptr, *lastval;
|
char *vptr, *lastval;
|
||||||
int lastlen;
|
int lastlen;
|
||||||
|
Plane *plane;
|
||||||
|
|
||||||
/* Append to existing mask hint (if any) */
|
ASSERT(proprec->prop_type == PROPERTY_TYPE_PLANE, "dbCopyMaskHintsFunc");
|
||||||
parentprop = (char *)DBPropGet(dest, key, &propfound);
|
|
||||||
newvalue = (propfound) ? StrDup((char **)NULL, parentprop) : (char *)NULL;
|
|
||||||
|
|
||||||
vptr = propstr;
|
/* Get the existing mask hint plane in the parent cell, and
|
||||||
while (*vptr != '\0')
|
* 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,
|
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||||
&r.r_xtop, &r.r_ytop) == 4)
|
newproprec->prop_type = PROPERTY_TYPE_PLANE;
|
||||||
{
|
newproprec->prop_len = 0;
|
||||||
GeoTransRect(trans, &r, &rnew);
|
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||||
|
newproprec->prop_value.prop_plane = plane;
|
||||||
lastval = newvalue;
|
DBPropPut(dest, key, newproprec);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
if (newvalue)
|
puds->puds_plane = plane;
|
||||||
DBPropPut(dest, key, newvalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -468,6 +490,7 @@ DBCellCopyMaskHints(child, parent, transform)
|
||||||
puds.puds_source = child->cu_def;
|
puds.puds_source = child->cu_def;
|
||||||
puds.puds_dest = parent;
|
puds.puds_dest = parent;
|
||||||
puds.puds_trans = transform;
|
puds.puds_trans = transform;
|
||||||
|
puds.puds_area = (Rect *)&TiPlaneRect;
|
||||||
DBPropEnum(child->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
|
DBPropEnum(child->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -501,6 +524,7 @@ dbFlatCopyMaskHintsFunc(scx, def)
|
||||||
puds.puds_source = scx->scx_use->cu_def;
|
puds.puds_source = scx->scx_use->cu_def;
|
||||||
puds.puds_dest = def;
|
puds.puds_dest = def;
|
||||||
puds.puds_trans = &scx->scx_trans;
|
puds.puds_trans = &scx->scx_trans;
|
||||||
|
puds.puds_area = &scx->scx_area;
|
||||||
|
|
||||||
DBPropEnum(use->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
|
DBPropEnum(use->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -152,10 +152,9 @@ DBCellRename(cellname, newname, doforce)
|
||||||
|
|
||||||
if (doforce && ((celldef->cd_flags & CDVENDORGDS) == CDVENDORGDS))
|
if (doforce && ((celldef->cd_flags & CDVENDORGDS) == CDVENDORGDS))
|
||||||
{
|
{
|
||||||
char *chkgdsfile;
|
|
||||||
bool isReadOnly;
|
bool isReadOnly;
|
||||||
|
|
||||||
chkgdsfile = (char *)DBPropGet(celldef, "GDS_FILE", &isReadOnly);
|
DBPropGet(celldef, "GDS_FILE", &isReadOnly);
|
||||||
/* Note that clearing GDS_FILE will also clear CDVENDORGDS flag */
|
/* Note that clearing GDS_FILE will also clear CDVENDORGDS flag */
|
||||||
if (isReadOnly) DBPropPut(celldef, "GDS_FILE", NULL);
|
if (isReadOnly) DBPropPut(celldef, "GDS_FILE", NULL);
|
||||||
|
|
||||||
|
|
@ -1620,6 +1619,7 @@ dbAbutmentUseFunc(selUse, use, transform, data)
|
||||||
{
|
{
|
||||||
Rect bbox, refbox;
|
Rect bbox, refbox;
|
||||||
Transform *trans;
|
Transform *trans;
|
||||||
|
PropertyRecord *proprec;
|
||||||
char *propvalue;
|
char *propvalue;
|
||||||
char *refllx, *reflly, *refurx, *refury;
|
char *refllx, *reflly, *refurx, *refury;
|
||||||
bool found;
|
bool found;
|
||||||
|
|
@ -1643,14 +1643,25 @@ dbAbutmentUseFunc(selUse, use, transform, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
trans = &use->cu_transform;
|
trans = &use->cu_transform;
|
||||||
propvalue = (char *)DBPropGet(use->cu_def, "FIXED_BBOX", &found);
|
proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
|
||||||
if (!found)
|
if (!found)
|
||||||
bbox = use->cu_def->cd_bbox;
|
bbox = use->cu_def->cd_bbox;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||||
&bbox.r_xtop, &bbox.r_ytop) != 4)
|
(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;
|
bbox = use->cu_def->cd_bbox;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GeoTransRect(trans, &bbox, &refbox);
|
GeoTransRect(trans, &bbox, &refbox);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -588,6 +588,25 @@ DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
|
||||||
if (!DBCellRead(def, TRUE, TRUE, NULL))
|
if (!DBCellRead(def, TRUE, TRUE, NULL))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (flags & TF_LABEL_REVERSE_SEARCH)
|
||||||
|
{
|
||||||
|
/* Search children first */
|
||||||
|
filter.tf_func = func;
|
||||||
|
filter.tf_arg = cdarg;
|
||||||
|
filter.tf_mask = mask;
|
||||||
|
filter.tf_xmask = xMask;
|
||||||
|
filter.tf_tpath = tpath;
|
||||||
|
filter.tf_flags = flags;
|
||||||
|
|
||||||
|
scx2 = *scx;
|
||||||
|
if (scx2.scx_area.r_xbot > TiPlaneRect.r_xbot) scx2.scx_area.r_xbot -= 1;
|
||||||
|
if (scx2.scx_area.r_ybot > TiPlaneRect.r_ybot) scx2.scx_area.r_ybot -= 1;
|
||||||
|
if (scx2.scx_area.r_xtop < TiPlaneRect.r_xtop) scx2.scx_area.r_xtop += 1;
|
||||||
|
if (scx2.scx_area.r_ytop < TiPlaneRect.r_ytop) scx2.scx_area.r_ytop += 1;
|
||||||
|
if (DBCellSrArea(&scx2, dbCellLabelSrFunc, (ClientData) &filter))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
||||||
{
|
{
|
||||||
if (SigInterruptPending) break;
|
if (SigInterruptPending) break;
|
||||||
|
|
@ -640,6 +659,8 @@ DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & TF_LABEL_REVERSE_SEARCH) return 0; /* children already searched */
|
||||||
|
|
||||||
filter.tf_func = func;
|
filter.tf_func = func;
|
||||||
filter.tf_arg = cdarg;
|
filter.tf_arg = cdarg;
|
||||||
filter.tf_mask = mask;
|
filter.tf_mask = mask;
|
||||||
|
|
@ -711,6 +732,16 @@ dbCellLabelSrFunc(scx, fp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If fp->tf_flags has TF_LABEL_REVERSE_SEARCH, then search child
|
||||||
|
* uses first, then the parent. This is for display, so that if
|
||||||
|
* a child cell and parent cell have overlapping labels, the parent
|
||||||
|
* label is the one on top.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (fp->tf_flags & TF_LABEL_REVERSE_SEARCH)
|
||||||
|
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
|
||||||
|
result = 1;
|
||||||
|
|
||||||
/* Apply the function first to any of the labels in this def. */
|
/* Apply the function first to any of the labels in this def. */
|
||||||
|
|
||||||
result = 0;
|
result = 0;
|
||||||
|
|
@ -732,9 +763,11 @@ dbCellLabelSrFunc(scx, fp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now visit each child use recursively */
|
/* Now visit each child use recursively, if not doing a reverse search */
|
||||||
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
|
|
||||||
result = 1;
|
if (!(fp->tf_flags & TF_LABEL_REVERSE_SEARCH))
|
||||||
|
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
|
||||||
|
result = 1;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
/* Remove the trailing pathname component from the TerminalPath */
|
/* Remove the trailing pathname component from the TerminalPath */
|
||||||
|
|
@ -1713,7 +1746,7 @@ dbTileMoveFunc(tile, dinfo, mvvals)
|
||||||
if (IsSplit(tile))
|
if (IsSplit(tile))
|
||||||
type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
|
type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
|
||||||
DBNMPaintPlane(mvvals->ptarget, exact, &targetRect,
|
DBNMPaintPlane(mvvals->ptarget, exact, &targetRect,
|
||||||
DBStdPaintTbl(type, mvvals->pnum),
|
(mvvals->pnum < 0) ? CIFPaintTable : DBStdPaintTbl(type, mvvals->pnum),
|
||||||
(PaintUndoInfo *)NULL);
|
(PaintUndoInfo *)NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1806,84 +1839,48 @@ typedef struct _cellpropstruct {
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int dbScaleProp(name, value, cps)
|
int dbScaleProp(name, proprec, cps)
|
||||||
char *name;
|
char *name;
|
||||||
char *value;
|
PropertyRecord *proprec;
|
||||||
CellPropStruct *cps;
|
CellPropStruct *cps;
|
||||||
{
|
{
|
||||||
int scalen, scaled;
|
int i, scalen, scaled;
|
||||||
char *newvalue, *vptr;
|
Point p;
|
||||||
Rect r;
|
|
||||||
|
|
||||||
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,
|
Plane *newplane;
|
||||||
&r.r_xtop, &r.r_ytop) == 4)
|
newplane = DBNewPlane((ClientData)TT_SPACE);
|
||||||
{
|
DBClearPaintPlane(newplane);
|
||||||
/* Scale numerator held in point X value, */
|
/* Plane index is unused; arbitrarily substitute -1 */
|
||||||
/* scale denominator held in point Y value */
|
dbScalePlane(proprec->prop_value.prop_plane, newplane, -1,
|
||||||
|
scalen, scaled, TRUE);
|
||||||
scalen = cps->cps_point.p_x;
|
DBFreePaintPlane(proprec->prop_value.prop_plane);
|
||||||
scaled = cps->cps_point.p_y;
|
TiFreePlane(proprec->prop_value.prop_plane);
|
||||||
|
proprec->prop_value.prop_plane = newplane;
|
||||||
DBScalePoint(&r.r_ll, scalen, scaled);
|
return 0;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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;
|
if ((i + 1) >= proprec->prop_len) break;
|
||||||
int lastlen;
|
|
||||||
|
|
||||||
newvalue = (char *)NULL;
|
p.p_x = proprec->prop_value.prop_integer[i];
|
||||||
vptr = value;
|
p.p_y = proprec->prop_value.prop_integer[i + 1];
|
||||||
while (*vptr != '\0')
|
DBScalePoint(&p, scalen, scaled);
|
||||||
{
|
proprec->prop_value.prop_integer[i] = p.p_x;
|
||||||
if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
|
proprec->prop_value.prop_integer[i + 1] = p.p_y;
|
||||||
&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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0; /* Keep enumerating through properties */
|
return 0; /* Keep enumerating through properties */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1899,33 +1896,47 @@ int dbScaleProp(name, value, cps)
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int dbMoveProp(name, value, cps)
|
int dbMoveProp(name, proprec, cps)
|
||||||
char *name;
|
char *name;
|
||||||
char *value;
|
PropertyRecord *proprec;
|
||||||
CellPropStruct *cps;
|
CellPropStruct *cps;
|
||||||
{
|
{
|
||||||
int origx, origy;
|
int i, origx, origy;
|
||||||
char *newvalue;
|
char *newvalue;
|
||||||
Rect r;
|
Point p;
|
||||||
|
|
||||||
if (((strlen(name) > 5) && !strncmp(name + strlen(name) - 5, "_BBOX", 5))
|
/* Only "dimension" and "plane" type properties get scaled */
|
||||||
|| !strncmp(name, "MASKHINTS_", 10))
|
|
||||||
|
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
|
||||||
{
|
{
|
||||||
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
|
Plane *newplane;
|
||||||
&r.r_xtop, &r.r_ytop) == 4)
|
|
||||||
{
|
|
||||||
origx = cps->cps_point.p_x;
|
|
||||||
origy = cps->cps_point.p_y;
|
|
||||||
|
|
||||||
DBMovePoint(&r.r_ll, origx, origy);
|
newplane = DBNewPlane((ClientData) TT_SPACE);
|
||||||
DBMovePoint(&r.r_ur, origx, origy);
|
DBClearPaintPlane(newplane);
|
||||||
|
/* Use plane index -1 to indicate use of CIFPaintTable */
|
||||||
newvalue = (char *)mallocMagic(40);
|
dbMovePlane(proprec->prop_value.prop_plane, newplane, -1, origx, origy);
|
||||||
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
|
DBFreePaintPlane(proprec->prop_value.prop_plane);
|
||||||
r.r_xtop, r.r_ytop);
|
TiFreePlane(proprec->prop_value.prop_plane);
|
||||||
DBPropPut(cps->cps_def, name, newvalue);
|
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 */
|
return 0; /* Keep enumerating through properties */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ struct expandArg
|
||||||
{
|
{
|
||||||
bool ea_deref; /* TRUE if root def dereference flag is set */
|
bool ea_deref; /* TRUE if root def dereference flag is set */
|
||||||
int ea_xmask; /* Expand mask. */
|
int ea_xmask; /* Expand mask. */
|
||||||
|
int ea_type; /* Expand, unexpand, or toggle */
|
||||||
int (*ea_func)(); /* Function to call for each cell whose
|
int (*ea_func)(); /* Function to call for each cell whose
|
||||||
* status is changed.
|
* status is changed.
|
||||||
*/
|
*/
|
||||||
|
|
@ -67,15 +68,22 @@ struct expandArg
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
DBExpand(cellUse, expandMask, expandFlag)
|
DBExpand(cellUse, expandMask, expandType)
|
||||||
CellUse *cellUse;
|
CellUse *cellUse;
|
||||||
int expandMask;
|
int expandMask;
|
||||||
bool expandFlag;
|
int expandType;
|
||||||
{
|
{
|
||||||
CellDef *def;
|
CellDef *def;
|
||||||
|
bool expandFlag, expandTest;
|
||||||
if (DBDescendSubcell(cellUse, expandMask) == expandFlag)
|
|
||||||
return;
|
expandTest = DBDescendSubcell(cellUse, expandMask);
|
||||||
|
if ((expandType & DB_EXPAND_MASK) == DB_EXPAND_TOGGLE)
|
||||||
|
expandFlag = expandTest;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
expandFlag = ((expandType & DB_EXPAND_MASK) == DB_EXPAND) ? TRUE : FALSE;
|
||||||
|
if (expandFlag == expandTest) return;
|
||||||
|
}
|
||||||
|
|
||||||
if (expandFlag)
|
if (expandFlag)
|
||||||
{
|
{
|
||||||
|
|
@ -130,17 +138,17 @@ DBExpand(cellUse, expandMask, expandFlag)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
DBExpandAll(rootUse, rootRect, expandMask, expandFlag, func, cdarg)
|
DBExpandAll(rootUse, rootRect, expandMask, expandType, func, cdarg)
|
||||||
CellUse *rootUse; /* Root cell use from which search begins */
|
CellUse *rootUse; /* Root cell use from which search begins */
|
||||||
Rect *rootRect; /* Area to be expanded, in root coordinates */
|
Rect *rootRect; /* Area to be expanded, in root coordinates */
|
||||||
int expandMask; /* Window mask in which cell is to be expanded */
|
int expandMask; /* Window mask in which cell is to be expanded */
|
||||||
bool expandFlag; /* TRUE => expand, FALSE => unexpand */
|
int expandType; /* DB_EXPAND, DB_UNEXPAND, DB_EXPAND_TOGGLE */
|
||||||
int (*func)(); /* Function to call for each cell whose expansion
|
int (*func)(); /* Function to call for each cell whose expansion
|
||||||
* status is modified. NULL means don't call anyone.
|
* status is modified. NULL means don't call anyone.
|
||||||
*/
|
*/
|
||||||
ClientData cdarg; /* Argument to pass to func. */
|
ClientData cdarg; /* Argument to pass to func. */
|
||||||
{
|
{
|
||||||
int dbExpandFunc(), dbUnexpandFunc();
|
int dbExpandFunc();
|
||||||
SearchContext scontext;
|
SearchContext scontext;
|
||||||
struct expandArg arg;
|
struct expandArg arg;
|
||||||
|
|
||||||
|
|
@ -148,29 +156,26 @@ DBExpandAll(rootUse, rootRect, expandMask, expandFlag, func, cdarg)
|
||||||
(void) DBCellRead(rootUse->cu_def, TRUE, TRUE, NULL);
|
(void) DBCellRead(rootUse->cu_def, TRUE, TRUE, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Walk through the area and set the expansion state
|
* Walk through the area and set the expansion state appropriately.
|
||||||
* appropriately.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
arg.ea_xmask = expandMask;
|
arg.ea_xmask = expandMask;
|
||||||
arg.ea_func = func;
|
arg.ea_func = func;
|
||||||
arg.ea_arg = cdarg;
|
arg.ea_arg = cdarg;
|
||||||
|
arg.ea_type = expandType;
|
||||||
arg.ea_deref = (rootUse->cu_def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
arg.ea_deref = (rootUse->cu_def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||||
|
|
||||||
scontext.scx_use = rootUse;
|
scontext.scx_use = rootUse;
|
||||||
scontext.scx_trans = GeoIdentityTransform;
|
scontext.scx_trans = GeoIdentityTransform;
|
||||||
scontext.scx_area = *rootRect;
|
scontext.scx_area = *rootRect;
|
||||||
if (expandFlag)
|
DBCellSrArea(&scontext, dbExpandFunc, (ClientData) &arg);
|
||||||
DBCellSrArea(&scontext, dbExpandFunc, (ClientData) &arg);
|
|
||||||
else
|
|
||||||
DBCellSrArea(&scontext, dbUnexpandFunc, (ClientData) &arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dbExpandFunc --
|
* dbExpandFunc --
|
||||||
*
|
*
|
||||||
* Filter function called by DBCellSrArea on behalf of DBExpandAll above
|
* Filter function called by DBCellSrArea on behalf of DBExpandAll above
|
||||||
* when cells are being expanded.
|
* when cells are being expanded, unexpanded, or toggled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -184,68 +189,55 @@ dbExpandFunc(scx, arg)
|
||||||
{
|
{
|
||||||
CellUse *childUse = scx->scx_use;
|
CellUse *childUse = scx->scx_use;
|
||||||
int n = DBLambda[1];
|
int n = DBLambda[1];
|
||||||
|
int expandTest;
|
||||||
|
int expandType = (arg->ea_type & DB_EXPAND_MASK);
|
||||||
|
int expandSurround = (arg->ea_type & DB_EXPAND_SURROUND_MASK);
|
||||||
|
bool surround;
|
||||||
|
|
||||||
|
expandTest = DBDescendSubcell(childUse, arg->ea_xmask);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Change the expansion status of this cell if necessary. Call the
|
* Change the expansion status of this cell if necessary. Call the
|
||||||
* client's function if the expansion status has changed.
|
* client's function if the expansion status has changed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!DBDescendSubcell(childUse, arg->ea_xmask))
|
if (!expandTest && ((expandType == DB_EXPAND) || (expandType == DB_EXPAND_TOGGLE)))
|
||||||
{
|
{
|
||||||
/* If the cell is unavailable, then don't expand it.
|
surround = (!GEO_SURROUND(&childUse->cu_def->cd_bbox, &scx->scx_area)
|
||||||
*/
|
|| GEO_SURROUND(&scx->scx_area, &childUse->cu_def->cd_bbox));
|
||||||
if ((childUse->cu_def->cd_flags & CDAVAILABLE) == 0)
|
if (surround || (expandSurround == DB_EXPAND_OVERLAP))
|
||||||
{
|
{
|
||||||
/* If the parent is dereferenced, then the child should be, too */
|
/* If the cell is unavailable, then don't expand it.
|
||||||
if (arg->ea_deref) childUse->cu_def->cd_flags |= CDDEREFERENCE;
|
*/
|
||||||
if(!DBCellRead(childUse->cu_def, TRUE, TRUE, NULL))
|
if ((childUse->cu_def->cd_flags & CDAVAILABLE) == 0)
|
||||||
{
|
{
|
||||||
TxError("Cell %s is unavailable. It could not be expanded.\n",
|
/* If the parent is dereferenced, then the child should be, too */
|
||||||
childUse->cu_def->cd_name);
|
if (arg->ea_deref) childUse->cu_def->cd_flags |= CDDEREFERENCE;
|
||||||
return 2;
|
if (!DBCellRead(childUse->cu_def, TRUE, TRUE, NULL))
|
||||||
|
{
|
||||||
|
TxError("Cell %s is unavailable. It could not be expanded.\n",
|
||||||
|
childUse->cu_def->cd_name);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
childUse->cu_expandMask |= arg->ea_xmask;
|
||||||
|
expandTest = TRUE;
|
||||||
|
if (arg->ea_func != NULL)
|
||||||
|
{
|
||||||
|
if ((*arg->ea_func)(childUse, arg->ea_arg) != 0) return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
childUse->cu_expandMask |= arg->ea_xmask;
|
|
||||||
if (arg->ea_func != NULL)
|
|
||||||
{
|
|
||||||
if ((*arg->ea_func)(childUse, arg->ea_arg) != 0) return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (expandTest && ((expandType == DB_UNEXPAND) ||
|
||||||
if (DBCellSrArea(scx, dbExpandFunc, (ClientData) arg))
|
(expandType == DB_EXPAND_TOGGLE)))
|
||||||
return 1;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* dbUnexpandFunc --
|
|
||||||
*
|
|
||||||
* Filter function called by DBCellSrArea on behalf of DBExpandAll above
|
|
||||||
* when cells are being unexpanded.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
dbUnexpandFunc(scx, arg)
|
|
||||||
SearchContext *scx; /* Pointer to search context containing
|
|
||||||
* child use, search area in coor-
|
|
||||||
* dinates of the child use, and
|
|
||||||
* transform back to "root".
|
|
||||||
*/
|
|
||||||
struct expandArg *arg; /* Client data from caller */
|
|
||||||
{
|
|
||||||
CellUse *childUse = scx->scx_use;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Change the expansion status of this cell if necessary.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (DBDescendSubcell(childUse, arg->ea_xmask))
|
|
||||||
{
|
{
|
||||||
if (!GEO_SURROUND(&childUse->cu_def->cd_bbox, &scx->scx_area)
|
surround = (!GEO_SURROUND(&childUse->cu_def->cd_bbox, &scx->scx_area)
|
||||||
|| GEO_SURROUND(&scx->scx_area, &childUse->cu_def->cd_bbox))
|
|| GEO_SURROUND(&scx->scx_area, &childUse->cu_def->cd_bbox));
|
||||||
|
if (surround || (expandSurround == DB_EXPAND_OVERLAP))
|
||||||
{
|
{
|
||||||
childUse->cu_expandMask &= ~arg->ea_xmask;
|
childUse->cu_expandMask &= ~arg->ea_xmask;
|
||||||
|
expandTest = FALSE;
|
||||||
|
|
||||||
/* Call the client's function, if there is one. */
|
/* Call the client's function, if there is one. */
|
||||||
|
|
||||||
|
|
@ -256,11 +248,7 @@ dbUnexpandFunc(scx, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't recursively search things that aren't already expanded. */
|
if (DBCellSrArea(scx, dbExpandFunc, (ClientData) arg))
|
||||||
|
|
||||||
else return 2;
|
|
||||||
|
|
||||||
if (DBCellSrArea(scx, dbUnexpandFunc, (ClientData) arg))
|
|
||||||
return 1;
|
return 1;
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1071
database/DBio.c
1071
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 "database/database.h"
|
||||||
#include "utils/malloc.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
|
void
|
||||||
DBPropPut(cellDef, name, value)
|
DBPropPut(cellDef, name, value)
|
||||||
CellDef *cellDef; /* Pointer to definition of cell. */
|
CellDef *cellDef; /* Pointer to definition of cell. */
|
||||||
char *name; /* The name of the property desired. */
|
char *name; /* The name of the property desired. */
|
||||||
ClientData value; /* MUST point to a malloc'ed structure, or NULL.
|
PropertyRecord *value; /* MUST point to a malloc'ed structure, or NULL.
|
||||||
* This will be freed when the CellDef is freed.
|
* This will be freed when the CellDef is freed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
{
|
{
|
||||||
HashTable *htab;
|
HashTable *htab;
|
||||||
HashEntry *entry;
|
HashEntry *entry;
|
||||||
char *oldvalue;
|
PropertyRecord *oldvalue;
|
||||||
|
|
||||||
/* Honor the NOEDIT flag. Note that the caller always assumes that */
|
/* 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 */
|
/* 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);
|
entry = HashFind(htab, name);
|
||||||
oldvalue = (char *)HashGetValue(entry);
|
oldvalue = (PropertyRecord *)HashGetValue(entry);
|
||||||
if (oldvalue != NULL) freeMagic(oldvalue);
|
/* All properties are allocated as a single block and can just be freed,
|
||||||
if (value == (ClientData)NULL)
|
* 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);
|
HashRemove(htab, name);
|
||||||
else
|
else
|
||||||
HashSetValue(entry, value);
|
HashSetValue(entry, PTR2CD(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
|
|
@ -110,13 +131,13 @@ DBPropPut(cellDef, name, value)
|
||||||
* Get a property from a celldef.
|
* Get a property from a celldef.
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* NULL if the property didn't exist, or if the property value was NULL.
|
* NULL if the property didn't exist, or if the property record was NULL.
|
||||||
* Otherwise, ClientData that represents the property.
|
* Otherwise, returns a pointer to the property record.
|
||||||
*
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ClientData
|
PropertyRecord *
|
||||||
DBPropGet(cellDef, name, found)
|
DBPropGet(cellDef, name, found)
|
||||||
CellDef *cellDef; /* Pointer to definition of cell. */
|
CellDef *cellDef; /* Pointer to definition of cell. */
|
||||||
char *name; /* The name of the property desired. */
|
char *name; /* The name of the property desired. */
|
||||||
|
|
@ -124,12 +145,12 @@ DBPropGet(cellDef, name, found)
|
||||||
* exists.
|
* exists.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
ClientData result;
|
PropertyRecord *result;
|
||||||
bool haveit;
|
bool haveit;
|
||||||
HashTable *htab;
|
HashTable *htab;
|
||||||
HashEntry *entry;
|
HashEntry *entry;
|
||||||
|
|
||||||
result = (ClientData) NULL;
|
result = (PropertyRecord *)NULL;
|
||||||
haveit = FALSE;
|
haveit = FALSE;
|
||||||
htab = (HashTable *) cellDef->cd_props;
|
htab = (HashTable *) cellDef->cd_props;
|
||||||
if (htab == (HashTable *) NULL) goto done;
|
if (htab == (HashTable *) NULL) goto done;
|
||||||
|
|
@ -138,7 +159,7 @@ DBPropGet(cellDef, name, found)
|
||||||
if (entry != NULL)
|
if (entry != NULL)
|
||||||
{
|
{
|
||||||
haveit = TRUE;
|
haveit = TRUE;
|
||||||
result = (ClientData) HashGetValue(entry);
|
result = (PropertyRecord *)HashGetValue(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
@ -146,6 +167,109 @@ done:
|
||||||
return result;
|
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 --
|
* DBPropEnum --
|
||||||
|
|
@ -168,7 +292,7 @@ DBPropEnum(cellDef, func, cdata)
|
||||||
*
|
*
|
||||||
* int foo(name, value, cdata)
|
* int foo(name, value, cdata)
|
||||||
* char *name;
|
* char *name;
|
||||||
* ClientData value;
|
* PropertyRecord *value;
|
||||||
* ClientData cdata;
|
* ClientData cdata;
|
||||||
* {
|
* {
|
||||||
* -- return 0 to continue,
|
* -- return 0 to continue,
|
||||||
|
|
@ -189,7 +313,7 @@ DBPropEnum(cellDef, func, cdata)
|
||||||
HashStartSearch(&hs);
|
HashStartSearch(&hs);
|
||||||
while ((entry = HashNext(htab, &hs)) != NULL)
|
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;
|
if (res != 0) return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -651,6 +651,7 @@ typedef struct treeFilter
|
||||||
#define TF_LABEL_ATTACH_NOT_SE 0x10 /* Same as above, ignore tile SE corner */
|
#define TF_LABEL_ATTACH_NOT_SE 0x10 /* Same as above, ignore tile SE corner */
|
||||||
#define TF_LABEL_ATTACH_NOT_SW 0x20 /* Same as above, ignore tile SW corner */
|
#define TF_LABEL_ATTACH_NOT_SW 0x20 /* Same as above, ignore tile SW corner */
|
||||||
#define TF_LABEL_ATTACH_CORNER 0x3C /* Mask of the four types above */
|
#define TF_LABEL_ATTACH_CORNER 0x3C /* Mask of the four types above */
|
||||||
|
#define TF_LABEL_REVERSE_SEARCH 0x40 /* Search children before parent */
|
||||||
|
|
||||||
/* To do: Make the tpath entries dynamically allocated */
|
/* To do: Make the tpath entries dynamically allocated */
|
||||||
#define FLATTERMSIZE 4096 /* Used for generating flattened labels */
|
#define FLATTERMSIZE 4096 /* Used for generating flattened labels */
|
||||||
|
|
@ -704,6 +705,25 @@ struct conSrArg2
|
||||||
|
|
||||||
#define CSA2_LIST_SIZE 65536 /* Number of entries per list */
|
#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 ------------- */
|
/* -------------- Undo information passed to DBPaintPlane ------------- */
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|
@ -736,6 +756,14 @@ typedef struct
|
||||||
#define PAINT_MARK 1 /* Mark tiles that are painted */
|
#define PAINT_MARK 1 /* Mark tiles that are painted */
|
||||||
#define PAINT_XOR 2 /* Use with XOR function to prevent double-painting */
|
#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 -------------------- */
|
/* -------------------- Exported procedure headers -------------------- */
|
||||||
|
|
||||||
/* Painting/erasing */
|
/* Painting/erasing */
|
||||||
|
|
@ -921,7 +949,9 @@ extern void DBFreePaintPlane();
|
||||||
|
|
||||||
/* Cell properties */
|
/* Cell properties */
|
||||||
extern void DBPropPut();
|
extern void DBPropPut();
|
||||||
extern ClientData DBPropGet();
|
extern PropertyRecord *DBPropGet();
|
||||||
|
extern char *DBPropGetString();
|
||||||
|
extern dlong DBPropGetDouble();
|
||||||
extern int DBPropEnum();
|
extern int DBPropEnum();
|
||||||
extern void DBPropClearAll();
|
extern void DBPropClearAll();
|
||||||
|
|
||||||
|
|
@ -1019,6 +1049,7 @@ extern int DBLambda[2];
|
||||||
/* -------------------- Exported magic file suffix -------------------- */
|
/* -------------------- Exported magic file suffix -------------------- */
|
||||||
|
|
||||||
extern char *DBSuffix; /* Suffix appended to all Magic cell names */
|
extern char *DBSuffix; /* Suffix appended to all Magic cell names */
|
||||||
|
extern bool DBPropCompat; /* Backwards-compatible properties */
|
||||||
|
|
||||||
/* -------------------- User Interface Stuff -------------------------- */
|
/* -------------------- User Interface Stuff -------------------------- */
|
||||||
|
|
||||||
|
|
@ -1031,6 +1062,19 @@ extern unsigned char DBVerbose; /* If 0, don't print any messages */
|
||||||
#define DB_VERBOSE_WARN 2
|
#define DB_VERBOSE_WARN 2
|
||||||
#define DB_VERBOSE_ALL 3
|
#define DB_VERBOSE_ALL 3
|
||||||
|
|
||||||
|
/* ---------- Definitions for expanding/unexpanding cells --------------*/
|
||||||
|
|
||||||
|
/* Selection expansion flags */
|
||||||
|
#define DB_EXPAND_MASK 3 /* 1 = expand, 0 = unexpand, 2 = toggle */
|
||||||
|
#define DB_EXPAND_SURROUND_MASK 4 /* 1 = surround, 0 = touch */
|
||||||
|
|
||||||
|
/* Selection expansion values */
|
||||||
|
#define DB_EXPAND 0
|
||||||
|
#define DB_UNEXPAND 1
|
||||||
|
#define DB_EXPAND_TOGGLE 2
|
||||||
|
#define DB_EXPAND_SURROUND 4
|
||||||
|
#define DB_EXPAND_OVERLAP 0
|
||||||
|
|
||||||
/* ------------------ Exported technology variables ------------------- */
|
/* ------------------ Exported technology variables ------------------- */
|
||||||
|
|
||||||
/***
|
/***
|
||||||
|
|
|
||||||
|
|
@ -131,8 +131,11 @@ DBWAddButtonHandler(
|
||||||
for (i = 0; i < MAXBUTTONHANDLERS; i++)
|
for (i = 0; i < MAXBUTTONHANDLERS; i++)
|
||||||
{
|
{
|
||||||
if (dbwButtonHandlers[i] != NULL) continue;
|
if (dbwButtonHandlers[i] != NULL) continue;
|
||||||
(void) StrDup(&dbwButtonHandlers[i], name);
|
StrDup(&dbwButtonHandlers[i], name);
|
||||||
(void) StrDup(&dbwButtonDoc[i], doc);
|
if (doc != NULL)
|
||||||
|
StrDup(&dbwButtonDoc[i], doc);
|
||||||
|
else
|
||||||
|
dbwButtonDoc[i] = (char *)NULL;
|
||||||
dbwButtonProcs[i] = proc;
|
dbwButtonProcs[i] = proc;
|
||||||
dbwButtonCursors[i] = cursor;
|
dbwButtonCursors[i] = cursor;
|
||||||
return;
|
return;
|
||||||
|
|
@ -273,6 +276,37 @@ DBWGetButtonHandler()
|
||||||
return dbwButtonHandlers[dbwButtonCurrentIndex];
|
return dbwButtonHandlers[dbwButtonCurrentIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* DBWButtonHandlerIndex()
|
||||||
|
*
|
||||||
|
* Given a string, return the index of the button handler. If the
|
||||||
|
* string does not correspond to any button handler name, then
|
||||||
|
* return -1.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* Index of button handler, if it exists; -1 otherwise.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* None.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
DBWButtonHandlerIndex(char *toolName)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAXBUTTONHANDLERS; i++)
|
||||||
|
{
|
||||||
|
if (dbwButtonHandlers[i] == NULL) return -1;
|
||||||
|
else if (!strcmp(toolName, dbwButtonHandlers[i])) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -294,7 +328,10 @@ DBWGetButtonHandler()
|
||||||
void
|
void
|
||||||
DBWPrintButtonDoc()
|
DBWPrintButtonDoc()
|
||||||
{
|
{
|
||||||
TxPrintf("%s", dbwButtonDoc[dbwButtonCurrentIndex]);
|
if (dbwButtonDoc[dbwButtonCurrentIndex])
|
||||||
|
TxPrintf("%s", dbwButtonDoc[dbwButtonCurrentIndex]);
|
||||||
|
else
|
||||||
|
TxPrintf("(no usage information)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -421,7 +421,8 @@ DBWredisplay(w, rootArea, clipArea)
|
||||||
/* Set style information beforehand */
|
/* Set style information beforehand */
|
||||||
GrSetStuff(STYLE_LABEL);
|
GrSetStuff(STYLE_LABEL);
|
||||||
(void) DBTreeSrLabels(&scontext, &DBAllTypeBits, bitMask,
|
(void) DBTreeSrLabels(&scontext, &DBAllTypeBits, bitMask,
|
||||||
(TerminalPath *) NULL, TF_LABEL_DISPLAY | TF_LABEL_ATTACH,
|
(TerminalPath *) NULL,
|
||||||
|
TF_LABEL_DISPLAY | TF_LABEL_ATTACH | TF_LABEL_REVERSE_SEARCH,
|
||||||
dbwLabelFunc, (ClientData)(&crec->dbw_visibleLayers));
|
dbwLabelFunc, (ClientData)(&crec->dbw_visibleLayers));
|
||||||
GrClipTo(&rootClip);
|
GrClipTo(&rootClip);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -546,12 +546,12 @@ DBWloadWindow(window, name, flags)
|
||||||
newEditUse = DBCellNewUse(newEditDef, (char *) NULL);
|
newEditUse = DBCellNewUse(newEditDef, (char *) NULL);
|
||||||
(void) StrDup(&(newEditUse->cu_id), "Topmost cell in the window");
|
(void) StrDup(&(newEditUse->cu_id), "Topmost cell in the window");
|
||||||
DBExpand(newEditUse,
|
DBExpand(newEditUse,
|
||||||
((DBWclientRec *)window->w_clientData)->dbw_bitmask, TRUE);
|
((DBWclientRec *)window->w_clientData)->dbw_bitmask, DB_EXPAND);
|
||||||
|
|
||||||
if (expand)
|
if (expand)
|
||||||
DBExpandAll(newEditUse, &(newEditUse->cu_bbox),
|
DBExpandAll(newEditUse, &(newEditUse->cu_bbox),
|
||||||
((DBWclientRec *)window->w_clientData)->dbw_bitmask,
|
((DBWclientRec *)window->w_clientData)->dbw_bitmask,
|
||||||
FALSE, UnexpandFunc,
|
DB_UNEXPAND, UnexpandFunc,
|
||||||
INT2CD(((DBWclientRec *)window->w_clientData)->dbw_bitmask));
|
INT2CD(((DBWclientRec *)window->w_clientData)->dbw_bitmask));
|
||||||
|
|
||||||
if (newEdit)
|
if (newEdit)
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@ extern void DBWAddButtonHandler(const char *name, const cb_database_buttonhandle
|
||||||
int cursor, const char *doc);
|
int cursor, const char *doc);
|
||||||
extern char *DBWGetButtonHandler();
|
extern char *DBWGetButtonHandler();
|
||||||
extern char *DBWChangeButtonHandler();
|
extern char *DBWChangeButtonHandler();
|
||||||
|
extern int DBWButtonHandlerIndex();
|
||||||
extern void DBWPrintButtonDoc();
|
extern void DBWPrintButtonDoc();
|
||||||
extern void DBWBoxHandler();
|
extern void DBWBoxHandler();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,12 +71,15 @@ Operations on cell definitions.
|
||||||
<DT> <B>rename</B> <I>name newname</I>
|
<DT> <B>rename</B> <I>name newname</I>
|
||||||
<DD> Change the name of the cell definition <I>name</I> to
|
<DD> Change the name of the cell definition <I>name</I> to
|
||||||
<I>newname</I>.
|
<I>newname</I>.
|
||||||
<DT> <B>delete</B> <I>name</I>
|
<DT> <B>delete</B> <I>name</I> [<B>-noprompt</B>]
|
||||||
<DD> Delete the cell definition with name <I>name</I>. If cell
|
<DD> Delete the cell definition with name <I>name</I>. If cell
|
||||||
<I>name</I> is a descendent of another cell, the command
|
<I>name</I> is a descendent of another cell, the command
|
||||||
will be prohibited. If the cell <I>name</I> is currently
|
will be prohibited. If the cell <I>name</I> is currently
|
||||||
the topmost cell in the window, the window will be loaded
|
the topmost cell in the window, the window will be loaded
|
||||||
with default cell "(UNNAMED)".
|
with default cell "(UNNAMED)". If option <B>-noprompt</B>
|
||||||
|
is specified, then the actions specified above happen
|
||||||
|
immediately. Otherwise, a dialog box will be raised
|
||||||
|
asking for confirmation to delete the cell.
|
||||||
<DT> <B>dereference</B> <I>name</I>
|
<DT> <B>dereference</B> <I>name</I>
|
||||||
<DD> Perform a flush of the cell (per the "<B>flush</B>" command),
|
<DD> Perform a flush of the cell (per the "<B>flush</B>" command),
|
||||||
first removing any file path associated with the cell, so
|
first removing any file path associated with the cell, so
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@ expanded/unexpanded cells in the current selection.
|
||||||
|
|
||||||
<H3>Usage:</H3>
|
<H3>Usage:</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<B>expand</B> [<B>toggle</B>] <BR><BR>
|
<B>expand</B> [<B>selection</B>|<B>surround</B>|<B>overlap</B>|<B>all</B>]
|
||||||
|
[<B>toggle</B>] <BR><BR>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H3>Shortcuts:</H3>
|
<H3>Shortcuts:</H3>
|
||||||
|
|
@ -38,14 +39,32 @@ expanded/unexpanded cells in the current selection.
|
||||||
<H3>Summary:</H3>
|
<H3>Summary:</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
The <B>expand</B> command expands the view of subcells to
|
The <B>expand</B> command expands the view of subcells to
|
||||||
display the contents of the subcells. Without arguments,
|
display the contents of the subcells.
|
||||||
the <B>expand</B> command expands all unexpanded subcells that
|
|
||||||
touch or intersect the cursor box in the layout window. <P>
|
Option <B>overlap</B> expands all unexpanded subcells that
|
||||||
|
overlap with the cursor box in the layout window. <P>
|
||||||
|
|
||||||
|
Option <B>surround</B> expands all unexpanded subcells that
|
||||||
|
are completely surrounded by the cursor box in the layout window. <P>
|
||||||
|
|
||||||
|
Option <B>all</B> expands all subcells in the layout window. <P>
|
||||||
|
|
||||||
|
Option <B>selection</B> operates on the current selection, not
|
||||||
|
relative to the cursor box, expanding all selected cells. <P>
|
||||||
|
|
||||||
|
Option <B>toggle</B> will expand a selected cell that is
|
||||||
|
unexpanded, or unexpand a cell that is already expanded.
|
||||||
|
<B>toggle</B> may be given as an additional option to any
|
||||||
|
of the other options above; however, the <B>toggle</B> option
|
||||||
|
must be the last option given to the command.<P>
|
||||||
|
|
||||||
|
With no arguments, the <B>expand</B> command behaves like
|
||||||
|
<B>expand overlap</B>, and the <B>expand toggle</B> command
|
||||||
|
with no additonal arguments behaves like
|
||||||
|
<B>expand selection toggle</B>, for backwards-compatible
|
||||||
|
behavior with earlier versions of magic which offered only
|
||||||
|
the <B>toggle</B> option.
|
||||||
|
|
||||||
Option <B>expand toggle</B> operates on the current selection,
|
|
||||||
not relative to the cursor box, and will expand a selected
|
|
||||||
cell that is unexpanded, or unexpand a cell that is already
|
|
||||||
expanded.
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H3>Implementation Notes:</H3>
|
<H3>Implementation Notes:</H3>
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,11 @@ Circuit netlist extractor
|
||||||
<DL>
|
<DL>
|
||||||
<DT> <B>capacitance</B>
|
<DT> <B>capacitance</B>
|
||||||
<DD> Extract local parasitic capacitance values to substrate
|
<DD> Extract local parasitic capacitance values to substrate
|
||||||
<DT> <B>resistance</B>
|
<DT> <B>coupling</B>
|
||||||
<DD> Extract lumped resistance values. Note that this
|
<DD> Extract the parasitic coupling capacitance between
|
||||||
is <I>not</I> the same as full parasitic resistance.
|
nodes.
|
||||||
|
<DT> <B>lumped</B>
|
||||||
|
<DD> Extract lumped resistance values.
|
||||||
The values extracted are "lumped" resistance and
|
The values extracted are "lumped" resistance and
|
||||||
indicate the value for which the delay through the
|
indicate the value for which the delay through the
|
||||||
net can be computed with R times C, where R is the
|
net can be computed with R times C, where R is the
|
||||||
|
|
@ -55,9 +57,10 @@ Circuit netlist extractor
|
||||||
command. Lumped resistances have no meaning in
|
command. Lumped resistances have no meaning in
|
||||||
SPICE netlists and will only be used when running
|
SPICE netlists and will only be used when running
|
||||||
<B>ext2sim</B> to generate a .sim netlist.
|
<B>ext2sim</B> to generate a .sim netlist.
|
||||||
<DT> <B>coupling</B>
|
Prior to magic version 8.3.597, this option was
|
||||||
<DD> Extract the parasitic coupling capacitance between
|
<B>resistance</B>, but as that was often confused
|
||||||
nodes.
|
with full parasitic resistance extraction, it has
|
||||||
|
been changed.
|
||||||
<DT> <B>length</B>
|
<DT> <B>length</B>
|
||||||
<DD> Extract the length of the shortest path from a driver
|
<DD> Extract the length of the shortest path from a driver
|
||||||
to a receiver, for computing more accurate parasitic
|
to a receiver, for computing more accurate parasitic
|
||||||
|
|
@ -73,7 +76,7 @@ Circuit netlist extractor
|
||||||
array instances, is guaranteed to be strictly positive.
|
array instances, is guaranteed to be strictly positive.
|
||||||
<DT> <B>all</B>
|
<DT> <B>all</B>
|
||||||
<DD> Apply all standard options (does not include options
|
<DD> Apply all standard options (does not include options
|
||||||
"local", "labelcheck", or "aliases").
|
"local", "labelcheck", "aliases", or "resistance").
|
||||||
<DT> <B>local</B>
|
<DT> <B>local</B>
|
||||||
<DD> Write all .ext files to the current working directory.
|
<DD> Write all .ext files to the current working directory.
|
||||||
If not specified, each .ext file will be placed in the
|
If not specified, each .ext file will be placed in the
|
||||||
|
|
@ -109,6 +112,18 @@ Circuit netlist extractor
|
||||||
Note the difference: "extract unique" is a command that
|
Note the difference: "extract unique" is a command that
|
||||||
runs immediately, and cannot be undone;
|
runs immediately, and cannot be undone;
|
||||||
"extract do unique" is an option setting for "extract".
|
"extract do unique" is an option setting for "extract".
|
||||||
|
<DT> <B>resistance</B>
|
||||||
|
<DD> (Added in magic version 8.3.597) This setting replaces
|
||||||
|
the use of the standalone command "extresist". The
|
||||||
|
effect is the same: Magic performs full R-C extraction,
|
||||||
|
generating a <TT>.res.ext</TT> file that annotates the
|
||||||
|
existing <TT>.ext</TT> file (see the "extresist" command
|
||||||
|
documentation). The "extresist" command options can
|
||||||
|
still be used to set options such as tolerance for the
|
||||||
|
R-C extraction.
|
||||||
|
Note that prior to magic version 8.3.597, this option
|
||||||
|
name would produce the lumped resistance approximation
|
||||||
|
(see <B>lumped</B>, above).
|
||||||
</DL>
|
</DL>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
These options (except for "local") determine how much
|
These options (except for "local") determine how much
|
||||||
|
|
@ -223,7 +238,9 @@ Circuit netlist extractor
|
||||||
<I>Warning:</I> This operation immediately modifies the
|
<I>Warning:</I> This operation immediately modifies the
|
||||||
existing layout in preparation for extraction. Label
|
existing layout in preparation for extraction. Label
|
||||||
modifications are permanent, and cannot be undone. All
|
modifications are permanent, and cannot be undone. All
|
||||||
cells in the hierarchy may potentially be modified. <BR>
|
cells in the hierarchy may potentially be modified. To avoid
|
||||||
|
this issue, use the "extract do unique" option instead (see
|
||||||
|
above). <BR>
|
||||||
<DT> <B>warn</B> [[<B>no</B>] <I>option</I>]
|
<DT> <B>warn</B> [[<B>no</B>] <I>option</I>]
|
||||||
<DD> Enable/disable reporting of non-fatal errors, where <I>option</I>
|
<DD> Enable/disable reporting of non-fatal errors, where <I>option</I>
|
||||||
may be one of the following:
|
may be one of the following:
|
||||||
|
|
|
||||||
|
|
@ -92,17 +92,25 @@ information.
|
||||||
The <B>extresist</B> command provides a method for generating
|
The <B>extresist</B> command provides a method for generating
|
||||||
a more detailed model of resistance, in which long network
|
a more detailed model of resistance, in which long network
|
||||||
routes and branching routes are replaced with resistor devices
|
routes and branching routes are replaced with resistor devices
|
||||||
and device networks. <P>
|
and device networks. This is known as "full R-C extraction". <P>
|
||||||
|
|
||||||
Using <B>extresist</B> is a multi-step process. It is first
|
Using <B>extresist</B> as a standalone command is a multi-step
|
||||||
necessary to run both <B>extract</B> and <B>ext2sim</B> to get
|
process. It is first necessary to run <B>extract</B> to get
|
||||||
the initial netlist (with lumped, not detailed, resistances).
|
the initial netlist.
|
||||||
After a <TT>.sim</TT> file has been generated, the
|
After a <TT>.ext</TT> file has been generated, the
|
||||||
<B>extresist all</B> command may be run. The output is
|
<B>extresist</B> command may be run. The output is
|
||||||
a file <TT>.res.ext</TT> for each cell in the hierarchy.
|
a file <TT>.res.ext</TT> for each cell in the hierarchy.
|
||||||
Finally, with the option <B>extresist on</B> set,
|
Finally, with the option <B>extresist on</B> set, <B>ext2spice</B>
|
||||||
<B>ext2sim</B> or <B>ext2spice</B> will generate the final,
|
will generate the final, detailed simulation file. <P>
|
||||||
detailed simulation file. <P>
|
|
||||||
|
Prior to magic version 8.3.597, it was also necessary to run
|
||||||
|
<B>ext2sim labels on</B> and <B>ext2sim</B> to write out a
|
||||||
|
<TT>.sim</TT> and a <TT>.node</TT> file before running
|
||||||
|
<B>extresist</B>. This is no longer necessary. There is since
|
||||||
|
magic version 8.3.597 an option <B>extract do resistance</B>
|
||||||
|
that runs the resistance extraction in sequence with the regular
|
||||||
|
extraction, producing both the <TT>.ext</TT> and <TT>.res.ext</TT>
|
||||||
|
files.
|
||||||
|
|
||||||
More details on using <B>extresist</B> can be found in
|
More details on using <B>extresist</B> can be found in
|
||||||
<B>magic</B> Tutorial number 8.
|
<B>magic</B> Tutorial number 8.
|
||||||
|
|
@ -117,6 +125,7 @@ information.
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<A HREF=extract.html><B>extract</B></A> <BR>
|
<A HREF=extract.html><B>extract</B></A> <BR>
|
||||||
<A HREF=ext2sim.html><B>ext2sim</B></A> <BR>
|
<A HREF=ext2sim.html><B>ext2sim</B></A> <BR>
|
||||||
|
<A HREF=ext2spice.html><B>ext2spice</B></A> <BR>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<P><IMG SRC=graphics/line1.gif><P>
|
<P><IMG SRC=graphics/line1.gif><P>
|
||||||
|
|
|
||||||
|
|
@ -182,6 +182,13 @@ Read GDSII input or generate GDSII output.
|
||||||
than to subsplit the internal grid to such a fine value.
|
than to subsplit the internal grid to such a fine value.
|
||||||
The "<B>cif limit</B>" function may also be used to limit
|
The "<B>cif limit</B>" function may also be used to limit
|
||||||
grid subdivision to a minimum value.
|
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>]
|
<DT> <B>unique</B> [<B>yes</B>|<B>no</B>]
|
||||||
<DD> When reading a GDS file, this option forces magic to rename
|
<DD> When reading a GDS file, this option forces magic to rename
|
||||||
cell definitions in the database when a cell of the same name
|
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>
|
to another layer. <P>
|
||||||
</BLOCKQUOTE>
|
</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>
|
<H3>Implementation Notes:</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<B>label</B> is implemented as a built-in command in <B>magic</B>.
|
<B>label</B> is implemented as a built-in command in <B>magic</B>.
|
||||||
|
|
|
||||||
|
|
@ -20,22 +20,64 @@
|
||||||
|
|
||||||
<H2>macro</H2>
|
<H2>macro</H2>
|
||||||
<HR>
|
<HR>
|
||||||
Define or print a macro called char
|
Define or print a key or button macro binding.
|
||||||
<HR>
|
<HR>
|
||||||
|
|
||||||
<H3>Usage:</H3>
|
<H3>Usage:</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<B>macro</B> [<I>window_type</I>] [<I>key</I> [<I>value</I>]] <BR><BR>
|
<B>macro</B> [<I>window_type</I>] [<I>option</I>] [<I>key</I> [<I>value</I>]]
|
||||||
|
<BR><BR>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
where <I>key</I> is the name of a valid key (see below), and
|
where <I>key</I> is the name of a valid key (see below), and
|
||||||
<I>value</I> is a <B>magic</B> command-line command. If
|
<I>value</I> is a <B>magic</B> command-line command. If
|
||||||
present, <I>window_type</I> must be one of the four window
|
present, <I>window_type</I> must be one of the known valid window
|
||||||
types accepted by the <B>specialopen</B> command: <B>layout</B>,
|
types accepted by the <B>specialopen</B> command (<B>color</B>,
|
||||||
<B>color</B>, <B>netlist</B>, and <B>wind3d</B>. If omitted,
|
<B>netlist</B>, and <B>wind3d</B>), or a known layout tool
|
||||||
the layout window is assumed by default, unless the command has
|
(<B>box</B>, <B>wiring</B>, <B>nettool</B>, or <B>pick</B>). If
|
||||||
been called from inside a window (using the colon or semicolon
|
omitted, the layout window is assumed by default, unless the command
|
||||||
|
has been called from inside a window (using the colon or semicolon
|
||||||
escape to the command-line), in which case that window type is
|
escape to the command-line), in which case that window type is
|
||||||
assumed.
|
assumed. <P>
|
||||||
|
|
||||||
|
In the non-Tcl version of magic, the <I>window_type</I> must be
|
||||||
|
one of the three valid window types listed above, or <B>layout</B>.
|
||||||
|
Tool button bindings are hard-coded, fixed, and unknown to the
|
||||||
|
macro handler. <P>
|
||||||
|
|
||||||
|
In the Tcl version of magic, tool types are generated by
|
||||||
|
procedure and can be modified or overridden. The four tools
|
||||||
|
listed above are the default tools known to magic. If no window
|
||||||
|
or tool type is given, then the current tool in the current
|
||||||
|
active layout window is assumed.<P>
|
||||||
|
|
||||||
|
<I>option</I> may be one of the following:
|
||||||
|
<DL>
|
||||||
|
<DT> <B>list</B> [<B>-reverse</B>]
|
||||||
|
<DD> The key bindings are returned in the form of a Tcl list
|
||||||
|
(Tcl version of magic only). The returned value is a
|
||||||
|
single list with alternating entries of the macro key and
|
||||||
|
the macro binding. In Tcl, this list can be treated as a
|
||||||
|
dictionary type of key:value pairs. With the <B>-reverse</B>
|
||||||
|
option, the keys and values are reversed, resulting in a
|
||||||
|
dictionary that can be searched or listed by function.
|
||||||
|
<DT> <B>help</B>
|
||||||
|
<DD> Curently, <B>macro help</B> is equivalent to <B>macro</B>
|
||||||
|
without arguments, and returns a full list of macro names
|
||||||
|
and their bindings.
|
||||||
|
<DT> <B>search</B> <I>text</I>
|
||||||
|
<DD> Return only results which match (all or in part) the string
|
||||||
|
<I>text</I>. For example, <B>macro search grid</B> will
|
||||||
|
return all key bindings that include the command <B>grid</B>.
|
||||||
|
<DT> <B>copy</B> <I>tool_name</I>
|
||||||
|
<DD> This is a method introduced to allow the interactive creation
|
||||||
|
of new tools, in the Tcl version of magic. Each tool is defined
|
||||||
|
specifically by its unique button and key bindings. Because
|
||||||
|
tools generally keep most of the same default bindings, the
|
||||||
|
<B>copy</B> option will copy all the existing bindings to the
|
||||||
|
new tool from the current tool. This can be followed by
|
||||||
|
switching to the new tool and replacing macros with ones
|
||||||
|
unique to the tool.
|
||||||
|
</DL>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
@ -72,7 +114,6 @@ Define or print a macro called char
|
||||||
etc., the <B>macro</B> command accepts the abbreviated
|
etc., the <B>macro</B> command accepts the abbreviated
|
||||||
forms <B>Button1</B>, and so forth. <P>
|
forms <B>Button1</B>, and so forth. <P>
|
||||||
|
|
||||||
|
|
||||||
Finally, key modifiers may be prepended to the key name.
|
Finally, key modifiers may be prepended to the key name.
|
||||||
Valid key modifiers are <B>Shift_</B>, <B>Control_</B>,
|
Valid key modifiers are <B>Shift_</B>, <B>Control_</B>,
|
||||||
<B>Alt_</B>, and <B>Meta_</B>, and may be coupled in any
|
<B>Alt_</B>, and <B>Meta_</B>, and may be coupled in any
|
||||||
|
|
@ -89,6 +130,7 @@ Define or print a macro called char
|
||||||
<H3>See Also:</H3>
|
<H3>See Also:</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<A HREF=imacro.html><B>imacro</B></A> <BR>
|
<A HREF=imacro.html><B>imacro</B></A> <BR>
|
||||||
|
<A HREF=toolchange.html><B>tool</B></A> (Tcl version) <BR>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<P><IMG SRC=graphics/line1.gif><P>
|
<P><IMG SRC=graphics/line1.gif><P>
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,13 @@ Attach a "property" (string key and value pair) to the edit cell
|
||||||
|
|
||||||
<H3>Usage:</H3>
|
<H3>Usage:</H3>
|
||||||
<BLOCKQUOTE>
|
<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>
|
<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>
|
||||||
</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
|
with the key is returned. With both arguments, the string
|
||||||
<I>value</I> is associated with the string <I>key</I> as a
|
<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
|
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>
|
||||||
|
|
||||||
<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>
|
<DL>
|
||||||
<DT> <B>GDS_FILE</B>
|
<DT> <B>GDS_FILE</B>
|
||||||
<DD> The value is the name of a GDS file which contains the mask
|
<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
|
<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
|
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
|
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>
|
<DT> <B>GDS_END</B>
|
||||||
<DD> If a <B>GDS_FILE</B> is defined, then this value indicates the
|
<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
|
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
|
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>
|
<DT> <B>LEFview</B>
|
||||||
<DD> If set to <B>TRUE</B>, this cell is an abstract view such as that
|
<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
|
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
|
corresponding to the abutment box of the cell, in magic's internal
|
||||||
units. The abutment box is automatically read from LEF files, but
|
units. The abutment box is automatically read from LEF files, but
|
||||||
may be defined for any file and can be used for placement alignment.
|
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>
|
<DT> <B>OBS_BBOX</B>
|
||||||
<DD> This property value is a space-sparated list of four integer values
|
<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
|
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
|
will be entirely covered in obstruction layers (unless cut-outs
|
||||||
are required to accommodate pins). Any set-back applied by the
|
are required to accommodate pins). Any set-back applied by the
|
||||||
"lef write -hide <value>" option will be applied to this obstruction
|
"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>
|
<DT> <B>flatten</B>
|
||||||
<DD> This property is used in conjunction with the "flatten -doproperty"
|
<DD> This property is used in conjunction with the "flatten -doproperty"
|
||||||
command option and marks the cell for flattening. Cells without
|
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
|
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,
|
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,
|
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>
|
</DL>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
@ -157,6 +220,11 @@ Attach a "property" (string key and value pair) to the edit cell
|
||||||
the cell definition structure.
|
the cell definition structure.
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<H3>See Also:</H3>
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<A HREF=units.html><B>units</B></A> <BR>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<P><IMG SRC=graphics/line1.gif><P>
|
<P><IMG SRC=graphics/line1.gif><P>
|
||||||
<TABLE BORDER=0>
|
<TABLE BORDER=0>
|
||||||
<TR>
|
<TR>
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ Unexpand everything inside or touching the cursor box.
|
||||||
|
|
||||||
<H3>Usage:</H3>
|
<H3>Usage:</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<B>unexpand</B> <BR><BR>
|
<B>unexpand</B> [<B>selection</B>|<B>surround</B>|<B>overlap</B>|<B>all</B>]
|
||||||
|
<BR><BR>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H3>Shortcuts:</H3>
|
<H3>Shortcuts:</H3>
|
||||||
|
|
@ -37,8 +38,23 @@ Unexpand everything inside or touching the cursor box.
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
The <B>unexpand</B> command unexpands the view of subcells to
|
The <B>unexpand</B> command unexpands the view of subcells to
|
||||||
hide the contents of the subcells and show the bounding box
|
hide the contents of the subcells and show the bounding box
|
||||||
outline only. The <B>unexpand</B> command unexpands all subcells
|
outline only.
|
||||||
that touch or intersect the cursor box in the layout window. <P>
|
|
||||||
|
Option <B>overlap</B> unexpands all expanded subcells that
|
||||||
|
overlap with the cursor box in the layout window. <P>
|
||||||
|
|
||||||
|
Option <B>surround</B> unexpands all expanded subcells that
|
||||||
|
are completely surrounded by the cursor box in the layout window. <P>
|
||||||
|
|
||||||
|
Option <B>all</B> unexpands all subcells in the layout window. <P>
|
||||||
|
|
||||||
|
Option <B>selection</B> operates on the current selection, not
|
||||||
|
relative to the cursor box, unexpanding all selected cells. <P>
|
||||||
|
|
||||||
|
With no arguments, the <B>unexpand</B> command behaves like
|
||||||
|
<B>unexpand surround</B>, for backwards-compatible behavior with
|
||||||
|
earlier versions of magic which did not offer the options.
|
||||||
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H3>Implementation Notes:</H3>
|
<H3>Implementation Notes:</H3>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
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,
|
<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
|
<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
|
<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
|
corners of the screen are at the indicated positions in the
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ extern int drcArrayYankFunc(), drcArrayOverlapFunc();
|
||||||
static DRCCookie drcArrayCookie = {
|
static DRCCookie drcArrayCookie = {
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
{ {0} }, { {0} },
|
{ {0} }, { {0} },
|
||||||
0, 0, 0,
|
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||||
DRC_ARRAY_OVERLAP_TAG,
|
DRC_ARRAY_OVERLAP_TAG,
|
||||||
(DRCCookie *) NULL
|
(DRCCookie *) NULL
|
||||||
};
|
};
|
||||||
|
|
|
||||||
188
drc/DRCbasic.c
188
drc/DRCbasic.c
|
|
@ -27,6 +27,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h> // for memcpy()
|
#include <string.h> // for memcpy()
|
||||||
#include <math.h> // for sqrt() for diagonal check
|
#include <math.h> // for sqrt() for diagonal check
|
||||||
|
|
||||||
|
#include "tcltk/tclmagic.h"
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "tiles/tile.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/signals.h"
|
||||||
#include "utils/maxrect.h"
|
#include "utils/maxrect.h"
|
||||||
#include "utils/malloc.h"
|
#include "utils/malloc.h"
|
||||||
|
#include "utils/undo.h"
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
|
#include "cif/CIFint.h"
|
||||||
|
|
||||||
int dbDRCDebug = 0;
|
int dbDRCDebug = 0;
|
||||||
|
|
||||||
|
|
@ -48,7 +52,7 @@ int dbDRCDebug = 0;
|
||||||
static DRCCookie drcOverlapCookie = {
|
static DRCCookie drcOverlapCookie = {
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
{ {0} }, { {0} },
|
{ {0} }, { {0} },
|
||||||
0, 0, 0,
|
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||||
DRC_OVERLAP_TAG,
|
DRC_OVERLAP_TAG,
|
||||||
(DRCCookie *) NULL
|
(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)
|
* Euclidean-distance point-to-segment distance (squared)
|
||||||
* calculation (borrowed from XCircuit)
|
* calculation (borrowed from XCircuit)
|
||||||
|
|
@ -468,12 +498,39 @@ DRCBasicCheck (celldef, checkRect, clipRect, function, cdata)
|
||||||
DBResetTilePlane(celldef->cd_planes[planeNum], DRC_UNPROCESSED);
|
DBResetTilePlane(celldef->cd_planes[planeNum], DRC_UNPROCESSED);
|
||||||
(void) DBSrPaintArea ((Tile *) NULL, celldef->cd_planes[planeNum],
|
(void) DBSrPaintArea ((Tile *) NULL, celldef->cd_planes[planeNum],
|
||||||
checkRect, &DBAllTypeBits, drcTile, (ClientData) &arg);
|
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);
|
drcCifCheck(&arg);
|
||||||
if (arg.dCD_rlist != NULL) freeMagic(arg.dCD_rlist);
|
if (arg.dCD_rlist != NULL) freeMagic(arg.dCD_rlist);
|
||||||
return (errors);
|
return (errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Expect that keeping around 3 MaxRectsData records should be sufficient
|
||||||
|
* to avoid recomputing drcCanonicalMaxwidth() multiple times. Note that
|
||||||
|
* if a PDK sets up multiple rules on an edge which all require running
|
||||||
|
* drcCanonicalMaxwidth(), then this cache size may need to be revisited.
|
||||||
|
*/
|
||||||
|
#define MAXRECTSCACHE 3
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -511,6 +568,19 @@ drcTile (tile, dinfo, arg)
|
||||||
int triggered;
|
int triggered;
|
||||||
int cdist, dist, ccdist, result;
|
int cdist, dist, ccdist, result;
|
||||||
|
|
||||||
|
/* Keep up to three MaxRectsData records to avoid doing the same
|
||||||
|
* expensive computation more than once.
|
||||||
|
*
|
||||||
|
* mrdcache[0] will be used for the tpleft tile, since it will never
|
||||||
|
* be reused. mrdcache[1] and mrdcache[2] will be used for the tile
|
||||||
|
* itself. Note that if more than 2 DRCCookie entries for the same
|
||||||
|
* edge require drcCanonicalMaxwidth(), then mrdcache[2] will be
|
||||||
|
* re-used so that at least mrdcache[1] is always a cache hit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static MaxRectsData *mrdcache[MAXRECTSCACHE] = {NULL, NULL, NULL};
|
||||||
|
DRCCookie *cptrcache;
|
||||||
|
|
||||||
arg->dCD_constraint = &errRect;
|
arg->dCD_constraint = &errRect;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -652,6 +722,8 @@ drcTile (tile, dinfo, arg)
|
||||||
DRCstatEdges++;
|
DRCstatEdges++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cptrcache = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check design rules along a vertical boundary between two tiles.
|
* Check design rules along a vertical boundary between two tiles.
|
||||||
*
|
*
|
||||||
|
|
@ -727,6 +799,44 @@ drcTile (tile, dinfo, arg)
|
||||||
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
||||||
cptr = cptr->drcc_next)
|
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 */
|
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
|
||||||
/* the code above for non-Manhattan shapes and do not */
|
/* the code above for non-Manhattan shapes and do not */
|
||||||
/* need to be processed again. */
|
/* need to be processed again. */
|
||||||
|
|
@ -769,12 +879,23 @@ drcTile (tile, dinfo, arg)
|
||||||
|
|
||||||
if (cptr->drcc_flags & DRC_REVERSE)
|
if (cptr->drcc_flags & DRC_REVERSE)
|
||||||
{
|
{
|
||||||
mrd = drcCanonicalMaxwidth(tpleft, GEO_WEST, arg, cptr);
|
mrd = drcCanonicalMaxwidth(tpleft, GEO_WEST, arg, cptr,
|
||||||
|
&mrdcache[0]);
|
||||||
triggered = 0;
|
triggered = 0;
|
||||||
}
|
}
|
||||||
else if (firsttile)
|
else
|
||||||
{
|
{
|
||||||
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr);
|
if (cptrcache == NULL)
|
||||||
|
{
|
||||||
|
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr,
|
||||||
|
&mrdcache[1]);
|
||||||
|
cptrcache = cptr;
|
||||||
|
}
|
||||||
|
else if (cptrcache != cptr)
|
||||||
|
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr,
|
||||||
|
&mrdcache[2]);
|
||||||
|
else
|
||||||
|
mrd = mrdcache[1];
|
||||||
triggered = 0;
|
triggered = 0;
|
||||||
}
|
}
|
||||||
if (!trigpending || (DRCCurStyle->DRCFlags
|
if (!trigpending || (DRCCurStyle->DRCFlags
|
||||||
|
|
@ -1065,6 +1186,8 @@ drcTile (tile, dinfo, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cptrcache = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check design rules along a horizontal boundary between two tiles.
|
* Check design rules along a horizontal boundary between two tiles.
|
||||||
*
|
*
|
||||||
|
|
@ -1136,6 +1259,44 @@ drcTile (tile, dinfo, arg)
|
||||||
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
||||||
cptr = cptr->drcc_next)
|
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 */
|
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
|
||||||
/* the code above for non-Manhattan shapes and do not */
|
/* the code above for non-Manhattan shapes and do not */
|
||||||
/* need to be processed again. */
|
/* need to be processed again. */
|
||||||
|
|
@ -1173,12 +1334,23 @@ drcTile (tile, dinfo, arg)
|
||||||
|
|
||||||
if (cptr->drcc_flags & DRC_REVERSE)
|
if (cptr->drcc_flags & DRC_REVERSE)
|
||||||
{
|
{
|
||||||
mrd = drcCanonicalMaxwidth(tpbot, GEO_SOUTH, arg, cptr);
|
mrd = drcCanonicalMaxwidth(tpbot, GEO_SOUTH, arg, cptr,
|
||||||
|
&mrdcache[0]);
|
||||||
triggered = 0;
|
triggered = 0;
|
||||||
}
|
}
|
||||||
else if (firsttile)
|
else
|
||||||
{
|
{
|
||||||
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr);
|
if (cptrcache == NULL)
|
||||||
|
{
|
||||||
|
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr,
|
||||||
|
&mrdcache[1]);
|
||||||
|
cptrcache = cptr;
|
||||||
|
}
|
||||||
|
else if (cptrcache != cptr)
|
||||||
|
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr,
|
||||||
|
&mrdcache[2]);
|
||||||
|
else
|
||||||
|
mrd = mrdcache[1];
|
||||||
triggered = 0;
|
triggered = 0;
|
||||||
}
|
}
|
||||||
if (!trigpending || (DRCCurStyle->DRCFlags
|
if (!trigpending || (DRCCurStyle->DRCFlags
|
||||||
|
|
|
||||||
|
|
@ -510,16 +510,17 @@ MaxRectsExclude(
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MaxRectsData *
|
MaxRectsData *
|
||||||
drcCanonicalMaxwidth(starttile, dir, arg, cptr)
|
drcCanonicalMaxwidth(starttile, dir, arg, cptr, mrdptr)
|
||||||
Tile *starttile;
|
Tile *starttile;
|
||||||
int dir; /* direction of rule */
|
int dir; /* direction of rule */
|
||||||
struct drcClientData *arg;
|
struct drcClientData *arg;
|
||||||
DRCCookie *cptr;
|
DRCCookie *cptr;
|
||||||
|
MaxRectsData **mrdptr;
|
||||||
{
|
{
|
||||||
int s, edgelimit;
|
int s, edgelimit;
|
||||||
Tile *tile,*tp;
|
Tile *tile,*tp;
|
||||||
TileTypeBitMask wrongtypes;
|
TileTypeBitMask wrongtypes;
|
||||||
static MaxRectsData *mrd = (MaxRectsData *)NULL;
|
MaxRectsData *mrd = *mrdptr;
|
||||||
Rect *boundrect, boundorig;
|
Rect *boundrect, boundorig;
|
||||||
|
|
||||||
/* Generate an initial array size of 8 for rlist and swap. */
|
/* Generate an initial array size of 8 for rlist and swap. */
|
||||||
|
|
@ -529,6 +530,7 @@ drcCanonicalMaxwidth(starttile, dir, arg, cptr)
|
||||||
mrd->rlist = (Rect *)mallocMagic(8 * sizeof(Rect));
|
mrd->rlist = (Rect *)mallocMagic(8 * sizeof(Rect));
|
||||||
mrd->swap = (Rect *)mallocMagic(8 * sizeof(Rect));
|
mrd->swap = (Rect *)mallocMagic(8 * sizeof(Rect));
|
||||||
mrd->listdepth = 8;
|
mrd->listdepth = 8;
|
||||||
|
*mrdptr = mrd;
|
||||||
}
|
}
|
||||||
if (starttile == NULL) return mrd;
|
if (starttile == NULL) return mrd;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ static ClientData drcSubClientData; /* To be passed to error function. */
|
||||||
static DRCCookie drcSubcellCookie = {
|
static DRCCookie drcSubcellCookie = {
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
{ {0} }, { {0} },
|
{ {0} }, { {0} },
|
||||||
0, 0, 0,
|
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||||
DRC_SUBCELL_OVERLAP_TAG,
|
DRC_SUBCELL_OVERLAP_TAG,
|
||||||
(DRCCookie *) NULL
|
(DRCCookie *) NULL
|
||||||
};
|
};
|
||||||
|
|
@ -65,7 +65,7 @@ static DRCCookie drcSubcellCookie = {
|
||||||
static DRCCookie drcInSubCookie = {
|
static DRCCookie drcInSubCookie = {
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
{ {0} }, { {0} },
|
{ {0} }, { {0} },
|
||||||
0, 0, 0,
|
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||||
DRC_IN_SUBCELL_TAG,
|
DRC_IN_SUBCELL_TAG,
|
||||||
(DRCCookie *) NULL
|
(DRCCookie *) NULL
|
||||||
};
|
};
|
||||||
|
|
@ -79,7 +79,7 @@ static DRCCookie drcInSubCookie = {
|
||||||
static DRCCookie drcOffGridCookie = {
|
static DRCCookie drcOffGridCookie = {
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
{ {0} }, { {0} },
|
{ {0} }, { {0} },
|
||||||
0, 0, 0,
|
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||||
DRC_OFFGRID_TAG,
|
DRC_OFFGRID_TAG,
|
||||||
(DRCCookie *) NULL
|
(DRCCookie *) NULL
|
||||||
};
|
};
|
||||||
|
|
@ -826,6 +826,7 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
||||||
*/
|
*/
|
||||||
subArea = *erasebox;
|
subArea = *erasebox;
|
||||||
GeoClip(&subArea, &cliparea);
|
GeoClip(&subArea, &cliparea);
|
||||||
|
if (GEO_RECTNULL(&subArea)) continue;
|
||||||
GEO_EXPAND(&subArea, DRCTechHalo, &intArea);
|
GEO_EXPAND(&subArea, DRCTechHalo, &intArea);
|
||||||
|
|
||||||
errorSaveType = DRCErrorType;
|
errorSaveType = DRCErrorType;
|
||||||
|
|
|
||||||
202
drc/DRCtech.c
202
drc/DRCtech.c
|
|
@ -72,6 +72,12 @@ static int drcRulesOptimized = 0;
|
||||||
|
|
||||||
static int DRCtag = 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.
|
* Forward declarations.
|
||||||
*/
|
*/
|
||||||
|
|
@ -79,6 +85,7 @@ int drcWidth(), drcSpacing(), drcEdge(), drcNoOverlap();
|
||||||
int drcExactOverlap(), drcExtend();
|
int drcExactOverlap(), drcExtend();
|
||||||
int drcSurround(), drcRectOnly(), drcOverhang();
|
int drcSurround(), drcRectOnly(), drcOverhang();
|
||||||
int drcStepSize(), drcOption(), drcOffGrid();
|
int drcStepSize(), drcOption(), drcOffGrid();
|
||||||
|
int drcException(), drcExemption();
|
||||||
int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles();
|
int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles();
|
||||||
int drcCifSetStyle(), drcCifWidth(), drcCifSpacing();
|
int drcCifSetStyle(), drcCifWidth(), drcCifSpacing();
|
||||||
int drcCifMaxwidth(), drcCifArea();
|
int drcCifMaxwidth(), drcCifArea();
|
||||||
|
|
@ -301,6 +308,12 @@ drcTechFreeStyle()
|
||||||
/* Clear the Why string list */
|
/* Clear the Why string list */
|
||||||
freeMagic(DRCCurStyle->DRCWhyList);
|
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);
|
freeMagic(DRCCurStyle);
|
||||||
DRCCurStyle = NULL;
|
DRCCurStyle = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -384,6 +397,63 @@ drcWhyCreate(whystring)
|
||||||
return DRCCurStyle->DRCWhySize;
|
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->DRCStepSize = 0;
|
||||||
DRCCurStyle->DRCFlags = (char)0;
|
DRCCurStyle->DRCFlags = (char)0;
|
||||||
DRCCurStyle->DRCWhySize = 0;
|
DRCCurStyle->DRCWhySize = 0;
|
||||||
|
DRCCurStyle->DRCExceptionList = (char **)NULL;
|
||||||
|
DRCCurStyle->DRCExceptionSize = 0;
|
||||||
|
|
||||||
HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS);
|
HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS);
|
||||||
|
|
||||||
|
|
@ -663,6 +735,7 @@ DRCTechStyleInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
drcCifInit();
|
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_plane = planeto;
|
||||||
(cookie)->drcc_mod = 0;
|
(cookie)->drcc_mod = 0;
|
||||||
(cookie)->drcc_cmod = 0;
|
(cookie)->drcc_cmod = 0;
|
||||||
|
(cookie)->drcc_exception = drcCurException;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is like drcCifAssign, but checks for bad plane numbers in planeto and
|
// 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 */
|
int (*rk_proc)(); /* Procedure implementing this keyword */
|
||||||
const char *rk_err; /* Error message */
|
const char *rk_err; /* Error message */
|
||||||
} ruleKeys[] = {
|
} ruleKeys[] = {
|
||||||
{"angles", 4, 4, drcAngles,
|
{"angles", 4, 4, drcAngles, "layers 45|90 why"},
|
||||||
"layers 45|90 why"},
|
|
||||||
{"edge", 8, 10, drcEdge,
|
{"edge", 8, 10, drcEdge,
|
||||||
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
|
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
|
||||||
{"edge4way", 8, 10, drcEdge,
|
{"edge4way", 8, 10, drcEdge,
|
||||||
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
|
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
|
||||||
{"exact_overlap", 2, 2, drcExactOverlap,
|
{"exact_overlap", 2, 2, drcExactOverlap, "layers"},
|
||||||
"layers"},
|
{"exception", 2, 2, drcException, "name"},
|
||||||
|
{"exemption", 2, 2, drcExemption, "name"},
|
||||||
{"extend", 5, 6, drcExtend,
|
{"extend", 5, 6, drcExtend,
|
||||||
"layers1 layers2 distance [option] why"},
|
"layers1 layers2 distance [option] why"},
|
||||||
{"no_overlap", 3, 3, drcNoOverlap,
|
{"no_overlap", 3, 3, drcNoOverlap, "layers1 layers2"},
|
||||||
"layers1 layers2"},
|
{"option", 2, 2, drcOption, "option_name option_value"},
|
||||||
{"option", 2, 2, drcOption,
|
{"overhang", 5, 5, drcOverhang, "layers1 layers2 distance why"},
|
||||||
"option_name option_value"},
|
{"rect_only", 3, 3, drcRectOnly, "layers why"},
|
||||||
{"overhang", 5, 5, drcOverhang,
|
|
||||||
"layers1 layers2 distance why"},
|
|
||||||
{"rect_only", 3, 3, drcRectOnly,
|
|
||||||
"layers why"},
|
|
||||||
{"spacing", 6, 7, drcSpacing,
|
{"spacing", 6, 7, drcSpacing,
|
||||||
"layers1 layers2 separation [layers3] adjacency why"},
|
"layers1 layers2 separation [layers3] adjacency why"},
|
||||||
{"stepsize", 2, 2, drcStepSize,
|
{"stepsize", 2, 2, drcStepSize, "step_size"},
|
||||||
"step_size"},
|
|
||||||
{"surround", 6, 7, drcSurround,
|
{"surround", 6, 7, drcSurround,
|
||||||
"layers1 layers2 distance presence why"},
|
"layers1 layers2 distance presence why"},
|
||||||
{"width", 4, 5, drcWidth,
|
{"width", 4, 5, drcWidth, "layers width why"},
|
||||||
"layers width why"},
|
|
||||||
{"widespacing", 7, 8, drcSpacing,
|
{"widespacing", 7, 8, drcSpacing,
|
||||||
"layers1 width layers2 separation adjacency why"},
|
"layers1 width layers2 separation adjacency why"},
|
||||||
{"area", 5, 5, drcArea,
|
{"area", 5, 5, drcArea, "layers area horizon why"},
|
||||||
"layers area horizon why"},
|
{"off_grid", 4, 4, drcOffGrid, "layers pitch why"},
|
||||||
{"off_grid", 4, 4, drcOffGrid,
|
{"maxwidth", 4, 6, drcMaxwidth, "layers maxwidth bends why"},
|
||||||
"layers pitch why"},
|
{"cifstyle", 2, 2, drcCifSetStyle, "cif_style"},
|
||||||
{"maxwidth", 4, 6, drcMaxwidth,
|
{"cifwidth", 4, 4, drcCifWidth, "layers width why"},
|
||||||
"layers maxwidth bends why"},
|
|
||||||
{"cifstyle", 2, 2, drcCifSetStyle,
|
|
||||||
"cif_style"},
|
|
||||||
{"cifwidth", 4, 4, drcCifWidth,
|
|
||||||
"layers width why"},
|
|
||||||
{"cifspacing", 6, 6, drcCifSpacing,
|
{"cifspacing", 6, 6, drcCifSpacing,
|
||||||
"layers1 layers2 separation adjacency why"},
|
"layers1 layers2 separation adjacency why"},
|
||||||
{"cifarea", 5, 5, drcCifArea,
|
{"cifarea", 5, 5, drcCifArea, "layers area horizon why"},
|
||||||
"layers area horizon why"},
|
{"cifmaxwidth", 5, 5, drcCifMaxwidth, "layers maxwidth bends why"},
|
||||||
{"cifmaxwidth", 5, 5, drcCifMaxwidth,
|
|
||||||
"layers maxwidth bends why"},
|
|
||||||
{"rectangle", 5, 5, drcRectangle,
|
{"rectangle", 5, 5, drcRectangle,
|
||||||
"layers maxwidth [even|odd|any] why"},
|
"layers maxwidth [even|odd|any] why"},
|
||||||
{0}
|
{0}
|
||||||
|
|
@ -1695,7 +1756,7 @@ drcMaxwidth(argc, argv)
|
||||||
if (PlaneMaskHasPlane(pmask2, plane2))
|
if (PlaneMaskHasPlane(pmask2, plane2))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (plane2 == plane)
|
if (PlaneMaskHasPlane(pmask, plane2))
|
||||||
TechError("Warning: Exclude types for \"maxwidth\" are on the "
|
TechError("Warning: Exclude types for \"maxwidth\" are on the "
|
||||||
"same plane and so cannot be checked.\n");
|
"same plane and so cannot be checked.\n");
|
||||||
}
|
}
|
||||||
|
|
@ -3634,6 +3695,84 @@ drcRectangle(argc, argv)
|
||||||
return maxwidth;
|
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_dist > next->drcc_dist) continue;
|
||||||
if (dp->drcc_cdist > next->drcc_cdist) continue;
|
if (dp->drcc_cdist > next->drcc_cdist) continue;
|
||||||
if (dp->drcc_plane != next->drcc_plane) continue;
|
if (dp->drcc_plane != next->drcc_plane) continue;
|
||||||
|
if (dp->drcc_exception != next->drcc_exception) continue;
|
||||||
if (dp->drcc_flags & DRC_REVERSE)
|
if (dp->drcc_flags & DRC_REVERSE)
|
||||||
{
|
{
|
||||||
if (!(next->drcc_flags & DRC_REVERSE)) continue;
|
if (!(next->drcc_flags & DRC_REVERSE)) continue;
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ typedef struct drccookie
|
||||||
TileTypeBitMask drcc_mask; /* Legal types on RHS */
|
TileTypeBitMask drcc_mask; /* Legal types on RHS */
|
||||||
TileTypeBitMask drcc_corner; /* Types that trigger corner check */
|
TileTypeBitMask drcc_corner; /* Types that trigger corner check */
|
||||||
unsigned short drcc_flags; /* Miscellaneous flags, see below. */
|
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_edgeplane; /* Plane of edge */
|
||||||
int drcc_plane; /* Index of plane on which to check
|
int drcc_plane; /* Index of plane on which to check
|
||||||
* legal types. */
|
* legal types. */
|
||||||
|
|
@ -91,6 +92,11 @@ typedef struct drccookie
|
||||||
#define DRC_UNPROCESSED CLIENTDEFAULT
|
#define DRC_UNPROCESSED CLIENTDEFAULT
|
||||||
#define DRC_PROCESSED 1
|
#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
|
* Background DRC (DRC Idle proc) for Tcl-based Magic
|
||||||
*/
|
*/
|
||||||
|
|
@ -177,6 +183,8 @@ typedef struct drcstyle
|
||||||
unsigned short DRCFlags; /* Option flags */
|
unsigned short DRCFlags; /* Option flags */
|
||||||
char **DRCWhyList; /* Indexed list of "why" text strings */
|
char **DRCWhyList; /* Indexed list of "why" text strings */
|
||||||
int DRCWhySize; /* Length of DRCWhyList */
|
int DRCWhySize; /* Length of DRCWhyList */
|
||||||
|
char **DRCExceptionList; /* Indexed list of DRC exceptions */
|
||||||
|
int DRCExceptionSize; /* Length of DRCExceptionList */
|
||||||
PaintResultType DRCPaintTable[NP][NT][NT];
|
PaintResultType DRCPaintTable[NP][NT][NT];
|
||||||
} DRCStyle;
|
} DRCStyle;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,9 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
|
||||||
#include "dbwind/dbwind.h" /* for DBWclientID */
|
#include "dbwind/dbwind.h" /* for DBWclientID */
|
||||||
#include "commands/commands.h" /* for module auto-load */
|
#include "commands/commands.h" /* for module auto-load */
|
||||||
#include "textio/txcommands.h"
|
#include "textio/txcommands.h"
|
||||||
|
#include "extract/extract.h" /* for extDevTable */
|
||||||
#include "extflat/extflat.h"
|
#include "extflat/extflat.h"
|
||||||
#include "extflat/EFint.h"
|
#include "extflat/EFint.h"
|
||||||
#include "extract/extract.h" /* for extDevTable */
|
|
||||||
#include "utils/runstats.h"
|
#include "utils/runstats.h"
|
||||||
#include "utils/malloc.h"
|
#include "utils/malloc.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,14 +41,11 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
|
||||||
#include "commands/commands.h" /* for module auto-load */
|
#include "commands/commands.h" /* for module auto-load */
|
||||||
#include "textio/txcommands.h"
|
#include "textio/txcommands.h"
|
||||||
#include "extflat/extflat.h"
|
#include "extflat/extflat.h"
|
||||||
#include "extflat/EFint.h"
|
|
||||||
#include "extract/extract.h" /* for extDevTable */
|
#include "extract/extract.h" /* for extDevTable */
|
||||||
|
#include "extflat/EFint.h"
|
||||||
#include "utils/runstats.h"
|
#include "utils/runstats.h"
|
||||||
#include "ext2spice/ext2spice.h"
|
#include "ext2spice/ext2spice.h"
|
||||||
|
|
||||||
/* C99 compat */
|
|
||||||
#include "extflat/extflat.h"
|
|
||||||
|
|
||||||
/* These global values are defined in ext2spice.c */
|
/* These global values are defined in ext2spice.c */
|
||||||
extern HashTable subcktNameTable;
|
extern HashTable subcktNameTable;
|
||||||
extern DQueue subcktNameQueue;
|
extern DQueue subcktNameQueue;
|
||||||
|
|
@ -637,7 +634,7 @@ subcktHierVisit(
|
||||||
|
|
||||||
if (hasports || is_top)
|
if (hasports || is_top)
|
||||||
return subcktVisit(use, hierName, 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;
|
return 0;
|
||||||
else
|
else
|
||||||
return subcktVisit(use, hierName, is_top);
|
return subcktVisit(use, hierName, is_top);
|
||||||
|
|
@ -1091,6 +1088,7 @@ spcdevHierVisit(
|
||||||
|
|
||||||
if (!has_model)
|
if (!has_model)
|
||||||
{
|
{
|
||||||
|
fprintf(esSpiceF, " ");
|
||||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||||
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
||||||
}
|
}
|
||||||
|
|
@ -1141,6 +1139,7 @@ spcdevHierVisit(
|
||||||
|
|
||||||
if (!has_model)
|
if (!has_model)
|
||||||
{
|
{
|
||||||
|
fprintf(esSpiceF, " ");
|
||||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||||
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,9 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
|
||||||
#include "dbwind/dbwind.h" /* for DBWclientID */
|
#include "dbwind/dbwind.h" /* for DBWclientID */
|
||||||
#include "commands/commands.h" /* for module auto-load */
|
#include "commands/commands.h" /* for module auto-load */
|
||||||
#include "textio/txcommands.h"
|
#include "textio/txcommands.h"
|
||||||
|
#include "extract/extract.h" /* for extDevTable */
|
||||||
#include "extflat/extflat.h"
|
#include "extflat/extflat.h"
|
||||||
#include "extflat/EFint.h"
|
#include "extflat/EFint.h"
|
||||||
#include "extract/extract.h" /* for extDevTable */
|
|
||||||
#include "utils/runstats.h"
|
#include "utils/runstats.h"
|
||||||
|
|
||||||
#include "ext2spice/ext2spice.h"
|
#include "ext2spice/ext2spice.h"
|
||||||
|
|
@ -1689,23 +1689,43 @@ subcktVisit(
|
||||||
HashStartSearch(&hs);
|
HashStartSearch(&hs);
|
||||||
while ((he = HashNext(&def->def_nodes, &hs)))
|
while ((he = HashNext(&def->def_nodes, &hs)))
|
||||||
{
|
{
|
||||||
|
bool found = FALSE;
|
||||||
|
|
||||||
sname = (EFNodeName *) HashGetValue(he);
|
sname = (EFNodeName *) HashGetValue(he);
|
||||||
if (sname == NULL) continue;
|
if (sname == NULL) continue;
|
||||||
snode = sname->efnn_node;
|
snode = sname->efnn_node;
|
||||||
|
|
||||||
if ((snode == NULL) || !(snode->efnode_flags & EF_PORT)) continue;
|
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)
|
for (nodeName = sname; nodeName != NULL; nodeName = nodeName->efnn_next)
|
||||||
{
|
{
|
||||||
|
if (found == TRUE) break;
|
||||||
|
|
||||||
portidx = nodeName->efnn_port;
|
portidx = nodeName->efnn_port;
|
||||||
if (portidx < 0) continue;
|
if (portidx < 0) continue;
|
||||||
if (nodeList[portidx] == NULL)
|
if (nodeList[portidx] == NULL)
|
||||||
{
|
{
|
||||||
nodeList[portidx] = nodeName;
|
nodeList[portidx] = nodeName;
|
||||||
|
found = TRUE;
|
||||||
}
|
}
|
||||||
else if (EFHNBest(nodeName->efnn_hier, nodeList[portidx]->efnn_hier))
|
else if (EFHNBest(nodeName->efnn_hier, nodeList[portidx]->efnn_hier))
|
||||||
{
|
{
|
||||||
nodeList[portidx] = nodeName;
|
nodeList[portidx] = nodeName;
|
||||||
|
found = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1932,6 +1952,7 @@ topVisit(
|
||||||
{
|
{
|
||||||
char stmp[MAX_STR_SIZE];
|
char stmp[MAX_STR_SIZE];
|
||||||
int portidx;
|
int portidx;
|
||||||
|
bool found = FALSE;
|
||||||
|
|
||||||
sname = (EFNodeName *) HashGetValue(he);
|
sname = (EFNodeName *) HashGetValue(he);
|
||||||
if (sname == NULL) continue; /* Should not happen */
|
if (sname == NULL) continue; /* Should not happen */
|
||||||
|
|
@ -1939,33 +1960,68 @@ topVisit(
|
||||||
snode = sname->efnn_node;
|
snode = sname->efnn_node;
|
||||||
if ((!snode) || (!(snode->efnode_flags & EF_PORT))) continue;
|
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)
|
for (nodeName = sname; nodeName != NULL; nodeName = nodeName->efnn_next)
|
||||||
{
|
{
|
||||||
|
if (found == TRUE) break;
|
||||||
portidx = nodeName->efnn_port;
|
portidx = nodeName->efnn_port;
|
||||||
if (portidx < 0) continue;
|
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)
|
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);
|
EFHNSprintf(stmp, nodeName->efnn_hier);
|
||||||
pname = stmp;
|
pname = stmp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// pname = nodeSpiceName(snode->efnode_name->efnn_hier, NULL);
|
|
||||||
pname = nodeSpiceName(nodeName->efnn_hier, NULL);
|
pname = nodeSpiceName(nodeName->efnn_hier, NULL);
|
||||||
|
|
||||||
if (heh == (HashEntry *)NULL) /* pname now resolved for log output */
|
if (heh == (HashEntry *)NULL) /* pname now resolved for log output */
|
||||||
|
|
@ -1983,7 +2039,10 @@ topVisit(
|
||||||
hep = HashFind(&portNameTable, pname);
|
hep = HashFind(&portNameTable, pname);
|
||||||
HashSetValue(hep, (ClientData)(pointertype)nodeName->efnn_port);
|
HashSetValue(hep, (ClientData)(pointertype)nodeName->efnn_port);
|
||||||
if (sorted_ports[portidx] == NULL)
|
if (sorted_ports[portidx] == NULL)
|
||||||
|
{
|
||||||
sorted_ports[portidx] = StrDup((char **)NULL, pname);
|
sorted_ports[portidx] = StrDup((char **)NULL, pname);
|
||||||
|
found = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -3081,6 +3140,7 @@ spcdevVisit(
|
||||||
|
|
||||||
if (!has_model)
|
if (!has_model)
|
||||||
{
|
{
|
||||||
|
fprintf(esSpiceF, " ");
|
||||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||||
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
|
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
|
||||||
}
|
}
|
||||||
|
|
@ -3127,6 +3187,7 @@ spcdevVisit(
|
||||||
|
|
||||||
if (!has_model)
|
if (!has_model)
|
||||||
{
|
{
|
||||||
|
fprintf(esSpiceF, " ");
|
||||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||||
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
|
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header$";
|
||||||
#include "tiles/tile.h"
|
#include "tiles/tile.h"
|
||||||
#include "database/database.h" /* for TileType definition */
|
#include "database/database.h" /* for TileType definition */
|
||||||
#include "extflat/extflat.h"
|
#include "extflat/extflat.h"
|
||||||
|
#include "extflat/extparse.h"
|
||||||
#include "extflat/EFint.h"
|
#include "extflat/EFint.h"
|
||||||
#include "extract/extract.h" /* for device class list */
|
#include "extract/extract.h"
|
||||||
#include "extract/extractInt.h" /* for extGetDevType() */
|
#include "extract/extractInt.h" /* for extGetDevType() */
|
||||||
|
|
||||||
/* C99 compat */
|
/* C99 compat */
|
||||||
|
|
@ -647,8 +648,21 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (!resist)
|
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);
|
"shorted.\n", nodeName1, nodeName2);
|
||||||
|
if (uptr1) *uptr1 = '_';
|
||||||
|
if (uptr2) *uptr2 = '_';
|
||||||
|
}
|
||||||
else
|
else
|
||||||
/* Do not merge the nodes when folding in extresist parasitics */
|
/* Do not merge the nodes when folding in extresist parasitics */
|
||||||
return;
|
return;
|
||||||
|
|
@ -2102,7 +2116,7 @@ efNodeMerge(node1ptr, node2ptr)
|
||||||
/* Make all EFNodeNames point to "keeping" */
|
/* Make all EFNodeNames point to "keeping" */
|
||||||
if (removing->efnode_name)
|
if (removing->efnode_name)
|
||||||
{
|
{
|
||||||
bool topportk, topportr, bestname;
|
bool topportk, topportr, bestname, swapnames;
|
||||||
|
|
||||||
for (nn = removing->efnode_name; nn; nn = nn->efnn_next)
|
for (nn = removing->efnode_name; nn; nn = nn->efnn_next)
|
||||||
{
|
{
|
||||||
|
|
@ -2113,10 +2127,31 @@ efNodeMerge(node1ptr, node2ptr)
|
||||||
topportk = (keeping->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
|
topportk = (keeping->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
|
||||||
topportr = (removing->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
|
topportr = (removing->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
|
||||||
|
|
||||||
/* Concatenate list of EFNodeNames, taking into account precedence */
|
/* The node "keeping" is being kept, but we need to decide which
|
||||||
if ((!keeping->efnode_name) || (!topportk && topportr)
|
* node name of the two will be the node name of "keeping". If
|
||||||
|| EFHNBest(removing->efnode_name->efnn_hier,
|
* "keeping" has the best node name, then we're good; otherwise,
|
||||||
keeping->efnode_name->efnn_hier))
|
* 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".
|
* New official name is that of "removing".
|
||||||
|
|
@ -2203,6 +2238,14 @@ efNodeMerge(node1ptr, node2ptr)
|
||||||
if (removing->efnode_flags & EF_SUBS_NODE)
|
if (removing->efnode_flags & EF_SUBS_NODE)
|
||||||
keeping->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
|
/* If EFSaveLocs is set, then merge any disjoint segments from
|
||||||
* removing to keeping.
|
* removing to keeping.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
|
#include "extflat/extparse.h"
|
||||||
extern char *efReadFileName;
|
|
||||||
extern int efReadLineNum;
|
|
||||||
|
|
||||||
#ifdef MAGIC_WRAPPER
|
#ifdef MAGIC_WRAPPER
|
||||||
extern int Tcl_printf();
|
extern int Tcl_printf();
|
||||||
|
|
|
||||||
|
|
@ -61,15 +61,17 @@ int efFlatGlobHash(HierName *);
|
||||||
bool efFlatGlobCmp(HierName *, HierName *);
|
bool efFlatGlobCmp(HierName *, HierName *);
|
||||||
char *efFlatGlobCopy(HierName *);
|
char *efFlatGlobCopy(HierName *);
|
||||||
void efFlatGlobError(EFNodeName *nameGlob, EFNodeName *nameFlat);
|
void efFlatGlobError(EFNodeName *nameGlob, EFNodeName *nameFlat);
|
||||||
int efAddNodes(HierContext *hc, bool stdcell);
|
int efAddNodes(HierContext *hc, int flags);
|
||||||
int efAddConns(HierContext *hc, bool doWarn);
|
int efAddConns(HierContext *hc, int flags);
|
||||||
int efAddOneConn(HierContext *hc, char *name1, char *name2, Connection *conn, bool doWarn);
|
int efAddOneConn(HierContext *hc, char *name1, char *name2, Connection *conn, int flags);
|
||||||
|
|
||||||
/* Flags passed to efFlatNode() */
|
/* Flags passed to efFlatNode() */
|
||||||
|
|
||||||
#define FLATNODE_STDCELL 0x01
|
#define FLATNODE_STDCELL 0x01
|
||||||
#define FLATNODE_DOWARN 0x02
|
#define FLATNODE_DOWARN 0x02
|
||||||
#define FLATNODE_NOABSTRACT 0x04
|
#define FLATNODE_NOABSTRACT 0x04
|
||||||
|
#define FLATNODE_HIER 0x08
|
||||||
|
#define FLATNODE_CHILD 0x10
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -216,7 +218,7 @@ EFFlatBuildOneLevel(def, flags)
|
||||||
efFlatRootUse.use_def = efFlatRootDef;
|
efFlatRootUse.use_def = efFlatRootDef;
|
||||||
|
|
||||||
/* Record all nodes down the hierarchy from here */
|
/* Record all nodes down the hierarchy from here */
|
||||||
flatnodeflags = 0; /* No FLATNODE_DOWARN */
|
flatnodeflags = FLATNODE_HIER; /* No FLATNODE_DOWARN */
|
||||||
efFlatNodes(&efFlatContext, INT2CD(flatnodeflags));
|
efFlatNodes(&efFlatContext, INT2CD(flatnodeflags));
|
||||||
|
|
||||||
/* Expand all subcells that contain connectivity information but */
|
/* Expand all subcells that contain connectivity information but */
|
||||||
|
|
@ -320,9 +322,7 @@ efFlatNodes(hc, clientData)
|
||||||
ClientData clientData;
|
ClientData clientData;
|
||||||
{
|
{
|
||||||
int flags = (int)CD2INT(clientData);
|
int flags = (int)CD2INT(clientData);
|
||||||
|
int hierflags = 0;
|
||||||
bool stdcell = (flags & FLATNODE_STDCELL) ? TRUE : FALSE;
|
|
||||||
bool doWarn = (flags & FLATNODE_DOWARN) ? TRUE : FALSE;
|
|
||||||
|
|
||||||
if (flags & FLATNODE_NOABSTRACT)
|
if (flags & FLATNODE_NOABSTRACT)
|
||||||
{
|
{
|
||||||
|
|
@ -332,13 +332,19 @@ efFlatNodes(hc, clientData)
|
||||||
def->def_name);
|
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 */
|
/* Add all our own nodes to the table */
|
||||||
efAddNodes(hc, stdcell);
|
efAddNodes(hc, flags);
|
||||||
|
|
||||||
/* Process our own connections and adjustments */
|
/* Process our own connections and adjustments */
|
||||||
(void) efAddConns(hc, doWarn);
|
(void) efAddConns(hc, flags);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
@ -386,11 +392,11 @@ efFlatNodesStdCell(hc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add all our own nodes to the table */
|
/* Add all our own nodes to the table */
|
||||||
efAddNodes(hc, TRUE);
|
efAddNodes(hc, (int)FLATNODE_STDCELL);
|
||||||
|
|
||||||
/* Process our own connections and adjustments */
|
/* Process our own connections and adjustments */
|
||||||
if (!(hc->hc_use->use_def->def_flags & DEF_SUBCIRCUIT))
|
if (!(hc->hc_use->use_def->def_flags & DEF_SUBCIRCUIT))
|
||||||
(void) efAddConns(hc, TRUE);
|
(void) efAddConns(hc, (int)FLATNODE_DOWARN);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
@ -413,10 +419,10 @@ efFlatNodesDeviceless(hc, cdata)
|
||||||
if ((HashGetNumEntries(&hc->hc_use->use_def->def_devs) == 0) && (newcount == 0))
|
if ((HashGetNumEntries(&hc->hc_use->use_def->def_devs) == 0) && (newcount == 0))
|
||||||
{
|
{
|
||||||
/* Add all our own nodes to the table */
|
/* Add all our own nodes to the table */
|
||||||
efAddNodes(hc, TRUE);
|
efAddNodes(hc, (int)FLATNODE_STDCELL);
|
||||||
|
|
||||||
/* Process our own connections and adjustments */
|
/* 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 */
|
/* Mark this definition as having no devices, so it will not be visited */
|
||||||
hc->hc_use->use_def->def_flags |= DEF_NODEVICES;
|
hc->hc_use->use_def->def_flags |= DEF_NODEVICES;
|
||||||
|
|
@ -455,7 +461,7 @@ efFlatNodesDeviceless(hc, cdata)
|
||||||
int
|
int
|
||||||
efAddNodes(
|
efAddNodes(
|
||||||
HierContext *hc,
|
HierContext *hc,
|
||||||
bool stdcell)
|
int flags)
|
||||||
{
|
{
|
||||||
Def *def = hc->hc_use->use_def;
|
Def *def = hc->hc_use->use_def;
|
||||||
EFNodeName *nn, *newname, *oldname;
|
EFNodeName *nn, *newname, *oldname;
|
||||||
|
|
@ -465,6 +471,8 @@ efAddNodes(
|
||||||
HierName *hierName;
|
HierName *hierName;
|
||||||
int size, asize;
|
int size, asize;
|
||||||
HashEntry *he;
|
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;
|
bool is_subcircuit = (def->def_flags & DEF_SUBCIRCUIT) ? TRUE : FALSE;
|
||||||
|
|
||||||
size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (EFPerimArea);
|
size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (EFPerimArea);
|
||||||
|
|
@ -503,12 +511,15 @@ efAddNodes(
|
||||||
// If called with "hierarchy on", all local node caps and adjustments
|
// If called with "hierarchy on", all local node caps and adjustments
|
||||||
// have been output and should be ignored.
|
// 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_client = (ClientData) NULL;
|
||||||
newnode->efnode_flags = node->efnode_flags;
|
newnode->efnode_flags = node->efnode_flags;
|
||||||
newnode->efnode_type = node->efnode_type;
|
newnode->efnode_type = node->efnode_type;
|
||||||
newnode->efnode_num = 1;
|
newnode->efnode_num = 1;
|
||||||
if (!stdcell)
|
if (!stdcell && !is_child)
|
||||||
bcopy((char *) node->efnode_pa, (char *) newnode->efnode_pa,
|
bcopy((char *) node->efnode_pa, (char *) newnode->efnode_pa,
|
||||||
efNumResistClasses * sizeof (EFPerimArea));
|
efNumResistClasses * sizeof (EFPerimArea));
|
||||||
else
|
else
|
||||||
|
|
@ -601,7 +612,7 @@ efAddNodes(
|
||||||
int
|
int
|
||||||
efAddConns(
|
efAddConns(
|
||||||
HierContext *hc,
|
HierContext *hc,
|
||||||
bool doWarn)
|
int flags)
|
||||||
{
|
{
|
||||||
Connection *conn;
|
Connection *conn;
|
||||||
|
|
||||||
|
|
@ -614,9 +625,9 @@ efAddConns(
|
||||||
{
|
{
|
||||||
/* Special case for speed when no array info is present */
|
/* Special case for speed when no array info is present */
|
||||||
if (conn->conn_1.cn_nsubs == 0)
|
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
|
else
|
||||||
efHierSrArray(hc, conn, efAddOneConn, INT2CD(doWarn));
|
efHierSrArray(hc, conn, efAddOneConn, INT2CD(flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
|
|
@ -648,18 +659,23 @@ efAddOneConn(
|
||||||
char *name1, /* These are strings, not HierNames */
|
char *name1, /* These are strings, not HierNames */
|
||||||
char *name2,
|
char *name2,
|
||||||
Connection *conn,
|
Connection *conn,
|
||||||
bool doWarn)
|
int flags)
|
||||||
{
|
{
|
||||||
HashEntry *he1, *he2;
|
HashEntry *he1, *he2;
|
||||||
EFNode *node, *newnode;
|
EFNode *node, *newnode;
|
||||||
int n;
|
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);
|
he1 = EFHNLook(hc->hc_hierName, name1, (doWarn) ? "connect(1)" : NULL);
|
||||||
if (he1 == NULL)
|
if (he1 == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Adjust the resistance and capacitance of its corresponding node */
|
|
||||||
node = ((EFNodeName *) HashGetValue(he1))->efnn_node;
|
node = ((EFNodeName *) HashGetValue(he1))->efnn_node;
|
||||||
|
|
||||||
|
/* Adjust the resistance and capacitance of its corresponding node */
|
||||||
|
|
||||||
node->efnode_cap += conn->conn_cap;
|
node->efnode_cap += conn->conn_cap;
|
||||||
for (n = 0; n < efNumResistClasses; n++)
|
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
|
* variables cause nets named VDD and GND to become globals, which was
|
||||||
* not intended.
|
* 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:
|
* Results:
|
||||||
* TRUE if the name is a global.
|
* TRUE if the name is a global.
|
||||||
*
|
*
|
||||||
|
|
@ -99,12 +105,10 @@ EFHNIsGlob(hierName)
|
||||||
char *retstr;
|
char *retstr;
|
||||||
retstr = (char *)Tcl_GetVar2(magicinterp, "globals", hierName->hn_name,
|
retstr = (char *)Tcl_GetVar2(magicinterp, "globals", hierName->hn_name,
|
||||||
TCL_GLOBAL_ONLY);
|
TCL_GLOBAL_ONLY);
|
||||||
if (retstr != NULL) return TRUE;
|
return (retstr != NULL) ? TRUE : FALSE;
|
||||||
|
#else
|
||||||
// retstr = (char *)Tcl_GetVar(magicinterp, hierName->hn_name, TCL_GLOBAL_ONLY);
|
|
||||||
// if (retstr != NULL) return TRUE;
|
|
||||||
#endif
|
|
||||||
return hierName->hn_name[strlen(hierName->hn_name) - 1] == '!';
|
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];
|
last1 = hierName1->hn_name[strlen(hierName1->hn_name) - 1];
|
||||||
last2 = hierName2->hn_name[strlen(hierName2->hn_name) - 1];
|
last2 = hierName2->hn_name[strlen(hierName2->hn_name) - 1];
|
||||||
|
|
||||||
if (last1 != '!' || last2 != '!')
|
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 */
|
/* Prefer global over local names */
|
||||||
if (last1 == '!') return TRUE;
|
if (last1 == '!') return TRUE;
|
||||||
if (last2 == '!') return FALSE;
|
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 TRUE;
|
||||||
if (last1 == '#' && last2 != '#') return FALSE;
|
if (last1 == '#' && last2 != '#') return FALSE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
#include "commands/commands.h"
|
#include "commands/commands.h"
|
||||||
#include "database/database.h"
|
#include "database/database.h"
|
||||||
#include "extflat/extflat.h"
|
#include "extflat/extflat.h"
|
||||||
|
#include "extflat/extparse.h"
|
||||||
#include "extflat/EFint.h"
|
#include "extflat/EFint.h"
|
||||||
#include "extract/extract.h"
|
#include "extract/extract.h"
|
||||||
#include "extract/extractInt.h"
|
#include "extract/extractInt.h"
|
||||||
|
|
@ -48,58 +49,11 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
#ifndef MAGIC_WRAPPER
|
#ifndef MAGIC_WRAPPER
|
||||||
/* This must match the definition for extDevTable in extract/ExtBasic.c */
|
/* This must match the definition for extDevTable in extract/ExtBasic.c */
|
||||||
const char * const extDevTable[] = {"fet", "mosfet", "asymmetric", "bjt", "devres",
|
const char * const extDevTable[] = {"fet", "mosfet", "asymmetric", "bjt", "devres",
|
||||||
"devcap", "devcaprev", "vsource", "diode", "pdiode",
|
"devcap", "devcaprev", "vsource", "diode", "pdiode",
|
||||||
"ndiode", "subckt", "rsubckt", "msubckt", "csubckt",
|
"ndiode", "subckt", "rsubckt", "msubckt", "csubckt",
|
||||||
"dsubckt", "veriloga", NULL};
|
"dsubckt", "veriloga", NULL};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* The following table describes the kinds of lines
|
|
||||||
* that may be read in a .ext file.
|
|
||||||
*/
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
ABSTRACT, ADJUST, ATTR, CAP, DEVICE, DIST, EQUIV, FET, KILLNODE, MERGE,
|
|
||||||
NODE, PARAMETERS, PORT, PRIMITIVE, RESISTOR, RESISTCLASS, RNODE, SCALE,
|
|
||||||
SUBCAP, SUBSTRATE, TECH, TIMESTAMP, USE, VERSION, EXT_STYLE
|
|
||||||
} Key;
|
|
||||||
|
|
||||||
static const struct
|
|
||||||
{
|
|
||||||
const char *k_name; /* Name of first token on line */
|
|
||||||
Key k_key; /* Internal name for token of this type */
|
|
||||||
int k_mintokens; /* Min total # of tokens on line of this type */
|
|
||||||
}
|
|
||||||
keyTable[] =
|
|
||||||
{
|
|
||||||
{"abstract", ABSTRACT, 0}, /* defines a LEF-like view */
|
|
||||||
{"adjust", ADJUST, 4},
|
|
||||||
{"attr", ATTR, 8},
|
|
||||||
{"cap", CAP, 4},
|
|
||||||
{"device", DEVICE, 11}, /* effectively replaces "fet" */
|
|
||||||
{"distance", DIST, 4},
|
|
||||||
{"equiv", EQUIV, 3},
|
|
||||||
{"fet", FET, 12}, /* for backwards compatibility */
|
|
||||||
{"killnode", KILLNODE, 2},
|
|
||||||
{"merge", MERGE, 3},
|
|
||||||
{"node", NODE, 7},
|
|
||||||
{"parameters", PARAMETERS, 3},
|
|
||||||
{"port", PORT, 8},
|
|
||||||
{"primitive", PRIMITIVE, 0}, /* defines a primitive device */
|
|
||||||
{"resist", RESISTOR, 4},
|
|
||||||
{"resistclasses", RESISTCLASS, 1},
|
|
||||||
{"rnode", RNODE, 5},
|
|
||||||
{"scale", SCALE, 4},
|
|
||||||
{"subcap", SUBCAP, 3},
|
|
||||||
{"substrate", SUBSTRATE, 3},
|
|
||||||
{"tech", TECH, 2},
|
|
||||||
{"timestamp", TIMESTAMP, 2},
|
|
||||||
{"use", USE, 9},
|
|
||||||
{"version", VERSION, 2},
|
|
||||||
{"style", EXT_STYLE, 2},
|
|
||||||
{0}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Data shared with EFerror.c */
|
/* Data shared with EFerror.c */
|
||||||
char *efReadFileName; /* Name of file currently being read */
|
char *efReadFileName; /* Name of file currently being read */
|
||||||
int efReadLineNum; /* Current line number in above file */
|
int efReadLineNum; /* Current line number in above file */
|
||||||
|
|
@ -109,10 +63,6 @@ bool EFSaveLocs; /* If TRUE, save location of merged top-level nodes */
|
||||||
/* Data local to this file */
|
/* Data local to this file */
|
||||||
static bool efReadDef(Def *def, bool dosubckt, bool resist, bool noscale, bool toplevel, bool isspice);
|
static bool efReadDef(Def *def, bool dosubckt, bool resist, bool noscale, bool toplevel, bool isspice);
|
||||||
|
|
||||||
/* atoCap - convert a string to a EFCapValue */
|
|
||||||
#define atoCap(s) ((EFCapValue)atof(s))
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@
|
||||||
#include "extflat/EFtypes.h" /* EFCapValue, HierName, EFPerimArea, EFNode */
|
#include "extflat/EFtypes.h" /* EFCapValue, HierName, EFPerimArea, EFNode */
|
||||||
#include "extflat/EFint.h" /* Def, HierContext, Connection, Distance, CallArg */
|
#include "extflat/EFint.h" /* Def, HierContext, Connection, Distance, CallArg */
|
||||||
|
|
||||||
|
|
||||||
extern float EFScale; /* Scale factor to multiply all coords by */
|
extern float EFScale; /* Scale factor to multiply all coords by */
|
||||||
extern char *EFTech; /* Technology of extracted circuit */
|
extern char *EFTech; /* Technology of extracted circuit */
|
||||||
extern char *EFStyle; /* Extraction style of extracted circuit */
|
extern char *EFStyle; /* Extraction style of extracted circuit */
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* extparse.h
|
||||||
|
*
|
||||||
|
* Definitions for the .ext file parser. Relocated from EFread.c.
|
||||||
|
*
|
||||||
|
* *********************************************************************
|
||||||
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
||||||
|
* * Permission to use, copy, modify, and distribute this *
|
||||||
|
* * software and its documentation for any purpose and without *
|
||||||
|
* * fee is hereby granted, provided that the above copyright *
|
||||||
|
* * notice appear in all copies. The University of California *
|
||||||
|
* * makes no representations about the suitability of this *
|
||||||
|
* * software for any purpose. It is provided "as is" without *
|
||||||
|
* * express or implied warranty. Export of this software outside *
|
||||||
|
* * of the United States of America may require an export license. *
|
||||||
|
* *********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MAGIC__EXTFLAT__EXTPARSE_H
|
||||||
|
#define _MAGIC__EXTFLAT__EXTPARSE_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following table describes the kinds of lines
|
||||||
|
* that may be read in a .ext file.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
ABSTRACT, ADJUST, ATTR, CAP, DEVICE, DIST, EQUIV, FET, KILLNODE, MERGE,
|
||||||
|
NODE, PARAMETERS, PORT, PRIMITIVE, RESISTOR, RESISTCLASS, RNODE, SCALE,
|
||||||
|
SUBCAP, SUBSTRATE, TECH, TIMESTAMP, USE, VERSION, EXT_STYLE
|
||||||
|
} Key;
|
||||||
|
|
||||||
|
static const struct
|
||||||
|
{
|
||||||
|
const char *k_name; /* Name of first token on line */
|
||||||
|
Key k_key; /* Internal name for token of this type */
|
||||||
|
int k_mintokens; /* Min total # of tokens on line of this type */
|
||||||
|
}
|
||||||
|
keyTable[] =
|
||||||
|
{
|
||||||
|
{"abstract", ABSTRACT, 0}, /* defines a LEF-like view */
|
||||||
|
{"adjust", ADJUST, 4},
|
||||||
|
{"attr", ATTR, 8},
|
||||||
|
{"cap", CAP, 4},
|
||||||
|
{"device", DEVICE, 11}, /* effectively replaces "fet" */
|
||||||
|
{"distance", DIST, 4},
|
||||||
|
{"equiv", EQUIV, 3},
|
||||||
|
{"fet", FET, 12}, /* for backwards compatibility */
|
||||||
|
{"killnode", KILLNODE, 2},
|
||||||
|
{"merge", MERGE, 3},
|
||||||
|
{"node", NODE, 7},
|
||||||
|
{"parameters", PARAMETERS, 3},
|
||||||
|
{"port", PORT, 8},
|
||||||
|
{"primitive", PRIMITIVE, 0}, /* defines a primitive device */
|
||||||
|
{"resist", RESISTOR, 4},
|
||||||
|
{"resistclasses", RESISTCLASS, 1},
|
||||||
|
{"rnode", RNODE, 5},
|
||||||
|
{"scale", SCALE, 4},
|
||||||
|
{"subcap", SUBCAP, 3},
|
||||||
|
{"substrate", SUBSTRATE, 3},
|
||||||
|
{"tech", TECH, 2},
|
||||||
|
{"timestamp", TIMESTAMP, 2},
|
||||||
|
{"use", USE, 9},
|
||||||
|
{"version", VERSION, 2},
|
||||||
|
{"style", EXT_STYLE, 2},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* atoCap - convert a string to a EFCapValue */
|
||||||
|
#define atoCap(s) ((EFCapValue)atof(s))
|
||||||
|
|
||||||
|
extern int efReadLineNum; /* Current line number in the .ext file */
|
||||||
|
extern char *efReadFileName; /* Name of current .ext file being read */
|
||||||
|
|
||||||
|
#endif /* _MAGIC__EXTFLAT__EXTPARSE_H */
|
||||||
|
|
@ -37,6 +37,7 @@ static char sccsid[] = "@(#)ExtBasic.c 4.13 MAGIC (Berkeley) 12/5/85";
|
||||||
#include "utils/malloc.h"
|
#include "utils/malloc.h"
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "debug/debug.h"
|
#include "debug/debug.h"
|
||||||
|
#include "extflat/extparse.h"
|
||||||
#include "extract/extract.h"
|
#include "extract/extract.h"
|
||||||
#include "extract/extractInt.h"
|
#include "extract/extractInt.h"
|
||||||
#include "utils/signals.h"
|
#include "utils/signals.h"
|
||||||
|
|
@ -85,6 +86,8 @@ typedef struct /* Position of each terminal (below) tile position */
|
||||||
{
|
{
|
||||||
int pnum;
|
int pnum;
|
||||||
Point pt;
|
Point pt;
|
||||||
|
Tile *tile; /* Any tile beloging to the terminal */
|
||||||
|
TileType type; /* Type of "tile", including split information */
|
||||||
} TermTilePos;
|
} TermTilePos;
|
||||||
|
|
||||||
/* Field definitions for tr_devmatch */
|
/* Field definitions for tr_devmatch */
|
||||||
|
|
@ -147,6 +150,7 @@ int extTransTileFunc();
|
||||||
int extTransPerimFunc();
|
int extTransPerimFunc();
|
||||||
int extTransFindSubs();
|
int extTransFindSubs();
|
||||||
int extTransFindId();
|
int extTransFindId();
|
||||||
|
void extTermAPFunc();
|
||||||
|
|
||||||
int extAnnularTileFunc();
|
int extAnnularTileFunc();
|
||||||
int extResistorTileFunc();
|
int extResistorTileFunc();
|
||||||
|
|
@ -322,7 +326,7 @@ extBasic(def, outFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for "device", as it modifies handling of parasitics */
|
/* Check for "device", as it modifies handling of parasitics */
|
||||||
propptr = (char *)DBPropGet(def, "device", &propfound);
|
propptr = DBPropGetString(def, "device", &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
{
|
{
|
||||||
/* Remove parasitics from local nodes */
|
/* Remove parasitics from local nodes */
|
||||||
|
|
@ -798,14 +802,34 @@ extOutputNodes(nodeList, outFile)
|
||||||
lastname = ll->ll_label->lab_text;
|
lastname = ll->ll_label->lab_text;
|
||||||
}
|
}
|
||||||
/* Don't print a warning unless both labels are
|
/* 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) &&
|
if ((portname != NULL) &&
|
||||||
(ll->ll_attr == LL_PORTATTR) &&
|
(ll->ll_attr == LL_PORTATTR) &&
|
||||||
(strcmp(ll->ll_label->lab_text, portname)))
|
(strcmp(ll->ll_label->lab_text, portname)))
|
||||||
TxError("Warning: Ports \"%s\" and \"%s\" are"
|
{
|
||||||
" electrically shorted.\n",
|
char *uptr1, *uptr2;
|
||||||
text, ll->ll_label->lab_text);
|
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))
|
if (!isPort && (ll->ll_attr == LL_PORTATTR))
|
||||||
portname = ll->ll_label->lab_text;
|
portname = ll->ll_label->lab_text;
|
||||||
}
|
}
|
||||||
|
|
@ -1678,7 +1702,7 @@ extOutputParameters(def, transList, outFile)
|
||||||
* and device name, and if detected, add the type corresponding to the
|
* and device name, and if detected, add the type corresponding to the
|
||||||
* device name to the mask so it gets handled, too.
|
* device name to the mask so it gets handled, too.
|
||||||
*/
|
*/
|
||||||
propptr = DBPropGet(def, "device", &propfound);
|
propptr = DBPropGetString(def, "device", &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
{
|
{
|
||||||
char *devname;
|
char *devname;
|
||||||
|
|
@ -1811,6 +1835,8 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
|
||||||
ParamList *chkParam;
|
ParamList *chkParam;
|
||||||
HashEntry *he;
|
HashEntry *he;
|
||||||
ResValue resvalue;
|
ResValue resvalue;
|
||||||
|
LabRegion *node; /* Node connected to gate terminal */
|
||||||
|
LabelList *ll; /* Gate's label list */
|
||||||
|
|
||||||
for (chkParam = devptr->exts_deviceParams; chkParam
|
for (chkParam = devptr->exts_deviceParams; chkParam
|
||||||
!= NULL; chkParam = chkParam->pl_next)
|
!= NULL; chkParam = chkParam->pl_next)
|
||||||
|
|
@ -1942,6 +1968,34 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
|
||||||
break;
|
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 */
|
/* Structures used by extTermAPFunc() for storing area and perimeter data */
|
||||||
|
|
@ -2168,8 +2222,6 @@ extTransFindTermArea(tile, dinfo, eapd)
|
||||||
TileType dinfo;
|
TileType dinfo;
|
||||||
ExtAreaPerimData *eapd;
|
ExtAreaPerimData *eapd;
|
||||||
{
|
{
|
||||||
void extTermAPFunc(); /* Forward declaration */
|
|
||||||
|
|
||||||
extEnumTerminal(tile, dinfo, DBConnectTbl, extTermAPFunc, (ClientData)eapd);
|
extEnumTerminal(tile, dinfo, DBConnectTbl, extTermAPFunc, (ClientData)eapd);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -2257,6 +2309,8 @@ extOutputDevices(def, transList, outFile)
|
||||||
extTransRec.tr_termpos[i].pnum = 0;
|
extTransRec.tr_termpos[i].pnum = 0;
|
||||||
extTransRec.tr_termpos[i].pt.p_x = 0;
|
extTransRec.tr_termpos[i].pt.p_x = 0;
|
||||||
extTransRec.tr_termpos[i].pt.p_y = 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;
|
arg.fra_def = def;
|
||||||
|
|
@ -2281,6 +2335,58 @@ extOutputDevices(def, transList, outFile)
|
||||||
arg.fra_each = extTransTileFunc;
|
arg.fra_each = extTransTileFunc;
|
||||||
ntiles = ExtFindNeighbors(reg->treg_tile, reg->treg_dinfo, arg.fra_pNum, &arg);
|
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 */
|
/* Re-mark with extTransRec.tr_gatenode */
|
||||||
arg.fra_uninit = (ClientData) reg;
|
arg.fra_uninit = (ClientData) reg;
|
||||||
arg.fra_region = (ExtRegion *) extTransRec.tr_gatenode;
|
arg.fra_region = (ExtRegion *) extTransRec.tr_gatenode;
|
||||||
|
|
@ -2649,6 +2755,56 @@ extOutputDevices(def, transList, outFile)
|
||||||
/* get corrected by extComputeEffectiveLW(). */
|
/* get corrected by extComputeEffectiveLW(). */
|
||||||
length = (extTransRec.tr_gatelen - width) / 2;
|
length = (extTransRec.tr_gatelen - width) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((n == 1) && (length == 0) && (extTransRec.tr_gatelen == 0))
|
||||||
|
{
|
||||||
|
/* If a one-terminal device has not recorded any
|
||||||
|
* gate length, then get W and L from the bounding
|
||||||
|
* box of the device. This routine could be much
|
||||||
|
* better optimized but it is probably not worth
|
||||||
|
* the effort. Just reusing the code from above
|
||||||
|
* for creating extSpecialDevice, a list of device
|
||||||
|
* tiles. Note that W and L are not distinguishable
|
||||||
|
* and hopefully the PDK defines the device by area
|
||||||
|
* and perimeter.
|
||||||
|
*/
|
||||||
|
LinkedTile *lt;
|
||||||
|
Rect devbbox, ltbox;
|
||||||
|
|
||||||
|
extSpecialDevice = (LinkedTile *)NULL;
|
||||||
|
|
||||||
|
arg.fra_uninit = (ClientData)extTransRec.tr_gatenode;
|
||||||
|
arg.fra_region = (ExtRegion *)reg;
|
||||||
|
arg.fra_each = extSDTileFunc;
|
||||||
|
ExtFindNeighbors(reg->treg_tile, reg->treg_dinfo,
|
||||||
|
arg.fra_pNum, &arg);
|
||||||
|
|
||||||
|
arg.fra_uninit = (ClientData) reg;
|
||||||
|
arg.fra_region = (ExtRegion *) extTransRec.tr_gatenode;
|
||||||
|
arg.fra_each = (int (*)()) NULL;
|
||||||
|
ExtFindNeighbors(reg->treg_tile, reg->treg_dinfo,
|
||||||
|
arg.fra_pNum, &arg);
|
||||||
|
|
||||||
|
lt = extSpecialDevice;
|
||||||
|
if (lt)
|
||||||
|
{
|
||||||
|
TiToRect(lt->t, &devbbox);
|
||||||
|
for (; lt; lt = lt->t_next)
|
||||||
|
{
|
||||||
|
TiToRect(lt->t, <box);
|
||||||
|
GeoInclude(<box, &devbbox);
|
||||||
|
}
|
||||||
|
free_magic1_t mm1 = freeMagic1_init();
|
||||||
|
for (lt = extSpecialDevice; lt; lt = lt->t_next)
|
||||||
|
freeMagic1(&mm1, (char *)lt);
|
||||||
|
freeMagic1_end(&mm1);
|
||||||
|
}
|
||||||
|
length = devbbox.r_xtop - devbbox.r_xbot;
|
||||||
|
/* Width was likely a perimeter value and will
|
||||||
|
* be recalculated as the actual device width.
|
||||||
|
*/
|
||||||
|
width = devbbox.r_ytop - devbbox.r_ybot;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------*/
|
/*------------------------------------------------------*/
|
||||||
|
|
@ -3911,8 +4067,11 @@ extTransPerimFunc(bp)
|
||||||
extTransRec.tr_termvector[thisterm].p_y = 0;
|
extTransRec.tr_termvector[thisterm].p_y = 0;
|
||||||
extTransRec.tr_termpos[thisterm].pnum = DBPlane(toutside);
|
extTransRec.tr_termpos[thisterm].pnum = DBPlane(toutside);
|
||||||
extTransRec.tr_termpos[thisterm].pt = bp->b_outside->ti_ll;
|
extTransRec.tr_termpos[thisterm].pt = bp->b_outside->ti_ll;
|
||||||
|
/* tile and dinfo need only be one valid terminal tile,
|
||||||
/* Find the total area of this terminal */
|
* 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)
|
else if (extTransRec.tr_termnode[thisterm] == termNode)
|
||||||
{
|
{
|
||||||
|
|
@ -3944,42 +4103,6 @@ extTransPerimFunc(bp)
|
||||||
/* Add the length to this terminal's perimeter */
|
/* Add the length to this terminal's perimeter */
|
||||||
extTransRec.tr_termlen[thisterm] += len;
|
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 */
|
/* Update the boundary traversal vector */
|
||||||
switch(bp->b_direction) {
|
switch(bp->b_direction) {
|
||||||
case BD_LEFT:
|
case BD_LEFT:
|
||||||
|
|
@ -4994,9 +5117,12 @@ extFindNodes(def, clipArea, subonly)
|
||||||
/* If the default substrate type is set, it is used *only* for */
|
/* If the default substrate type is set, it is used *only* for */
|
||||||
/* isolated substrate regions and does not mark the default */
|
/* isolated substrate regions and does not mark the default */
|
||||||
/* substrate, so remove it from the list of substrate types. */
|
/* substrate, so remove it from the list of substrate types. */
|
||||||
|
/* Note that this is not the case when doing full R-C */
|
||||||
|
/* extraction. */
|
||||||
|
|
||||||
if (ExtCurStyle->exts_globSubstrateDefaultType != -1)
|
if (!(ExtOptions & EXT_DOEXTRESIST))
|
||||||
TTMaskClearType(&subsTypesNonSpace,
|
if (ExtCurStyle->exts_globSubstrateDefaultType != -1)
|
||||||
|
TTMaskClearType(&subsTypesNonSpace,
|
||||||
ExtCurStyle->exts_globSubstrateDefaultType);
|
ExtCurStyle->exts_globSubstrateDefaultType);
|
||||||
|
|
||||||
pNum = ExtCurStyle->exts_globSubstratePlane;
|
pNum = ExtCurStyle->exts_globSubstratePlane;
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
int extOutputUsesFunc();
|
int extOutputUsesFunc();
|
||||||
FILE *extFileOpen();
|
|
||||||
|
|
||||||
Plane* extCellFile();
|
Plane* extCellFile();
|
||||||
void extHeader();
|
void extHeader();
|
||||||
|
|
@ -96,7 +95,7 @@ ExtCell(def, outName, doLength)
|
||||||
if (def->cd_flags & CDNOEXTRACT)
|
if (def->cd_flags & CDNOEXTRACT)
|
||||||
return extPrepSubstrate(def);
|
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);
|
TxPrintf("Extracting %s into %s:\n", def->cd_name, filename);
|
||||||
|
|
||||||
|
|
@ -132,7 +131,7 @@ ExtCell(def, outName, doLength)
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* extFileOpen --
|
* ExtFileOpen --
|
||||||
*
|
*
|
||||||
* Open the .ext file corresponding to a .mag file.
|
* 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
|
* If def->cd_file is non-NULL, the .ext file is just def->cd_file with
|
||||||
|
|
@ -150,7 +149,7 @@ ExtCell(def, outName, doLength)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FILE *
|
FILE *
|
||||||
extFileOpen(def, file, mode, prealfile)
|
ExtFileOpen(def, file, mode, prealfile)
|
||||||
CellDef *def; /* Cell whose .ext file is to be written */
|
CellDef *def; /* Cell whose .ext file is to be written */
|
||||||
char *file; /* If non-NULL, open 'name'.ext; otherwise,
|
char *file; /* If non-NULL, open 'name'.ext; otherwise,
|
||||||
* derive filename from 'def' as described
|
* derive filename from 'def' as described
|
||||||
|
|
@ -493,7 +492,10 @@ extCellFile(def, f, doLength)
|
||||||
extUniqueCell(def, EXT_UNIQ_TEMP);
|
extUniqueCell(def, EXT_UNIQ_TEMP);
|
||||||
|
|
||||||
/* Prep any isolated substrate areas */
|
/* Prep any isolated substrate areas */
|
||||||
saveSub = extPrepSubstrate(def);
|
if (ExtOptions & EXT_DOEXTRESIST)
|
||||||
|
saveSub = extResPrepSubstrate(def);
|
||||||
|
else
|
||||||
|
saveSub = extPrepSubstrate(def);
|
||||||
|
|
||||||
/* Remove any label markers that were made by a previous extraction */
|
/* Remove any label markers that were made by a previous extraction */
|
||||||
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
||||||
|
|
@ -592,7 +594,7 @@ extHeader(def, f)
|
||||||
/* are to be passed to instances of the cell */
|
/* are to be passed to instances of the cell */
|
||||||
/* (created by defining property "parameter") */
|
/* (created by defining property "parameter") */
|
||||||
|
|
||||||
propvalue = (char *)DBPropGet(def, "parameter", &propfound);
|
propvalue = DBPropGetString(def, "parameter", &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
{
|
{
|
||||||
// Use device parameter table to store the cell def parameters,
|
// 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 tin = TiGetType(bp->b_inside);
|
||||||
TileType tout = TiGetType(bp->b_outside);
|
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];
|
pMask = ExtCurStyle->exts_sideOverlapOtherPlanes[tin][tout];
|
||||||
extOverlapDef = esws->def;
|
extOverlapDef = esws->def;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -354,8 +354,8 @@ extHierConnections(ha, cumFlat, oneFlat)
|
||||||
if (!(lab->lab_flags & LABEL_STICKY)) continue;
|
if (!(lab->lab_flags & LABEL_STICKY)) continue;
|
||||||
|
|
||||||
r = lab->lab_rect;
|
r = lab->lab_rect;
|
||||||
|
if (!GEO_TOUCH(&r, &ha->ha_subArea)) continue;
|
||||||
GEOCLIP(&r, &ha->ha_subArea);
|
GEOCLIP(&r, &ha->ha_subArea);
|
||||||
if (GEO_RECTNULL(&r)) continue;
|
|
||||||
|
|
||||||
cumDef = cumFlat->et_use->cu_def;
|
cumDef = cumFlat->et_use->cu_def;
|
||||||
connected = &DBConnectTbl[lab->lab_type];
|
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 "debug/debug.h"
|
||||||
#include "extract/extract.h"
|
#include "extract/extract.h"
|
||||||
#include "extract/extractInt.h"
|
#include "extract/extractInt.h"
|
||||||
|
#include "resis/resis.h"
|
||||||
#include "utils/signals.h"
|
#include "utils/signals.h"
|
||||||
#include "utils/stack.h"
|
#include "utils/stack.h"
|
||||||
#include "utils/utils.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/main.h"
|
||||||
#include "utils/undo.h"
|
#include "utils/undo.h"
|
||||||
|
|
||||||
/* Imports from elsewhere in this module */
|
|
||||||
extern FILE *extFileOpen();
|
|
||||||
|
|
||||||
/* ------------------------ Exported variables ------------------------ */
|
/* ------------------------ Exported variables ------------------------ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -83,16 +81,6 @@ typedef struct _linkedDef {
|
||||||
struct _linkedDef *ld_next;
|
struct _linkedDef *ld_next;
|
||||||
} LinkedDef;
|
} 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 of defs pending extraction */
|
||||||
Stack *extDefStack;
|
Stack *extDefStack;
|
||||||
|
|
||||||
|
|
@ -606,7 +594,7 @@ extParents(use, doExtract)
|
||||||
extDefParentFunc(use->cu_def);
|
extDefParentFunc(use->cu_def);
|
||||||
|
|
||||||
/* Now extract all the cells we just found */
|
/* Now extract all the cells we just found */
|
||||||
extExtractStack(extDefStack, doExtract, (CellDef *) NULL);
|
extExtractStack(extDefStack, doExtract, (CellDef *)NULL);
|
||||||
StackFree(extDefStack);
|
StackFree(extDefStack);
|
||||||
|
|
||||||
/* Replace any modified substrate planes in use->cu_def's children */
|
/* 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);
|
extDefParentAreaFunc(use->cu_def, use->cu_def, (CellUse *) NULL, &area);
|
||||||
|
|
||||||
/* Now extract all the cells we just found */
|
/* Now extract all the cells we just found */
|
||||||
extExtractStack(extDefStack, doExtract, (CellDef *) NULL);
|
extExtractStack(extDefStack, doExtract, (CellDef *)NULL);
|
||||||
StackFree(extDefStack);
|
StackFree(extDefStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -806,6 +794,23 @@ ExtractOneCell(def, outName, doLength)
|
||||||
|
|
||||||
savePlane = ExtCell(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 */
|
/* Restore all modified substrate planes and modified labels */
|
||||||
|
|
||||||
if (savePlane != NULL) ExtRevertSubstrate(def, savePlane);
|
if (savePlane != NULL) ExtRevertSubstrate(def, savePlane);
|
||||||
|
|
@ -945,7 +950,7 @@ extTimestampMisMatch(def)
|
||||||
|
|
||||||
doLocal = (ExtLocalPath == NULL) ? FALSE : TRUE;
|
doLocal = (ExtLocalPath == NULL) ? FALSE : TRUE;
|
||||||
|
|
||||||
extFile = extFileOpen(def, (char *) NULL, "r", (char **) NULL);
|
extFile = ExtFileOpen(def, (char *) NULL, "r", (char **) NULL);
|
||||||
if (extFile == NULL)
|
if (extFile == NULL)
|
||||||
return (TRUE);
|
return (TRUE);
|
||||||
|
|
||||||
|
|
@ -991,10 +996,18 @@ extExtractStack(stack, doExtract, rootDef)
|
||||||
bool first = TRUE;
|
bool first = TRUE;
|
||||||
Plane *savePlane;
|
Plane *savePlane;
|
||||||
CellDef *def;
|
CellDef *def;
|
||||||
|
LinkedDef *savelist = NULL, *revlist = NULL, *newld;
|
||||||
struct saveList *newsl, *sl = (struct saveList *)NULL;
|
struct saveList *newsl, *sl = (struct saveList *)NULL;
|
||||||
|
|
||||||
while ((def = (CellDef *) StackPop(stack)))
|
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;
|
def->cd_client = (ClientData) 0;
|
||||||
if (!SigInterruptPending)
|
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 */
|
/* Replace any modified substrate planes and modified labels */
|
||||||
free_magic1_t mm1 = freeMagic1_init();
|
free_magic1_t mm1 = freeMagic1_init();
|
||||||
for (; sl; sl = sl->sl_next)
|
for (; sl; sl = sl->sl_next)
|
||||||
|
|
|
||||||
|
|
@ -614,6 +614,7 @@ termtop:
|
||||||
|
|
||||||
termdone:
|
termdone:
|
||||||
/* (continue) */
|
/* (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
|
/* Clean up---Put the ClientData entries in the tiles back to
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,17 @@ extSubtree(parentUse, reg, f)
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
/* If result == FALSE then ha.ha_interArea is invalid. */
|
/* If result == FALSE then ha.ha_interArea is invalid. */
|
||||||
ha.ha_interArea = rlab;
|
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;
|
result = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -779,6 +790,7 @@ extSubtreeFunc(scx, ha)
|
||||||
*/
|
*/
|
||||||
ha->ha_subArea = use->cu_bbox;
|
ha->ha_subArea = use->cu_bbox;
|
||||||
GEOCLIP(&ha->ha_subArea, &ha->ha_interArea);
|
GEOCLIP(&ha->ha_subArea, &ha->ha_interArea);
|
||||||
|
|
||||||
hy.hy_area = &ha->ha_subArea;
|
hy.hy_area = &ha->ha_subArea;
|
||||||
hy.hy_target = oneFlat->et_use;
|
hy.hy_target = oneFlat->et_use;
|
||||||
hy.hy_prefix = TRUE;
|
hy.hy_prefix = TRUE;
|
||||||
|
|
|
||||||
|
|
@ -1368,7 +1368,7 @@ ExtTechSimplePerimCap(argc, argv)
|
||||||
|
|
||||||
if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1376,9 +1376,14 @@ ExtTechSimplePerimCap(argc, argv)
|
||||||
TTMaskSetMask(allExtractTypes, &types);
|
TTMaskSetMask(allExtractTypes, &types);
|
||||||
plane1 = DBTechNoisyNamePlane(argv[2]);
|
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]);
|
||||||
TTMaskAndMask(¬types, &DBPlaneTypes[plane1]);
|
|
||||||
|
|
||||||
capVal = aToCap(argv[argc - 1]);
|
capVal = aToCap(argv[argc - 1]);
|
||||||
|
|
||||||
|
|
@ -1632,7 +1637,7 @@ ExtTechSimpleOverlapCap(argv)
|
||||||
|
|
||||||
if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1732,7 +1737,7 @@ ExtTechSimpleSideOverlapCap(argv)
|
||||||
|
|
||||||
if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1740,9 +1745,14 @@ ExtTechSimpleSideOverlapCap(argv)
|
||||||
TTMaskSetMask(allExtractTypes, &types);
|
TTMaskSetMask(allExtractTypes, &types);
|
||||||
plane1 = DBTechNoisyNamePlane(argv[2]);
|
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]);
|
||||||
TTMaskAndMask(¬types, &DBPlaneTypes[plane1]);
|
|
||||||
|
|
||||||
DBTechNoisyNameMask(argv[3], &ov);
|
DBTechNoisyNameMask(argv[3], &ov);
|
||||||
TTMaskSetMask(allExtractTypes, &ov);
|
TTMaskSetMask(allExtractTypes, &ov);
|
||||||
|
|
|
||||||
|
|
@ -68,13 +68,14 @@ extern const char * const extDevTable[];
|
||||||
#define EXT_DOADJUST 0x001 /* Extract hierarchical adjustments */
|
#define EXT_DOADJUST 0x001 /* Extract hierarchical adjustments */
|
||||||
#define EXT_DOCAPACITANCE 0x002 /* Extract capacitance */
|
#define EXT_DOCAPACITANCE 0x002 /* Extract capacitance */
|
||||||
#define EXT_DOCOUPLING 0x004 /* Extract coupling capacitance */
|
#define EXT_DOCOUPLING 0x004 /* Extract coupling capacitance */
|
||||||
#define EXT_DORESISTANCE 0x008 /* Extract resistance */
|
#define EXT_DORESISTANCE 0x008 /* Extract lumped resistance */
|
||||||
#define EXT_DOLENGTH 0x010 /* Extract pathlengths */
|
#define EXT_DOLENGTH 0x010 /* Extract pathlengths */
|
||||||
#define EXT_DOFRINGEHALO 0x020 /* Distributed fringe capacitance */
|
#define EXT_DOFRINGEHALO 0x020 /* Distributed fringe capacitance */
|
||||||
#define EXT_DOALL 0x03f /* ALL OF THE ABOVE */
|
#define EXT_DOALL 0x03f /* ALL OF THE ABOVE */
|
||||||
#define EXT_DOLABELCHECK 0x040 /* Check for connections by label */
|
#define EXT_DOLABELCHECK 0x040 /* Check for connections by label */
|
||||||
#define EXT_DOALIASES 0x080 /* Output all node aliases */
|
#define EXT_DOALIASES 0x080 /* Output all node aliases */
|
||||||
#define EXT_DOUNIQUE 0x100 /* Force unique nodes during extraction */
|
#define EXT_DOUNIQUE 0x100 /* Force unique nodes during extraction */
|
||||||
|
#define EXT_DOEXTRESIST 0x200 /* Do full R-C extraction */
|
||||||
|
|
||||||
extern int ExtOptions; /* Bitmask of above */
|
extern int ExtOptions; /* Bitmask of above */
|
||||||
extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */
|
extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */
|
||||||
|
|
@ -112,6 +113,8 @@ extern void ExtDumpCaps();
|
||||||
|
|
||||||
extern int extEnumTilePerim(Tile *tpIn, TileType dinfo, const TileTypeBitMask *maskp, int pNum, int (*func)(), ClientData cdata);
|
extern int extEnumTilePerim(Tile *tpIn, TileType dinfo, const TileTypeBitMask *maskp, int pNum, int (*func)(), ClientData cdata);
|
||||||
extern Plane *extPrepSubstrate();
|
extern Plane *extPrepSubstrate();
|
||||||
|
extern FILE *ExtFileOpen(CellDef *def, char *file, char *mode, char **prealfile);
|
||||||
|
|
||||||
|
|
||||||
/* C99 compat */
|
/* C99 compat */
|
||||||
extern void ExtAll();
|
extern void ExtAll();
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,7 @@ typedef struct nreg
|
||||||
* in X, then in Y.
|
* in X, then in Y.
|
||||||
*/
|
*/
|
||||||
LabelList *nreg_labels; /* See LabRegion for description */
|
LabelList *nreg_labels; /* See LabRegion for description */
|
||||||
|
ClientData nreg_subnet; /* Subnet record generated by extresist */
|
||||||
CapValue nreg_cap; /* Capacitance to ground */
|
CapValue nreg_cap; /* Capacitance to ground */
|
||||||
ResValue nreg_resist; /* Resistance estimate */
|
ResValue nreg_resist; /* Resistance estimate */
|
||||||
PerimArea nreg_pa[1]; /* Dummy; each node actually has
|
PerimArea nreg_pa[1]; /* Dummy; each node actually has
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "utils/hash.h"
|
#include "utils/hash.h"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@
|
||||||
#include "utils/main.h"
|
#include "utils/main.h"
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/malloc.h"
|
#include "utils/malloc.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
#include "tcltk/tclmagic.h"
|
#include "tcltk/tclmagic.h"
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@
|
||||||
#include "utils/main.h"
|
#include "utils/main.h"
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/malloc.h"
|
#include "utils/malloc.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
#include "tcltk/tclmagic.h"
|
#include "tcltk/tclmagic.h"
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@
|
||||||
#include "utils/main.h"
|
#include "utils/main.h"
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/malloc.h"
|
#include "utils/malloc.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
#include "tcltk/tclmagic.h"
|
#include "tcltk/tclmagic.h"
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "textio/txcommands.h"
|
#include "textio/txcommands.h"
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
|
|
||||||
|
|
@ -1359,15 +1359,21 @@ DefReadLocation(
|
||||||
|
|
||||||
if (use->cu_def->cd_flags & CDFIXEDBBOX)
|
if (use->cu_def->cd_flags & CDFIXEDBBOX)
|
||||||
{
|
{
|
||||||
char *propval;
|
PropertyRecord *proprec;
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
propval = (char *)DBPropGet(use->cu_def, "FIXED_BBOX", &found);
|
proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
if (sscanf(propval, "%d %d %d %d", &rect.r_xbot, &rect.r_ybot,
|
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||||
&rect.r_xtop, &rect.r_ytop) == 4)
|
(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 = ▭
|
r = ▭
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2453,7 +2459,7 @@ DefRead(
|
||||||
FILE *f;
|
FILE *f;
|
||||||
char *filename;
|
char *filename;
|
||||||
const char *token;
|
const char *token;
|
||||||
char *bboxstr;
|
PropertyRecord *proprec;
|
||||||
int keyword, dscale, total;
|
int keyword, dscale, total;
|
||||||
float oscale;
|
float oscale;
|
||||||
Rect *dierect;
|
Rect *dierect;
|
||||||
|
|
@ -2605,14 +2611,17 @@ DefRead(
|
||||||
break;
|
break;
|
||||||
case DEF_DIEAREA:
|
case DEF_DIEAREA:
|
||||||
dierect = LefReadRect(f, 0, oscale);
|
dierect = LefReadRect(f, 0, oscale);
|
||||||
bboxstr = mallocMagic(40);
|
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||||
sprintf(bboxstr, "%d %d %d %d",
|
2 * sizeof(int));
|
||||||
dierect->r_xbot,
|
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||||
dierect->r_ybot,
|
proprec->prop_len = 4;
|
||||||
dierect->r_xtop,
|
proprec->prop_value.prop_integer[0] = dierect->r_xbot;
|
||||||
dierect->r_ytop);
|
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);
|
if (rootDef == NULL) rootDef = DefNewCell(inName);
|
||||||
DBPropPut(rootDef, "FIXED_BBOX", bboxstr);
|
DBPropPut(rootDef, "FIXED_BBOX", proprec);
|
||||||
|
|
||||||
LefEndStatement(f);
|
LefEndStatement(f);
|
||||||
break;
|
break;
|
||||||
case DEF_PROPERTYDEFINITIONS:
|
case DEF_PROPERTYDEFINITIONS:
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ defWriteHeader(
|
||||||
float oscale,
|
float oscale,
|
||||||
int units) /* Units for UNITS; could be derived from oscale */
|
int units) /* Units for UNITS; could be derived from oscale */
|
||||||
{
|
{
|
||||||
char *propvalue;
|
PropertyRecord *proprec;
|
||||||
bool propfound;
|
bool propfound;
|
||||||
|
|
||||||
TxPrintf("Diagnostic: Write DEF header for cell %s\n", def->cd_name);
|
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, */
|
/* For DIEAREA, use the FIXED_BBOX property if present. Otherwise, */
|
||||||
/* use the extents of geometry (CellDef bounding box) */
|
/* use the extents of geometry (CellDef bounding box) */
|
||||||
|
|
||||||
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
|
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
{
|
{
|
||||||
Rect bbox;
|
Rect bbox;
|
||||||
|
|
||||||
/* Die area, taken from the declared FIXED_BBOX. */
|
/* Die area, taken from the declared FIXED_BBOX. */
|
||||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||||
&bbox.r_xtop, &bbox.r_ytop) == 4)
|
(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",
|
fprintf(f, " DIEAREA ( %.10g %.10g ) ( %.10g %.10g ) ;\n",
|
||||||
(float)bbox.r_xbot * oscale,
|
(float)bbox.r_xbot * oscale,
|
||||||
(float)bbox.r_ybot * oscale,
|
(float)bbox.r_ybot * oscale,
|
||||||
|
|
@ -2786,15 +2791,21 @@ arrayDefFunc(
|
||||||
|
|
||||||
if (use->cu_def->cd_flags & CDFIXEDBBOX)
|
if (use->cu_def->cd_flags & CDFIXEDBBOX)
|
||||||
{
|
{
|
||||||
char *propval;
|
PropertyRecord *proprec;
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
propval = (char *)DBPropGet(use->cu_def, "FIXED_BBOX", &found);
|
proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
if (sscanf(propval, "%d %d %d %d", &rect.r_xbot, &rect.r_ybot,
|
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||||
&rect.r_xtop, &rect.r_ytop) == 4)
|
(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 = ▭
|
r = ▭
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2844,15 +2855,20 @@ defComponentFunc(
|
||||||
xoff = yoff = 0;
|
xoff = yoff = 0;
|
||||||
if (cellUse->cu_def->cd_flags & CDFIXEDBBOX)
|
if (cellUse->cu_def->cd_flags & CDFIXEDBBOX)
|
||||||
{
|
{
|
||||||
char *propval;
|
PropertyRecord *proprec;
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
propval = (char *)DBPropGet(cellUse->cu_def, "FIXED_BBOX", &found);
|
proprec = DBPropGet(cellUse->cu_def, "FIXED_BBOX", &found);
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
if (sscanf(propval, "%d %d %d %d", &rect.r_xbot, &rect.r_ybot,
|
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||||
&rect.r_xtop, &rect.r_ytop) == 4)
|
(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 = ▭
|
r = ▭
|
||||||
GeoTransRect(&cellUse->cu_transform, &rect, &bbrect);
|
GeoTransRect(&cellUse->cu_transform, &rect, &bbrect);
|
||||||
GeoTransRect(&cellUse->cu_transform, &cellUse->cu_def->cd_bbox, &defrect);
|
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;
|
int keyword, pinNum, propsize, result;
|
||||||
float x, y;
|
float x, y;
|
||||||
bool has_size, is_imported = FALSE, propfound;
|
bool has_size, is_imported = FALSE, propfound;
|
||||||
|
PropertyRecord *proprec;
|
||||||
Rect lefBBox;
|
Rect lefBBox;
|
||||||
Point gdsOffset; /* Difference between GDS and LEF coordinates */
|
Point gdsOffset; /* Difference between GDS and LEF coordinates */
|
||||||
|
|
||||||
|
|
@ -2250,7 +2251,12 @@ LefReadMacro(
|
||||||
sprintf(tsave + strlen(tsave), " %s", token);
|
sprintf(tsave + strlen(tsave), " %s", token);
|
||||||
token = LefNextToken(f, TRUE);
|
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;
|
break;
|
||||||
case LEF_SIZE:
|
case LEF_SIZE:
|
||||||
token = LefNextToken(f, TRUE);
|
token = LefNextToken(f, TRUE);
|
||||||
|
|
@ -2294,7 +2300,12 @@ origin_error:
|
||||||
sprintf(tsave + strlen(tsave), " %s", token);
|
sprintf(tsave + strlen(tsave), " %s", token);
|
||||||
token = LefNextToken(f, TRUE);
|
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;
|
break;
|
||||||
case LEF_SOURCE:
|
case LEF_SOURCE:
|
||||||
token = LefNextToken(f, TRUE);
|
token = LefNextToken(f, TRUE);
|
||||||
|
|
@ -2305,12 +2316,19 @@ origin_error:
|
||||||
case LEF_SITE:
|
case LEF_SITE:
|
||||||
token = LefNextToken(f, TRUE);
|
token = LefNextToken(f, TRUE);
|
||||||
if (*token != '\n')
|
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);
|
LefEndStatement(f);
|
||||||
break;
|
break;
|
||||||
case LEF_PROPERTY:
|
case LEF_PROPERTY:
|
||||||
/* Append property key:value pairs to the cell property LEFproperties */
|
/* Append property key:value pairs to the cell property LEFproperties */
|
||||||
propval = (char *)DBPropGet(lefMacro, "LEFproperties", &propfound);
|
propval = DBPropGetString(lefMacro, "LEFproperties", &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
propsize = strlen(propval);
|
propsize = strlen(propval);
|
||||||
else
|
else
|
||||||
|
|
@ -2322,14 +2340,19 @@ origin_error:
|
||||||
char *propext;
|
char *propext;
|
||||||
sprintf(tsave, "%.127s", token);
|
sprintf(tsave, "%.127s", token);
|
||||||
token = LefNextToken(f, TRUE);
|
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);
|
LefEndStatement(f);
|
||||||
break;
|
break;
|
||||||
|
|
@ -2405,11 +2428,16 @@ foreign_error:
|
||||||
if (has_size)
|
if (has_size)
|
||||||
{
|
{
|
||||||
lefMacro->cd_flags |= CDFIXEDBBOX;
|
lefMacro->cd_flags |= CDFIXEDBBOX;
|
||||||
propval = (char *)mallocMagic(40);
|
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||||
sprintf(propval, "%d %d %d %d",
|
(2 * sizeof(int)));
|
||||||
lefBBox.r_xbot, lefBBox.r_ybot,
|
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||||
lefBBox.r_xtop, lefBBox.r_ytop);
|
proprec->prop_len = 4;
|
||||||
DBPropPut(lefMacro, "FIXED_BBOX", propval);
|
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
|
else
|
||||||
|
|
@ -2419,11 +2447,16 @@ foreign_error:
|
||||||
if (has_size)
|
if (has_size)
|
||||||
{
|
{
|
||||||
lefMacro->cd_flags |= CDFIXEDBBOX;
|
lefMacro->cd_flags |= CDFIXEDBBOX;
|
||||||
propval = (char *)mallocMagic(40);
|
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||||
sprintf(propval, "%d %d %d %d",
|
(2 * sizeof(int)));
|
||||||
lefBBox.r_xbot, lefBBox.r_ybot,
|
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||||
lefBBox.r_xtop, lefBBox.r_ytop);
|
proprec->prop_len = 4;
|
||||||
DBPropPut(lefMacro, "FIXED_BBOX", propval);
|
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
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -2432,13 +2465,17 @@ foreign_error:
|
||||||
|
|
||||||
/* Set the placement bounding box property to the current bounding box */
|
/* Set the placement bounding box property to the current bounding box */
|
||||||
lefMacro->cd_flags |= CDFIXEDBBOX;
|
lefMacro->cd_flags |= CDFIXEDBBOX;
|
||||||
propval = (char *)mallocMagic(40);
|
lefMacro->cd_flags |= CDFIXEDBBOX;
|
||||||
sprintf(propval, "%d %d %d %d",
|
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||||
lefMacro->cd_bbox.r_xbot,
|
(2 * sizeof(int)));
|
||||||
lefMacro->cd_bbox.r_ybot,
|
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||||
lefMacro->cd_bbox.r_xtop,
|
proprec->prop_len = 4;
|
||||||
lefMacro->cd_bbox.r_ytop);
|
proprec->prop_value.prop_integer[0] = lefMacro->cd_bbox.r_xbot;
|
||||||
DBPropPut(lefMacro, "FIXED_BBOX", propval);
|
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);
|
DRCCheckThis(lefMacro, TT_CHECKPAINT, &lefMacro->cd_bbox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2453,7 +2490,13 @@ foreign_error:
|
||||||
/* i.e., setting it to "FALSE" would be ineffective. */
|
/* i.e., setting it to "FALSE" would be ineffective. */
|
||||||
|
|
||||||
if (!is_imported)
|
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,
|
DBWAreaChanged(lefMacro, &lefMacro->cd_bbox, DBW_ALLWINDOWS,
|
||||||
&DBAllButSpaceBits);
|
&DBAllButSpaceBits);
|
||||||
|
|
|
||||||
|
|
@ -328,14 +328,14 @@ lefWriteHeader(
|
||||||
{
|
{
|
||||||
fprintf(f, "SITE %s\n", siteDef->cd_name);
|
fprintf(f, "SITE %s\n", siteDef->cd_name);
|
||||||
|
|
||||||
propvalue = (char *)DBPropGet(siteDef, "LEFsymmetry", &propfound);
|
propvalue = DBPropGetString(siteDef, "LEFsymmetry", &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
fprintf(f, IN0 "SYMMETRY %s ;\n", propvalue);
|
fprintf(f, IN0 "SYMMETRY %s ;\n", propvalue);
|
||||||
else
|
else
|
||||||
/* Usually core cells have symmetry Y only. */
|
/* Usually core cells have symmetry Y only. */
|
||||||
fprintf(f, IN0 "SYMMETRY Y ;\n");
|
fprintf(f, IN0 "SYMMETRY Y ;\n");
|
||||||
|
|
||||||
propvalue = (char *)DBPropGet(siteDef, "LEFclass", &propfound);
|
propvalue = DBPropGetString(siteDef, "LEFclass", &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
fprintf(f, IN0 "CLASS %s ;\n", propvalue);
|
fprintf(f, IN0 "CLASS %s ;\n", propvalue);
|
||||||
else
|
else
|
||||||
|
|
@ -345,10 +345,20 @@ lefWriteHeader(
|
||||||
boundary = siteDef->cd_bbox;
|
boundary = siteDef->cd_bbox;
|
||||||
if (siteDef->cd_flags & CDFIXEDBBOX)
|
if (siteDef->cd_flags & CDFIXEDBBOX)
|
||||||
{
|
{
|
||||||
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
|
PropertyRecord *proprec;
|
||||||
|
|
||||||
|
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
|
||||||
if (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 */
|
scale = CIFGetOutputScale(1000); /* conversion to microns */
|
||||||
|
|
@ -1288,7 +1298,7 @@ lefWriteMacro(
|
||||||
/* default values are optional, so in this case we will leave those */
|
/* default values are optional, so in this case we will leave those */
|
||||||
/* entries blank. */
|
/* entries blank. */
|
||||||
|
|
||||||
propvalue = (char *)DBPropGet(def, "LEFclass", &propfound);
|
propvalue = DBPropGetString(def, "LEFclass", &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
{
|
{
|
||||||
fprintf(f, IN0 "CLASS %s ;\n", propvalue);
|
fprintf(f, IN0 "CLASS %s ;\n", propvalue);
|
||||||
|
|
@ -1324,13 +1334,21 @@ lefWriteMacro(
|
||||||
|
|
||||||
if (def->cd_flags & CDFIXEDBBOX)
|
if (def->cd_flags & CDFIXEDBBOX)
|
||||||
{
|
{
|
||||||
char *propvalue;
|
PropertyRecord *proprec;
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &found);
|
proprec = DBPropGet(def, "FIXED_BBOX", &found);
|
||||||
if (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 */
|
/* Check if (boundry less setback) is degenerate. If so, then */
|
||||||
|
|
@ -1358,11 +1376,11 @@ lefWriteMacro(
|
||||||
lc.origin.p_x = 0;
|
lc.origin.p_x = 0;
|
||||||
lc.origin.p_y = 0;
|
lc.origin.p_y = 0;
|
||||||
|
|
||||||
propvalue = (char *)DBPropGet(def, "LEFsymmetry", &propfound);
|
propvalue = DBPropGetString(def, "LEFsymmetry", &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
fprintf(f, IN0 "SYMMETRY %s ;\n", propvalue);
|
fprintf(f, IN0 "SYMMETRY %s ;\n", propvalue);
|
||||||
|
|
||||||
propvalue = (char *)DBPropGet(def, "LEFsite", &propfound);
|
propvalue = DBPropGetString(def, "LEFsite", &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
fprintf(f, IN0 "SITE %s ;\n", propvalue);
|
fprintf(f, IN0 "SITE %s ;\n", propvalue);
|
||||||
|
|
||||||
|
|
@ -1821,20 +1839,24 @@ lefWriteMacro(
|
||||||
Rect layerBound, manualBound;
|
Rect layerBound, manualBound;
|
||||||
labelLinkedList *thislll;
|
labelLinkedList *thislll;
|
||||||
bool propfound;
|
bool propfound;
|
||||||
char *propvalue;
|
PropertyRecord *proprec;
|
||||||
|
|
||||||
/* If there is a property OBS_BBOX, then use the value of the */
|
/* If there is a property OBS_BBOX, then use the value of the */
|
||||||
/* defined box to set the minimum hidden area. This will still */
|
/* defined box to set the minimum hidden area. This will still */
|
||||||
/* get clipped to the setback. */
|
/* get clipped to the setback. */
|
||||||
|
|
||||||
propvalue = (char *)DBPropGet(def, "OBS_BBOX", &propfound);
|
proprec = DBPropGet(def, "OBS_BBOX", &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
{
|
{
|
||||||
if (sscanf(propvalue, "%d %d %d %d",
|
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
|
||||||
&(manualBound.r_xbot),
|
(proprec->prop_len == 4))
|
||||||
&(manualBound.r_ybot),
|
{
|
||||||
&(manualBound.r_xtop),
|
manualBound.r_xbot = proprec->prop_value.prop_integer[0];
|
||||||
&(manualBound.r_ytop)) != 4)
|
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 "
|
TxError("Improper values for obstruction bounding box "
|
||||||
"OBS_BBOX property");
|
"OBS_BBOX property");
|
||||||
|
|
@ -2016,7 +2038,7 @@ lefWriteMacro(
|
||||||
|
|
||||||
/* If there are any properties saved in LEFproperties, write them out */
|
/* If there are any properties saved in LEFproperties, write them out */
|
||||||
|
|
||||||
propvalue = (char *)DBPropGet(def, "LEFproperties", &propfound);
|
propvalue = DBPropGetString(def, "LEFproperties", &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
{
|
{
|
||||||
char *delim;
|
char *delim;
|
||||||
|
|
@ -2094,7 +2116,7 @@ lefGetSites(
|
||||||
bool propfound;
|
bool propfound;
|
||||||
char *propvalue;
|
char *propvalue;
|
||||||
|
|
||||||
propvalue = (char *)DBPropGet(def, "LEFsite", &propfound);
|
propvalue = DBPropGetString(def, "LEFsite", &propfound);
|
||||||
if (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?) */
|
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;
|
bool propfound;
|
||||||
char *propvalue;
|
char *propvalue;
|
||||||
|
|
||||||
propvalue = (char *)DBPropGet(def, "LEFproperties", &propfound);
|
propvalue = DBPropGetString(def, "LEFproperties", &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
{
|
{
|
||||||
char *key;
|
char *key;
|
||||||
|
|
|
||||||
|
|
@ -120,61 +120,61 @@ macro Control_XK_space "tool wiring"
|
||||||
# Arrow keys (X11 versions only)
|
# Arrow keys (X11 versions only)
|
||||||
macro XK_Left "scroll l .1 w"
|
macro XK_Left "scroll l .1 w"
|
||||||
macro Shift_XK_Left "scroll l 1 w"
|
macro Shift_XK_Left "scroll l 1 w"
|
||||||
macro Control_XK_Left "box grow w 1"
|
macro Control_XK_Left "box grow w 1i"
|
||||||
macro Control_Shift_XK_Left "box shrink e 1"
|
macro Control_Shift_XK_Left "box shrink e 1i"
|
||||||
macro XK_Right "scroll r .1 w"
|
macro XK_Right "scroll r .1 w"
|
||||||
macro Shift_XK_Right "scroll r 1 w"
|
macro Shift_XK_Right "scroll r 1 w"
|
||||||
macro Control_XK_Right "box grow e 1"
|
macro Control_XK_Right "box grow e 1i"
|
||||||
macro Control_Shift_XK_Right "box shrink w 1"
|
macro Control_Shift_XK_Right "box shrink w 1i"
|
||||||
macro XK_Up "scroll u .1 w"
|
macro XK_Up "scroll u .1 w"
|
||||||
macro Shift_XK_Up "scroll u 1 w"
|
macro Shift_XK_Up "scroll u 1 w"
|
||||||
macro Control_XK_Up "box grow n 1"
|
macro Control_XK_Up "box grow n 1i"
|
||||||
macro Control_Shift_XK_Up "box shrink s 1"
|
macro Control_Shift_XK_Up "box shrink s 1i"
|
||||||
macro XK_Down "scroll d .1 w"
|
macro XK_Down "scroll d .1 w"
|
||||||
macro Shift_XK_Down "scroll d 1 w"
|
macro Shift_XK_Down "scroll d 1 w"
|
||||||
macro Control_XK_Down "box grow s 1"
|
macro Control_XK_Down "box grow s 1i"
|
||||||
macro Control_Shift_XK_Down "box shrink n 1"
|
macro Control_Shift_XK_Down "box shrink n 1i"
|
||||||
# Keypad keys (X11 versions only)
|
# Keypad keys (X11 versions only)
|
||||||
# Functions duplicated for use both with Num_Lock ON and OFF
|
# Functions duplicated for use both with Num_Lock ON and OFF
|
||||||
macro XK_KP_Delete "box size 0 0"
|
macro XK_KP_Delete "box size 0 0"
|
||||||
macro XK_KP_Insert "box size 4 4"
|
macro XK_KP_Insert "box size 4l 4l"
|
||||||
macro XK_KP_0 "box size 7 2"
|
macro XK_KP_0 "box size 7l 2l"
|
||||||
macro Shift_XK_KP_0 "box size 7 2"
|
macro Shift_XK_KP_0 "box size 7l 2l"
|
||||||
macro XK_0 "box size 7 2"
|
macro XK_0 "box size 7l 2l"
|
||||||
macro Control_XK_KP_0 "box size 2 7"
|
macro Control_XK_KP_0 "box size 2l 7l"
|
||||||
macro Control_XK_KP_Insert "box size 2 7"
|
macro Control_XK_KP_Insert "box size 2l 7l"
|
||||||
macro XK_KP_End "move sw 1"
|
macro XK_KP_End "move sw 1i"
|
||||||
macro XK_KP_Down "move d 1"
|
macro XK_KP_Down "move d 1i"
|
||||||
macro XK_KP_2 "stretch d 1"
|
macro XK_KP_2 "stretch d 1i"
|
||||||
macro Shift_XK_KP_2 "stretch d 1"
|
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 Control_XK_KP_Down "stretch d 1i"
|
||||||
macro XK_2 "stretch d 1"
|
macro XK_2 "stretch d 1i"
|
||||||
macro XK_KP_Next "move se 1"
|
macro XK_KP_Next "move se 1i"
|
||||||
macro XK_KP_Left "move l 1"
|
macro XK_KP_Left "move l 1i"
|
||||||
macro XK_KP_4 "stretch l 1"
|
macro XK_KP_4 "stretch l 1i"
|
||||||
macro Shift_XK_KP_4 "stretch l 1"
|
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 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_Begin "findbox zoom"
|
||||||
macro XK_KP_5 "findbox"
|
macro XK_KP_5 "findbox"
|
||||||
macro Shift_XK_KP_5 "findbox"
|
macro Shift_XK_KP_5 "findbox"
|
||||||
macro XK_5 "findbox"
|
macro XK_5 "findbox"
|
||||||
macro XK_KP_Right "move r 1"
|
macro XK_KP_Right "move r 1i"
|
||||||
macro XK_KP_6 "stretch r 1"
|
macro XK_KP_6 "stretch r 1i"
|
||||||
macro Shift_XK_KP_6 "stretch r 1"
|
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 Control_XK_KP_Right "stretch r 1i"
|
||||||
macro XK_6 "stretch r 1"
|
macro XK_6 "stretch r 1i"
|
||||||
macro XK_KP_Home "move nw 1"
|
macro XK_KP_Home "move nw 1i"
|
||||||
macro XK_KP_Up "move u 1"
|
macro XK_KP_Up "move u 1i"
|
||||||
macro XK_KP_8 "stretch u 1"
|
macro XK_KP_8 "stretch u 1i"
|
||||||
macro Shift_XK_KP_8 "stretch u 1"
|
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 Control_XK_KP_Up "stretch u 1i"
|
||||||
macro XK_8 "stretch u 1"
|
macro XK_8 "stretch u 1i"
|
||||||
macro XK_KP_Prior "move ne 1"
|
macro XK_KP_Prior "move ne 1i"
|
||||||
# Scroll wheel bindings
|
# Scroll wheel bindings
|
||||||
macro XK_Pointer_Button4 "scroll u .05 w"
|
macro XK_Pointer_Button4 "scroll u .05 w"
|
||||||
macro XK_Pointer_Button5 "scroll d .05 w"
|
macro XK_Pointer_Button5 "scroll d .05 w"
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,8 @@ MAGIC_8.0 {
|
||||||
DBPlaneTypes;
|
DBPlaneTypes;
|
||||||
DBPrintUseId;
|
DBPrintUseId;
|
||||||
DBPropGet;
|
DBPropGet;
|
||||||
|
DBPropGetString;
|
||||||
|
DBPropGetDouble;
|
||||||
DBPutLabel;
|
DBPutLabel;
|
||||||
DBReComputeBbox;
|
DBReComputeBbox;
|
||||||
DBSeeTypesAll;
|
DBSeeTypesAll;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
MODULE = resis
|
MODULE = resis
|
||||||
MAGICDIR = ..
|
MAGICDIR = ..
|
||||||
SRCS = ResMain.c ResJunct.c ResMakeRes.c ResSimple.c ResPrint.c \
|
SRCS = ResMain.c ResJunct.c ResMakeRes.c ResSimple.c ResPrint.c \
|
||||||
ResReadSim.c ResRex.c ResBasic.c ResMerge.c ResChecks.c \
|
ResReadExt.c ResRex.c ResBasic.c ResMerge.c ResChecks.c \
|
||||||
ResFract.c ResUtils.c ResDebug.c
|
ResFract.c ResUtils.c ResDebug.c
|
||||||
|
|
||||||
include ${MAGICDIR}/defs.mak
|
include ${MAGICDIR}/defs.mak
|
||||||
|
|
|
||||||
|
|
@ -46,22 +46,22 @@ resNodeIsPort(node, x, y, tile)
|
||||||
Rect *rect;
|
Rect *rect;
|
||||||
Point p;
|
Point p;
|
||||||
resPort *pl, *lp;
|
resPort *pl, *lp;
|
||||||
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
|
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||||
|
|
||||||
p.p_x = x;
|
p.p_x = x;
|
||||||
p.p_y = y;
|
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);
|
rect = &(pl->rp_bbox);
|
||||||
if (GEO_ENCLOSE(&p, rect))
|
if (GEO_ENCLOSE(&p, rect))
|
||||||
{
|
{
|
||||||
node->rn_name = pl->rp_nodename;
|
node->rn_name = pl->rp_nodename;
|
||||||
if (junk->portList == pl)
|
if (info->portList == pl)
|
||||||
junk->portList = pl->rp_nextPort;
|
info->portList = pl->rp_nextPort;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (lp = junk->portList; lp && (lp->rp_nextPort != pl);
|
for (lp = info->portList; lp && (lp->rp_nextPort != pl);
|
||||||
lp = lp->rp_nextPort);
|
lp = lp->rp_nextPort);
|
||||||
lp->rp_nextPort = pl->rp_nextPort;
|
lp->rp_nextPort = pl->rp_nextPort;
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +77,8 @@ resNodeIsPort(node, x, y, tile)
|
||||||
* resAllPortNodes --
|
* resAllPortNodes --
|
||||||
*
|
*
|
||||||
* Generate new nodes and breakpoints for every unused port declared
|
* 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;
|
int x, y;
|
||||||
resNode *resptr;
|
resNode *resptr;
|
||||||
resPort *pl;
|
resPort *pl;
|
||||||
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
|
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||||
|
|
||||||
free_magic1_t mm1 = freeMagic1_init();
|
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;
|
x = pl->rp_loc.p_x;
|
||||||
y = pl->rp_loc.p_y;
|
y = pl->rp_loc.p_y;
|
||||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
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_status = TRUE;
|
||||||
resptr->rn_noderes = 0;
|
resptr->rn_noderes = 0;
|
||||||
resptr->rn_name = pl->rp_nodename;
|
resptr->rn_name = pl->rp_nodename;
|
||||||
|
|
@ -225,7 +226,7 @@ ResEachTile(tile, startpoint)
|
||||||
int xj, yj, i;
|
int xj, yj, i;
|
||||||
bool merged;
|
bool merged;
|
||||||
tElement *tcell;
|
tElement *tcell;
|
||||||
tileJunk *tstructs= (tileJunk *)TiGetClientPTR(tile);
|
resInfo *tstructs= (resInfo *)TiGetClientPTR(tile);
|
||||||
ExtDevice *devptr;
|
ExtDevice *devptr;
|
||||||
int sides;
|
int sides;
|
||||||
|
|
||||||
|
|
@ -262,7 +263,7 @@ ResEachTile(tile, startpoint)
|
||||||
int x = startpoint->p_x;
|
int x = startpoint->p_x;
|
||||||
int y = startpoint->p_y;
|
int y = startpoint->p_y;
|
||||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
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_status = TRUE;
|
||||||
resptr->rn_noderes = 0;
|
resptr->rn_noderes = 0;
|
||||||
ResAddToQueue(resptr, &ResNodeQueue);
|
ResAddToQueue(resptr, &ResNodeQueue);
|
||||||
|
|
@ -278,7 +279,7 @@ ResEachTile(tile, startpoint)
|
||||||
* for single tile device, but not as good for multiple ones.
|
* 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)
|
if (tstructs->deviceList->rd_fet_gate == NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -291,7 +292,7 @@ ResEachTile(tile, startpoint)
|
||||||
tcell->te_thist = tstructs->deviceList;
|
tcell->te_thist = tstructs->deviceList;
|
||||||
tcell->te_nextt = NULL;
|
tcell->te_nextt = NULL;
|
||||||
|
|
||||||
InitializeNode(resptr, x, y, RES_NODE_JUNCTION);
|
InitializeResNode(resptr, x, y, RES_NODE_JUNCTION);
|
||||||
resptr->rn_te = tcell;
|
resptr->rn_te = tcell;
|
||||||
ResAddToQueue(resptr, &ResNodeQueue);
|
ResAddToQueue(resptr, &ResNodeQueue);
|
||||||
resNodeIsPort(resptr, x, y, tile);
|
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);
|
resAllPortNodes(tile, &ResNodeQueue);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ ResSanityChecks(nodename, resistorList, nodeList, devlist)
|
||||||
for (node = nodeList; node != NULL; node=node->rn_more)
|
for (node = nodeList; node != NULL; node=node->rn_more)
|
||||||
{
|
{
|
||||||
node->rn_status &= ~RES_REACHED_NODE;
|
node->rn_status &= ~RES_REACHED_NODE;
|
||||||
if (node->rn_why == RES_NODE_ORIGIN)
|
if (node->rn_why & RES_NODE_ORIGIN)
|
||||||
STACKPUSH((ClientData) node, resSanityStack);
|
STACKPUSH((ClientData) node, resSanityStack);
|
||||||
}
|
}
|
||||||
for (resistor = resistorList; resistor != NULL; resistor = resistor->rr_nextResistor)
|
for (resistor = resistorList; resistor != NULL; resistor = resistor->rr_nextResistor)
|
||||||
|
|
@ -112,7 +112,6 @@ ResSanityChecks(nodename, resistorList, nodeList, devlist)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (dev->rd_status & RES_DEV_PLUG) continue;
|
|
||||||
reached = FALSE;
|
reached = FALSE;
|
||||||
for (i = 0; i != dev->rd_nterms; i++)
|
for (i = 0; i != dev->rd_nterms; i++)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,6 @@ ResPrintDeviceList(fp, list)
|
||||||
int i;
|
int i;
|
||||||
for (; list != NULL; list = list->rd_nextDev)
|
for (; list != NULL; list = list->rd_nextDev)
|
||||||
{
|
{
|
||||||
if (list->rd_status & RES_DEV_PLUG) continue;
|
|
||||||
if (fp == stdout)
|
if (fp == stdout)
|
||||||
TxPrintf("t w %d l %d ", list->rd_width, list->rd_length);
|
TxPrintf("t w %d l %d ", list->rd_width, list->rd_length);
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
||||||
resDevice *resDev;
|
resDevice *resDev;
|
||||||
tElement *tcell;
|
tElement *tcell;
|
||||||
int newnode;
|
int newnode;
|
||||||
tileJunk *j;
|
resInfo *ri;
|
||||||
|
|
||||||
newnode = FALSE;
|
newnode = FALSE;
|
||||||
|
|
||||||
|
|
@ -62,9 +62,9 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
||||||
*/
|
*/
|
||||||
if (TiGetClient(tp) == CLIENTDEFAULT) return;
|
if (TiGetClient(tp) == CLIENTDEFAULT) return;
|
||||||
|
|
||||||
j = (tileJunk *) TiGetClientPTR(tp);
|
ri = (resInfo *) TiGetClientPTR(tp);
|
||||||
resDev = j->deviceList;
|
resDev = ri->deviceList;
|
||||||
if ((j->sourceEdge & direction) != 0)
|
if ((ri->sourceEdge & direction) != 0)
|
||||||
{
|
{
|
||||||
if (resDev->rd_fet_source == (resNode *) NULL)
|
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 = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
|
||||||
tcell->te_nextt = NULL;
|
tcell->te_nextt = NULL;
|
||||||
tcell->te_thist = j->deviceList;
|
tcell->te_thist = ri->deviceList;
|
||||||
InitializeNode(resptr, xj, yj, RES_NODE_DEVICE);
|
InitializeResNode(resptr, xj, yj, RES_NODE_DEVICE);
|
||||||
resptr->rn_te = tcell;
|
resptr->rn_te = tcell;
|
||||||
ResAddToQueue(resptr, PendingList);
|
ResAddToQueue(resptr, PendingList);
|
||||||
}
|
}
|
||||||
|
|
@ -125,11 +125,11 @@ ResNewSubDevice(tile, tp, xj, yj, direction, PendingList)
|
||||||
resDevice *resDev;
|
resDevice *resDev;
|
||||||
tElement *tcell;
|
tElement *tcell;
|
||||||
int newnode;
|
int newnode;
|
||||||
tileJunk *j;
|
resInfo *ri;
|
||||||
|
|
||||||
newnode = FALSE;
|
newnode = FALSE;
|
||||||
j = (tileJunk *) TiGetClientPTR(tp);
|
ri = (resInfo *) TiGetClientPTR(tp);
|
||||||
resDev = j->deviceList;
|
resDev = ri->deviceList;
|
||||||
|
|
||||||
/* Arrived at a device that has a terminal connected to substrate */
|
/* Arrived at a device that has a terminal connected to substrate */
|
||||||
/* that is not a FET bulk terminal (e.g., varactor, diode). */
|
/* 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 = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
|
||||||
tcell->te_nextt = NULL;
|
tcell->te_nextt = NULL;
|
||||||
tcell->te_thist = j->deviceList;
|
tcell->te_thist = ri->deviceList;
|
||||||
InitializeNode(resptr, xj, yj, RES_NODE_DEVICE);
|
InitializeResNode(resptr, xj, yj, RES_NODE_DEVICE);
|
||||||
resptr->rn_te = tcell;
|
resptr->rn_te = tcell;
|
||||||
ResAddToQueue(resptr, PendingList);
|
ResAddToQueue(resptr, PendingList);
|
||||||
}
|
}
|
||||||
|
|
@ -181,8 +181,8 @@ ResProcessJunction(tile, tp, xj, yj, NodeList)
|
||||||
ResJunction *junction;
|
ResJunction *junction;
|
||||||
resNode *resptr;
|
resNode *resptr;
|
||||||
jElement *jcell;
|
jElement *jcell;
|
||||||
tileJunk *j0 = (tileJunk *)TiGetClientPTR(tile);
|
resInfo *ri0 = (resInfo *)TiGetClientPTR(tile);
|
||||||
tileJunk *j2 = (tileJunk *)TiGetClientPTR(tp);
|
resInfo *ri2 = (resInfo *)TiGetClientPTR(tp);
|
||||||
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
if (tile == tp)
|
if (tile == tp)
|
||||||
|
|
@ -191,12 +191,12 @@ ResProcessJunction(tile, tp, xj, yj, NodeList)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (j2->tj_status & RES_TILE_DONE) return;
|
if (ri2->ri_status & RES_TILE_DONE) return;
|
||||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
||||||
resptr->rn_te = (tElement *) NULL;
|
resptr->rn_te = (tElement *) NULL;
|
||||||
junction = (ResJunction *) mallocMagic((unsigned)(sizeof(ResJunction)));
|
junction = (ResJunction *) mallocMagic((unsigned)(sizeof(ResJunction)));
|
||||||
jcell = (jElement *) mallocMagic((unsigned)(sizeof(jElement)));
|
jcell = (jElement *) mallocMagic((unsigned)(sizeof(jElement)));
|
||||||
InitializeNode(resptr, xj, yj, RES_NODE_JUNCTION);
|
InitializeResNode(resptr, xj, yj, RES_NODE_JUNCTION);
|
||||||
resptr->rn_je = jcell;
|
resptr->rn_je = jcell;
|
||||||
ResAddToQueue(resptr, NodeList);
|
ResAddToQueue(resptr, NodeList);
|
||||||
|
|
||||||
|
|
@ -208,10 +208,10 @@ ResProcessJunction(tile, tp, xj, yj, NodeList)
|
||||||
junction->rj_Tile[1] = tp;
|
junction->rj_Tile[1] = tp;
|
||||||
junction->rj_loc.p_x =xj;
|
junction->rj_loc.p_x =xj;
|
||||||
junction->rj_loc.p_y =yj;
|
junction->rj_loc.p_y =yj;
|
||||||
junction->rj_nextjunction[0] = j0->junctionList;
|
junction->rj_nextjunction[0] = ri0->junctionList;
|
||||||
j0->junctionList = junction;
|
ri0->junctionList = junction;
|
||||||
junction->rj_nextjunction[1] = j2->junctionList;
|
junction->rj_nextjunction[1] = ri2->junctionList;
|
||||||
j2->junctionList = junction;
|
ri2->junctionList = junction;
|
||||||
|
|
||||||
NEWBREAK(junction->rj_jnode,tile, junction->rj_loc.p_x,
|
NEWBREAK(junction->rj_jnode,tile, junction->rj_loc.p_x,
|
||||||
junction->rj_loc.p_y, NULL);
|
junction->rj_loc.p_y, NULL);
|
||||||
|
|
|
||||||
303
resis/ResMain.c
303
resis/ResMain.c
|
|
@ -35,13 +35,12 @@ resNode *ResNodeList = NULL; /* Processed Nodes */
|
||||||
resDevice *ResDevList = NULL; /* Devices */
|
resDevice *ResDevList = NULL; /* Devices */
|
||||||
ResContactPoint *ResContactList = NULL; /* Contacts */
|
ResContactPoint *ResContactList = NULL; /* Contacts */
|
||||||
resNode *ResNodeQueue = NULL; /* Pending nodes */
|
resNode *ResNodeQueue = NULL; /* Pending nodes */
|
||||||
resNode *ResOriginNode = NULL; /* node where R=0 */
|
resNode *ResNodeAtOrigin = NULL; /* node where R=0 */
|
||||||
resNode *resCurrentNode;
|
resNode *resCurrentNode;
|
||||||
int ResTileCount = 0; /* Number of tiles rn_status */
|
int ResTileCount = 0; /* Number of tiles rn_status */
|
||||||
extern ExtRegion *ResFirst();
|
extern ExtRegion *ResFirst();
|
||||||
extern Tile *FindStartTile();
|
extern Tile *FindStartTile();
|
||||||
extern int ResEachTile();
|
extern int ResEachTile();
|
||||||
extern ResSimNode *ResInitializeNode();
|
|
||||||
TileTypeBitMask ResSDTypesBitMask;
|
TileTypeBitMask ResSDTypesBitMask;
|
||||||
TileTypeBitMask ResSubTypesBitMask;
|
TileTypeBitMask ResSubTypesBitMask;
|
||||||
|
|
||||||
|
|
@ -184,7 +183,7 @@ ResDissolveContacts(contacts)
|
||||||
* ResMakePortBreakpoints --
|
* ResMakePortBreakpoints --
|
||||||
*
|
*
|
||||||
* Search for nodes which are ports, and force them to be breakpoints
|
* 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
|
* ensures that connected nodes that stretch between two ports will
|
||||||
* not be assumed to be "hanging" nodes.
|
* not be assumed to be "hanging" nodes.
|
||||||
*
|
*
|
||||||
|
|
@ -201,13 +200,13 @@ ResMakePortBreakpoints(def)
|
||||||
TileTypeBitMask mask;
|
TileTypeBitMask mask;
|
||||||
HashSearch hs;
|
HashSearch hs;
|
||||||
HashEntry *entry;
|
HashEntry *entry;
|
||||||
ResSimNode *node;
|
ResExtNode *node;
|
||||||
int ResAddBreakpointFunc(); /* Forward Declaration */
|
int ResAddBreakpointFunc(); /* Forward Declaration */
|
||||||
|
|
||||||
HashStartSearch(&hs);
|
HashStartSearch(&hs);
|
||||||
while((entry = HashNext(&ResNodeTable,&hs)) != NULL)
|
while((entry = HashNext(&ResNodeTable, &hs)) != NULL)
|
||||||
{
|
{
|
||||||
node = (ResSimNode *)HashGetValue(entry);
|
node = (ResExtNode *)HashGetValue(entry);
|
||||||
if (node->status & PORTNODE)
|
if (node->status & PORTNODE)
|
||||||
{
|
{
|
||||||
if (node->rs_ttype <= 0)
|
if (node->rs_ttype <= 0)
|
||||||
|
|
@ -266,22 +265,22 @@ ResMakePortBreakpoints(def)
|
||||||
* ResMakeLabelBreakpoints --
|
* ResMakeLabelBreakpoints --
|
||||||
*
|
*
|
||||||
* Search for labels that are part of a node, and force them to be
|
* 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
|
* ResUse. This ensures (among other things) that pins of a top level
|
||||||
* cell will be retained and become the endpoint of a net.
|
* cell will be retained and become the endpoint of a net.
|
||||||
*
|
*
|
||||||
*----------------------------------------------------------------------------
|
*----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ResMakeLabelBreakpoints(def, goodies)
|
ResMakeLabelBreakpoints(def, resisdata)
|
||||||
CellDef *def;
|
CellDef *def;
|
||||||
ResGlobalParams *goodies;
|
ResisData *resisdata;
|
||||||
{
|
{
|
||||||
Plane *plane;
|
Plane *plane;
|
||||||
Rect *rect;
|
Rect *rect;
|
||||||
TileTypeBitMask mask;
|
TileTypeBitMask mask;
|
||||||
HashEntry *entry;
|
HashEntry *entry;
|
||||||
ResSimNode *node;
|
ResExtNode *node;
|
||||||
Label *slab;
|
Label *slab;
|
||||||
int ResAddBreakpointFunc(); /* Forward Declaration */
|
int ResAddBreakpointFunc(); /* Forward Declaration */
|
||||||
|
|
||||||
|
|
@ -292,14 +291,14 @@ ResMakeLabelBreakpoints(def, goodies)
|
||||||
if (*(slab->lab_text) == '\0') continue;
|
if (*(slab->lab_text) == '\0') continue;
|
||||||
|
|
||||||
entry = HashFind(&ResNodeTable, slab->lab_text);
|
entry = HashFind(&ResNodeTable, slab->lab_text);
|
||||||
node = ResInitializeNode(entry);
|
node = ResExtInitNode(entry);
|
||||||
|
|
||||||
/* If the drivepoint position changes and the drivepoint is */
|
/* If the drivepoint position changes and the drivepoint is */
|
||||||
/* in the "goodies" record, then make sure the tile type in */
|
/* in the "resisdata" record, then make sure the tile type */
|
||||||
/* "goodies" gets changed to match. */
|
/* in "resisdata" gets changed to match. */
|
||||||
|
|
||||||
if (goodies->rg_devloc == &node->drivepoint)
|
if (resisdata->rg_devloc == &node->drivepoint)
|
||||||
goodies->rg_ttype = slab->lab_type;
|
resisdata->rg_ttype = slab->lab_type;
|
||||||
|
|
||||||
node->drivepoint = slab->lab_rect.r_ll;
|
node->drivepoint = slab->lab_rect.r_ll;
|
||||||
node->rs_bbox = slab->lab_rect;
|
node->rs_bbox = slab->lab_rect;
|
||||||
|
|
@ -344,7 +343,7 @@ ResMakeLabelBreakpoints(def, goodies)
|
||||||
*
|
*
|
||||||
* ResAddBreakpointFunc --
|
* ResAddBreakpointFunc --
|
||||||
*
|
*
|
||||||
* Add a breakpoint to the "tileJunk" structure of the tile
|
* Add a breakpoint to the "resInfo" structure of the tile
|
||||||
*
|
*
|
||||||
*----------------------------------------------------------------------------
|
*----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
@ -353,9 +352,9 @@ int
|
||||||
ResAddBreakpointFunc(tile, dinfo, node)
|
ResAddBreakpointFunc(tile, dinfo, node)
|
||||||
Tile *tile;
|
Tile *tile;
|
||||||
TileType dinfo; /* (unused) */
|
TileType dinfo; /* (unused) */
|
||||||
ResSimNode *node;
|
ResExtNode *node;
|
||||||
{
|
{
|
||||||
tileJunk *junk;
|
resInfo *info;
|
||||||
|
|
||||||
if (TiGetClient(tile) == CLIENTDEFAULT)
|
if (TiGetClient(tile) == CLIENTDEFAULT)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -430,15 +429,15 @@ ResFindNewContactTiles(contacts)
|
||||||
if ((IsSplit(tile) && TTMaskHasType(&mask, TiGetRightType(tile)))
|
if ((IsSplit(tile) && TTMaskHasType(&mask, TiGetRightType(tile)))
|
||||||
|| TTMaskHasType(&mask, TiGetLeftType(tile)))
|
|| TTMaskHasType(&mask, TiGetLeftType(tile)))
|
||||||
{
|
{
|
||||||
tileJunk *j = (tileJunk *)TiGetClientPTR(tile);
|
resInfo *ri = (resInfo *)TiGetClientPTR(tile);
|
||||||
cElement *ce;
|
cElement *ce;
|
||||||
|
|
||||||
ce = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
|
ce = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
|
||||||
contacts->cp_tile[contacts->cp_currentcontact] = tile;
|
contacts->cp_tile[contacts->cp_currentcontact] = tile;
|
||||||
ce->ce_thisc = contacts;
|
ce->ce_thisc = contacts;
|
||||||
ce->ce_nextc = j->contactList;
|
ce->ce_nextc = ri->contactList;
|
||||||
(contacts->cp_currentcontact) += 1;
|
(contacts->cp_currentcontact) += 1;
|
||||||
j->contactList = ce;
|
ri->contactList = ce;
|
||||||
}
|
}
|
||||||
else if (!IsSplit(tile))
|
else if (!IsSplit(tile))
|
||||||
{
|
{
|
||||||
|
|
@ -452,15 +451,15 @@ ResFindNewContactTiles(contacts)
|
||||||
*/
|
*/
|
||||||
if (TTMaskIntersect(DBResidueMask(ttype), &mask))
|
if (TTMaskIntersect(DBResidueMask(ttype), &mask))
|
||||||
{
|
{
|
||||||
tileJunk *j = (tileJunk *)TiGetClientPTR(tile);
|
resInfo *ri = (resInfo *)TiGetClientPTR(tile);
|
||||||
cElement *ce;
|
cElement *ce;
|
||||||
|
|
||||||
ce = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
|
ce = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
|
||||||
contacts->cp_tile[contacts->cp_currentcontact] = tile;
|
contacts->cp_tile[contacts->cp_currentcontact] = tile;
|
||||||
ce->ce_thisc = contacts;
|
ce->ce_thisc = contacts;
|
||||||
ce->ce_nextc = j->contactList;
|
ce->ce_nextc = ri->contactList;
|
||||||
(contacts->cp_currentcontact) += 1;
|
(contacts->cp_currentcontact) += 1;
|
||||||
j->contactList = ce;
|
ri->contactList = ce;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -490,9 +489,9 @@ ResFindNewContactTiles(contacts)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
ResProcessTiles(goodies, origin)
|
ResProcessTiles(resisdata, origin)
|
||||||
Point *origin;
|
Point *origin;
|
||||||
ResGlobalParams *goodies;
|
ResisData *resisdata;
|
||||||
|
|
||||||
{
|
{
|
||||||
Tile *startTile;
|
Tile *startTile;
|
||||||
|
|
@ -506,57 +505,12 @@ ResProcessTiles(goodies, origin)
|
||||||
|
|
||||||
if (ResOptionsFlags & ResOpt_Signal)
|
if (ResOptionsFlags & ResOpt_Signal)
|
||||||
{
|
{
|
||||||
startTile = FindStartTile(goodies, origin);
|
startTile = FindStartTile(resisdata, origin);
|
||||||
if (startTile == NULL)
|
if (startTile == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
resCurrentNode = NULL;
|
resCurrentNode = NULL;
|
||||||
(void) ResEachTile(startTile, origin);
|
(void) ResEachTile(startTile, origin);
|
||||||
}
|
}
|
||||||
#ifdef ARIEL
|
|
||||||
else if (ResOptionsFlags & ResOpt_Power)
|
|
||||||
{
|
|
||||||
for (fix = ResFixList; fix != NULL; fix = fix->fp_next)
|
|
||||||
{
|
|
||||||
Tile *tile = fix->fp_tile;
|
|
||||||
if (tile == NULL)
|
|
||||||
{
|
|
||||||
tile = PlaneGetHint(ResDef->cd_planes[DBPlane(fix->fp_ttype)]);
|
|
||||||
GOTOPOINT(tile, &(fix->fp_loc));
|
|
||||||
if (TiGetTypeExact(tile) != TT_SPACE)
|
|
||||||
{
|
|
||||||
fix->fp_tile = tile;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tile = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tile != NULL)
|
|
||||||
{
|
|
||||||
int x = fix->fp_loc.p_x;
|
|
||||||
int y = fix->fp_loc.p_y;
|
|
||||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
|
||||||
InitializeNode(resptr, x, y, RES_NODE_ORIGIN);
|
|
||||||
resptr->rn_status = TRUE;
|
|
||||||
resptr->rn_noderes = 0;
|
|
||||||
ResAddToQueue(resptr, &ResNodeQueue);
|
|
||||||
fix->fp_node = resptr;
|
|
||||||
NEWBREAK(resptr, tile, x, y, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (fix = ResFixList; fix != NULL; fix = fix->fp_next)
|
|
||||||
{
|
|
||||||
Tile *tile = fix->fp_tile;
|
|
||||||
|
|
||||||
if (tile != NULL && (((tileJunk *)TiGetClientPTR(tile)->tj_status &
|
|
||||||
RES_TILE_DONE) == 0)
|
|
||||||
{
|
|
||||||
resCurrentNode = fix->fp_node;
|
|
||||||
(void) ResEachTile(startile, (Point *)NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -569,7 +523,7 @@ ResProcessTiles(goodies, origin)
|
||||||
while (ResNodeQueue != NULL)
|
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
|
* the current one. If it does, then the node must be processed
|
||||||
* because additional junctions or contacts were added
|
* because additional junctions or contacts were added
|
||||||
*/
|
*/
|
||||||
|
|
@ -587,16 +541,14 @@ ResProcessTiles(goodies, origin)
|
||||||
for (tilenum = 0; tilenum < TILES_PER_JUNCTION; tilenum++)
|
for (tilenum = 0; tilenum < TILES_PER_JUNCTION; tilenum++)
|
||||||
{
|
{
|
||||||
Tile *tile = rj->rj_Tile[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;
|
resCurrentNode = resptr2;
|
||||||
merged |= ResEachTile(tile, (Point *)NULL);
|
merged |= ResEachTile(tile, (Point *)NULL);
|
||||||
}
|
}
|
||||||
if (merged & ORIGIN) break;
|
|
||||||
}
|
}
|
||||||
if (merged & ORIGIN) break;
|
|
||||||
rj->rj_status = TRUE;
|
rj->rj_status = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -607,16 +559,15 @@ ResProcessTiles(goodies, origin)
|
||||||
{
|
{
|
||||||
ResContactPoint *cp = workingc->ce_thisc;
|
ResContactPoint *cp = workingc->ce_thisc;
|
||||||
|
|
||||||
if (merged & ORIGIN) break;
|
|
||||||
if (cp->cp_status == FALSE)
|
if (cp->cp_status == FALSE)
|
||||||
{
|
{
|
||||||
int newstatus = TRUE;
|
int newstatus = TRUE;
|
||||||
for (tilenum = 0; tilenum < cp->cp_currentcontact; tilenum++)
|
for (tilenum = 0; tilenum < cp->cp_currentcontact; tilenum++)
|
||||||
{
|
{
|
||||||
Tile *tile = cp->cp_tile[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)
|
if (cp->cp_cnode[tilenum] == resptr2)
|
||||||
{
|
{
|
||||||
|
|
@ -628,9 +579,7 @@ ResProcessTiles(goodies, origin)
|
||||||
newstatus = FALSE;
|
newstatus = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (merged & ORIGIN) break;
|
|
||||||
}
|
}
|
||||||
if (merged & ORIGIN) break;
|
|
||||||
cp->cp_status = newstatus;
|
cp->cp_status = newstatus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -646,15 +595,15 @@ ResProcessTiles(goodies, origin)
|
||||||
ResRemoveFromQueue(resptr2, &ResNodeQueue);
|
ResRemoveFromQueue(resptr2, &ResNodeQueue);
|
||||||
resptr2->rn_more = ResNodeList;
|
resptr2->rn_more = ResNodeList;
|
||||||
resptr2->rn_less = NULL;
|
resptr2->rn_less = NULL;
|
||||||
resptr2->rn_status &= ~PENDING;
|
resptr2->rn_status &= ~RES_PENDING;
|
||||||
resptr2->rn_status |= FINISHED | MARKED;
|
resptr2->rn_status |= RES_FINISHED | RES_MARKED;
|
||||||
if (ResNodeList != NULL)
|
if (ResNodeList != NULL)
|
||||||
{
|
{
|
||||||
ResNodeList->rn_less = resptr2;
|
ResNodeList->rn_less = resptr2;
|
||||||
}
|
}
|
||||||
if (resptr2->rn_noderes == 0)
|
if (resptr2->rn_noderes == 0)
|
||||||
{
|
{
|
||||||
ResOriginNode=resptr2;
|
ResNodeAtOrigin = resptr2;
|
||||||
}
|
}
|
||||||
ResNodeList = resptr2;
|
ResNodeList = resptr2;
|
||||||
ResCleanNode(resptr2, FALSE, &ResNodeList, &ResNodeQueue);
|
ResCleanNode(resptr2, FALSE, &ResNodeList, &ResNodeQueue);
|
||||||
|
|
@ -733,7 +682,7 @@ ResCalcPerimOverlap(tile, dev)
|
||||||
* resMakeDevFunc --
|
* resMakeDevFunc --
|
||||||
*
|
*
|
||||||
* Callback function from ResExtractNet. For each device in a node's
|
* 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
|
* to the device in the source tree, and fill out the complete device
|
||||||
* record (namely the full device area).
|
* record (namely the full device area).
|
||||||
*
|
*
|
||||||
|
|
@ -771,7 +720,7 @@ resMakeDevFunc(tile, dinfo, cx)
|
||||||
|
|
||||||
/* If more than one tile type extracts to the same device, then */
|
/* If more than one tile type extracts to the same device, then */
|
||||||
/* the device type may be different from what was recorded when */
|
/* 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 */
|
/* original type to avoid conflict with completely different */
|
||||||
/* devices (like transistors vs. MiM caps). */
|
/* devices (like transistors vs. MiM caps). */
|
||||||
|
|
||||||
|
|
@ -1035,9 +984,9 @@ ResShaveContacts(tile, dinfo, def)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ResExtractNet(node, goodies, cellname)
|
ResExtractNet(node, resisdata, cellname)
|
||||||
ResSimNode *node;
|
ResExtNode *node;
|
||||||
ResGlobalParams *goodies;
|
ResisData *resisdata;
|
||||||
char *cellname;
|
char *cellname;
|
||||||
{
|
{
|
||||||
SearchContext scx;
|
SearchContext scx;
|
||||||
|
|
@ -1059,12 +1008,12 @@ ResExtractNet(node, goodies, cellname)
|
||||||
ResDevList = NULL;
|
ResDevList = NULL;
|
||||||
ResNodeQueue = NULL;
|
ResNodeQueue = NULL;
|
||||||
ResContactList = NULL;
|
ResContactList = NULL;
|
||||||
ResOriginNode = NULL;
|
ResNodeAtOrigin = NULL;
|
||||||
|
|
||||||
/* Pass back network pointers */
|
/* Pass back network pointers */
|
||||||
|
|
||||||
goodies->rg_maxres = 0;
|
resisdata->rg_maxres = 0;
|
||||||
goodies->rg_tilecount = 0;
|
resisdata->rg_tilecount = 0;
|
||||||
|
|
||||||
/* Set up internal stuff if this is the first time through */
|
/* Set up internal stuff if this is the first time through */
|
||||||
|
|
||||||
|
|
@ -1103,11 +1052,6 @@ ResExtractNet(node, goodies, cellname)
|
||||||
|
|
||||||
DBCellClearDef(ResUse->cu_def);
|
DBCellClearDef(ResUse->cu_def);
|
||||||
|
|
||||||
#ifdef ARIEL
|
|
||||||
if ((ResOptionsFlags & ResOpt_Power) &&
|
|
||||||
strcmp(node->name, goodies->rg_name) != 0) continue;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Copy Paint */
|
/* Copy Paint */
|
||||||
|
|
||||||
scx.scx_area.r_ll.p_x = node->location.p_x - 2;
|
scx.scx_area.r_ll.p_x = node->location.p_x - 2;
|
||||||
|
|
@ -1152,10 +1096,10 @@ ResExtractNet(node, goodies, cellname)
|
||||||
resMakeDevFunc, (ClientData)thisDev);
|
resMakeDevFunc, (ClientData)thisDev);
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
{
|
{
|
||||||
TxError("No device of type %s found at location %d,%d\n",
|
TxError("No device of type %s found at location %s, %s\n",
|
||||||
DBTypeLongNameTbl[thisDev->type],
|
DBTypeLongNameTbl[thisDev->type],
|
||||||
tptr->thisDev->location.p_x,
|
DBWPrintValue(tptr->thisDev->location.p_x, (MagWindow*)NULL, TRUE),
|
||||||
tptr->thisDev->location.p_y);
|
DBWPrintValue(tptr->thisDev->location.p_y, (MagWindow*)NULL, FALSE));
|
||||||
freeMagic(thisDev);
|
freeMagic(thisDev);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -1219,7 +1163,7 @@ ResExtractNet(node, goodies, cellname)
|
||||||
|
|
||||||
ResDissolveContacts(ResContactList);
|
ResDissolveContacts(ResContactList);
|
||||||
|
|
||||||
/* Add "junk" fields to tiles */
|
/* Add "resInfo" fields to tiles */
|
||||||
|
|
||||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||||
{
|
{
|
||||||
|
|
@ -1232,39 +1176,22 @@ ResExtractNet(node, goodies, cellname)
|
||||||
(ClientData) &ResDevList);
|
(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);
|
ResMakePortBreakpoints(ResUse->cu_def);
|
||||||
ResMakeLabelBreakpoints(ResUse->cu_def, goodies);
|
ResMakeLabelBreakpoints(ResUse->cu_def, resisdata);
|
||||||
|
|
||||||
|
/* Finish preprocessing. */
|
||||||
|
|
||||||
ResFindNewContactTiles(ResContactList);
|
ResFindNewContactTiles(ResContactList);
|
||||||
ResPreProcessDevices(DevTiles, ResDevList, ResUse->cu_def);
|
ResPreProcessDevices(DevTiles, ResDevList, ResUse->cu_def);
|
||||||
|
|
||||||
#ifdef LAPLACE
|
|
||||||
if (ResOptionsFlags & ResOpt_DoLaplace)
|
|
||||||
{
|
|
||||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
||||||
{
|
|
||||||
Plane *plane = ResUse->cu_def->cd_planes[pNum];
|
|
||||||
Rect *rect = &ResUse->cu_def->cd_bbox;
|
|
||||||
Res1d(plane, rect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ARIEL
|
|
||||||
if (ResOptionsFlags & ResOpt_Power)
|
|
||||||
{
|
|
||||||
for (fix = startlist; fix != NULL; fix = fix->fp_next)
|
|
||||||
{
|
|
||||||
fix->fp_tile = PlaneGetHint(ResUse->cu_def->cd_planes[DBPlane(fix->fp_ttype)]);
|
|
||||||
GOTOPOINT(fix->fp_tile, &fix->fp_loc);
|
|
||||||
if (TiGetTypeExact(fix->fp_tile) == TT_SPACE) fix->fp_tile = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* do extraction */
|
/* do extraction */
|
||||||
if (ResProcessTiles(goodies, &startpoint) != 0) return TRUE;
|
if (ResProcessTiles(resisdata, &startpoint) != 0) return TRUE;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1383,7 +1310,7 @@ ResGetTileFunc(tile, dinfo, tpptr)
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* FindStartTile-- To start the extraction, we need to find the first driver.
|
* 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
|
* unit) of the device. FindStartTile looks for the device, then
|
||||||
* for adjoining diffusion. The diffusion tile is returned.
|
* for adjoining diffusion. The diffusion tile is returned.
|
||||||
*
|
*
|
||||||
|
|
@ -1397,10 +1324,9 @@ ResGetTileFunc(tile, dinfo, tpptr)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Tile *
|
Tile *
|
||||||
FindStartTile(goodies, SourcePoint)
|
FindStartTile(resisdata, SourcePoint)
|
||||||
|
ResisData *resisdata;
|
||||||
Point *SourcePoint;
|
Point *SourcePoint;
|
||||||
ResGlobalParams *goodies;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Point workingPoint;
|
Point workingPoint;
|
||||||
Tile *tile, *tp;
|
Tile *tile, *tp;
|
||||||
|
|
@ -1413,39 +1339,39 @@ FindStartTile(goodies, SourcePoint)
|
||||||
/* If the drive point is on a contact, check for the contact residues */
|
/* If the drive point is on a contact, check for the contact residues */
|
||||||
/* first, then the contact type itself. */
|
/* first, then the contact type itself. */
|
||||||
|
|
||||||
if (DBIsContact(goodies->rg_ttype))
|
if (DBIsContact(resisdata->rg_ttype))
|
||||||
{
|
{
|
||||||
TileTypeBitMask *rmask = DBResidueMask(goodies->rg_ttype);
|
TileTypeBitMask *rmask = DBResidueMask(resisdata->rg_ttype);
|
||||||
TileType savtype = goodies->rg_ttype;
|
TileType savtype = resisdata->rg_ttype;
|
||||||
TileType rtype;
|
TileType rtype;
|
||||||
|
|
||||||
for (rtype = TT_TECHDEPBASE; rtype < DBNumUserLayers; rtype++)
|
for (rtype = TT_TECHDEPBASE; rtype < DBNumUserLayers; rtype++)
|
||||||
if (TTMaskHasType(rmask, rtype))
|
if (TTMaskHasType(rmask, rtype))
|
||||||
{
|
{
|
||||||
goodies->rg_ttype = rtype;
|
resisdata->rg_ttype = rtype;
|
||||||
if ((tile = FindStartTile(goodies, SourcePoint)) != NULL)
|
if ((tile = FindStartTile(resisdata, SourcePoint)) != NULL)
|
||||||
{
|
{
|
||||||
goodies->rg_ttype = savtype;
|
resisdata->rg_ttype = savtype;
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
goodies->rg_ttype = savtype;
|
resisdata->rg_ttype = savtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
workingPoint.p_x = goodies->rg_devloc->p_x;
|
workingPoint.p_x = resisdata->rg_devloc->p_x;
|
||||||
workingPoint.p_y = goodies->rg_devloc->p_y;
|
workingPoint.p_y = resisdata->rg_devloc->p_y;
|
||||||
|
|
||||||
pnum = DBPlane(goodies->rg_ttype);
|
pnum = DBPlane(resisdata->rg_ttype);
|
||||||
|
|
||||||
/* for drivepoints, we don't have to find a device */
|
/* for drivepoints, we don't have to find a device */
|
||||||
if (goodies->rg_status & DRIVEONLY)
|
if (resisdata->rg_status & DRIVEONLY)
|
||||||
{
|
{
|
||||||
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
||||||
GOTOPOINT(tile, &workingPoint);
|
GOTOPOINT(tile, &workingPoint);
|
||||||
SourcePoint->p_x = workingPoint.p_x;
|
SourcePoint->p_x = workingPoint.p_x;
|
||||||
SourcePoint->p_y = workingPoint.p_y;
|
SourcePoint->p_y = workingPoint.p_y;
|
||||||
|
|
||||||
if (TiGetTypeExact(tile) == goodies->rg_ttype)
|
if (TiGetTypeExact(tile) == resisdata->rg_ttype)
|
||||||
return tile;
|
return tile;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1457,18 +1383,19 @@ FindStartTile(goodies, SourcePoint)
|
||||||
if (workingPoint.p_x == LEFT(tile))
|
if (workingPoint.p_x == LEFT(tile))
|
||||||
{
|
{
|
||||||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
|
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
|
||||||
if (TiGetRightType(tp) == goodies->rg_ttype)
|
if (TiGetRightType(tp) == resisdata->rg_ttype)
|
||||||
return(tp);
|
return(tp);
|
||||||
}
|
}
|
||||||
else if (workingPoint.p_y == BOTTOM(tile))
|
else if (workingPoint.p_y == BOTTOM(tile))
|
||||||
{
|
{
|
||||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
|
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
|
||||||
if (TiGetTopType(tp) == goodies->rg_ttype)
|
if (TiGetTopType(tp) == resisdata->rg_ttype)
|
||||||
return(tp);
|
return(tp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TxError("Couldn't find wire at %d %d\n",
|
TxError("Couldn't find wire at %s %s\n",
|
||||||
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
|
DBWPrintValue(resisdata->rg_devloc->p_x, (MagWindow *)NULL, TRUE),
|
||||||
|
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow *)NULL, FALSE));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1483,15 +1410,17 @@ FindStartTile(goodies, SourcePoint)
|
||||||
t1 = TiGetRightType(tile);
|
t1 = TiGetRightType(tile);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TxError("Couldn't find device at %d %d\n",
|
TxError("Couldn't find device at %s %s\n",
|
||||||
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
|
DBWPrintValue(resisdata->rg_devloc->p_x, (MagWindow *)NULL, TRUE),
|
||||||
|
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow *)NULL, FALSE));
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetType(tile)) == 0)
|
else if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetType(tile)) == 0)
|
||||||
{
|
{
|
||||||
TxError("Couldn't find device at %d %d\n",
|
TxError("Couldn't find device at %s %s\n",
|
||||||
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
|
DBWPrintValue(resisdata->rg_devloc->p_x, (MagWindow *)NULL, TRUE),
|
||||||
|
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow *)NULL, FALSE));
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1522,8 +1451,9 @@ FindStartTile(goodies, SourcePoint)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const ClientData ticlient = TiGetClient(tp);
|
const ClientData ticlient = TiGetClient(tp);
|
||||||
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
const resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||||
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
|
|
||||||
|
if (ticlient != CLIENTDEFAULT && rinfo->ri_status & RES_TILE_DEV)
|
||||||
complex = TRUE;
|
complex = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1543,8 +1473,8 @@ FindStartTile(goodies, SourcePoint)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const ClientData ticlient = TiGetClient(tp);
|
const ClientData ticlient = TiGetClient(tp);
|
||||||
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
const resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||||
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
|
if (ticlient != CLIENTDEFAULT && rinfo->ri_status & RES_TILE_DEV)
|
||||||
complex = TRUE;
|
complex = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1564,8 +1494,8 @@ FindStartTile(goodies, SourcePoint)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const ClientData ticlient = TiGetClient(tp);
|
const ClientData ticlient = TiGetClient(tp);
|
||||||
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
const resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||||
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
|
if (ticlient != CLIENTDEFAULT && rinfo->ri_status & RES_TILE_DEV)
|
||||||
complex = TRUE;
|
complex = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1585,8 +1515,8 @@ FindStartTile(goodies, SourcePoint)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const ClientData ticlient = TiGetClient(tp);
|
const ClientData ticlient = TiGetClient(tp);
|
||||||
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
const resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||||
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
|
if (ticlient != CLIENTDEFAULT && rinfo->ri_status & RES_TILE_DEV)
|
||||||
complex = TRUE;
|
complex = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1599,7 +1529,7 @@ FindStartTile(goodies, SourcePoint)
|
||||||
|
|
||||||
if (devStack == NULL) devStack = StackNew(8);
|
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);
|
STACKPUSH((ClientData)tile, devStack);
|
||||||
while (!StackEmpty(devStack))
|
while (!StackEmpty(devStack))
|
||||||
{
|
{
|
||||||
|
|
@ -1626,12 +1556,12 @@ FindStartTile(goodies, SourcePoint)
|
||||||
const ClientData ticlient = TiGetClient(tp);
|
const ClientData ticlient = TiGetClient(tp);
|
||||||
if (ticlient != CLIENTDEFAULT)
|
if (ticlient != CLIENTDEFAULT)
|
||||||
{
|
{
|
||||||
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||||
if (tj->tj_status & RES_TILE_DEV)
|
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);
|
STACKPUSH((ClientData)tp, devStack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1660,12 +1590,12 @@ FindStartTile(goodies, SourcePoint)
|
||||||
const ClientData ticlient = TiGetClient(tp);
|
const ClientData ticlient = TiGetClient(tp);
|
||||||
if (ticlient != CLIENTDEFAULT)
|
if (ticlient != CLIENTDEFAULT)
|
||||||
{
|
{
|
||||||
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||||
if (tj->tj_status & RES_TILE_DEV)
|
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);
|
STACKPUSH((ClientData)tp, devStack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1694,12 +1624,12 @@ FindStartTile(goodies, SourcePoint)
|
||||||
const ClientData ticlient = TiGetClient(tp);
|
const ClientData ticlient = TiGetClient(tp);
|
||||||
if (ticlient != CLIENTDEFAULT)
|
if (ticlient != CLIENTDEFAULT)
|
||||||
{
|
{
|
||||||
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||||
if (tj->tj_status & RES_TILE_DEV)
|
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);
|
STACKPUSH((ClientData)tp, devStack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1728,12 +1658,12 @@ FindStartTile(goodies, SourcePoint)
|
||||||
const ClientData ticlient = TiGetClient(tp);
|
const ClientData ticlient = TiGetClient(tp);
|
||||||
if (ticlient != CLIENTDEFAULT)
|
if (ticlient != CLIENTDEFAULT)
|
||||||
{
|
{
|
||||||
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
|
resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
|
||||||
if (tj->tj_status & RES_TILE_DEV)
|
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);
|
STACKPUSH((ClientData)tp, devStack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1782,8 +1712,9 @@ FindStartTile(goodies, SourcePoint)
|
||||||
/* Didn't find a terminal (S/D or substrate) type tile anywhere. Flag an error. */
|
/* Didn't find a terminal (S/D or substrate) type tile anywhere. Flag an error. */
|
||||||
|
|
||||||
if (devptr == NULL)
|
if (devptr == NULL)
|
||||||
TxError("Couldn't find a terminal of the device at %d %d\n",
|
TxError("Couldn't find a terminal of the device at %s %s\n",
|
||||||
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
|
DBWPrintValue(resisdata->rg_devloc->p_x, (MagWindow*)NULL, TRUE),
|
||||||
|
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow*)NULL, FALSE));
|
||||||
return((Tile *) NULL);
|
return((Tile *) NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1791,7 +1722,7 @@ FindStartTile(goodies, SourcePoint)
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* ResGetDevice -- Once the net is extracted, we still have to equate
|
* 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
|
* looks for a device at the given location. "type" is also
|
||||||
* specified to that the right plane will be searched.
|
* specified to that the right plane will be searched.
|
||||||
*
|
*
|
||||||
|
|
@ -1827,7 +1758,7 @@ ResGetDevice(pt, type)
|
||||||
{
|
{
|
||||||
if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetLeftType(tile))
|
if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetLeftType(tile))
|
||||||
|| TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetRightType(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)))
|
else if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetType(tile)))
|
||||||
{
|
{
|
||||||
|
|
@ -1835,7 +1766,7 @@ ResGetDevice(pt, type)
|
||||||
* error and indicates a problem that needs debugging.
|
* error and indicates a problem that needs debugging.
|
||||||
*/
|
*/
|
||||||
if (ticlient != CLIENTDEFAULT)
|
if (ticlient != CLIENTDEFAULT)
|
||||||
return (((tileJunk *)CD2PTR(ticlient))->deviceList);
|
return (((resInfo *)CD2PTR(ticlient))->deviceList);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,9 @@ bool ResCalcEastWest();
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ResCalcTileResistance(tile, junk, pendingList, doneList)
|
ResCalcTileResistance(tile, info, pendingList, doneList)
|
||||||
Tile *tile;
|
Tile *tile;
|
||||||
tileJunk *junk;
|
resInfo *info;
|
||||||
resNode **pendingList, **doneList;
|
resNode **pendingList, **doneList;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -67,7 +67,7 @@ ResCalcTileResistance(tile, junk, pendingList, doneList)
|
||||||
merged = FALSE;
|
merged = FALSE;
|
||||||
device = FALSE;
|
device = FALSE;
|
||||||
|
|
||||||
if ((p1 = junk->breakList) == NULL) return FALSE;
|
if ((p1 = info->breakList) == NULL) return FALSE;
|
||||||
for (; p1; p1 = p1->br_next)
|
for (; p1; p1 = p1->br_next)
|
||||||
{
|
{
|
||||||
int x = p1->br_loc.p_x;
|
int x = p1->br_loc.p_x;
|
||||||
|
|
@ -133,7 +133,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
||||||
resElement *element;
|
resElement *element;
|
||||||
resNode *currNode;
|
resNode *currNode;
|
||||||
float rArea;
|
float rArea;
|
||||||
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
|
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||||
|
|
||||||
merged = FALSE;
|
merged = FALSE;
|
||||||
height = TOP(tile) - BOTTOM(tile);
|
height = TOP(tile) - BOTTOM(tile);
|
||||||
|
|
@ -143,12 +143,12 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
||||||
* breakpoint, then return.
|
* breakpoint, then return.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
p1 = junk->breakList;
|
p1 = info->breakList;
|
||||||
if (p1->br_next == NULL)
|
if (p1->br_next == NULL)
|
||||||
{
|
{
|
||||||
p1->br_this->rn_float.rn_area += height * (LEFT(tile) - RIGHT(tile));
|
p1->br_this->rn_float.rn_area += height * (LEFT(tile) - RIGHT(tile));
|
||||||
freeMagic((char *)p1);
|
freeMagic((char *)p1);
|
||||||
junk->breakList = NULL;
|
info->breakList = NULL;
|
||||||
return(merged);
|
return(merged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,14 +164,14 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
||||||
|
|
||||||
/* Re-sort nodes left to right. */
|
/* Re-sort nodes left to right. */
|
||||||
|
|
||||||
ResSortBreaks(&junk->breakList, TRUE);
|
ResSortBreaks(&info->breakList, TRUE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Eliminate breakpoints with the same X coordinate and merge
|
* Eliminate breakpoints with the same X coordinate and merge
|
||||||
* their nodes.
|
* their nodes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
p2= junk->breakList;
|
p2= info->breakList;
|
||||||
|
|
||||||
/* Add extra left area to leftmost node */
|
/* 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.
|
* If so, replace the old node with the new one.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -263,10 +263,6 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
||||||
{
|
{
|
||||||
resistor->rr_status = RES_EW;
|
resistor->rr_status = RES_EW;
|
||||||
}
|
}
|
||||||
#ifdef ARIEL
|
|
||||||
resistor->rr_csArea = height *
|
|
||||||
ExtCurStyle->exts_thick[resistor->rr_tt];
|
|
||||||
#endif
|
|
||||||
resistor->rr_value =
|
resistor->rr_value =
|
||||||
(float)ExtCurStyle->exts_sheetResist[resistor->rr_tt]
|
(float)ExtCurStyle->exts_sheetResist[resistor->rr_tt]
|
||||||
* (float)(p2->br_loc.p_x - p1->br_loc.p_x)
|
* (float)(p2->br_loc.p_x - p1->br_loc.p_x)
|
||||||
|
|
@ -282,7 +278,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
||||||
|
|
||||||
p2->br_this->rn_float.rn_area += height * (RIGHT(tile) - p2->br_loc.p_x);
|
p2->br_this->rn_float.rn_area += height * (RIGHT(tile) - p2->br_loc.p_x);
|
||||||
freeMagic((char *)p2);
|
freeMagic((char *)p2);
|
||||||
junk->breakList = NULL;
|
info->breakList = NULL;
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -313,7 +309,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
||||||
resElement *element;
|
resElement *element;
|
||||||
resNode *currNode;
|
resNode *currNode;
|
||||||
float rArea;
|
float rArea;
|
||||||
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
|
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||||
|
|
||||||
merged = FALSE;
|
merged = FALSE;
|
||||||
width = RIGHT(tile) - LEFT(tile);
|
width = RIGHT(tile) - LEFT(tile);
|
||||||
|
|
@ -323,17 +319,17 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
||||||
* breakpoint, then return.
|
* breakpoint, then return.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
p1 = junk->breakList;
|
p1 = info->breakList;
|
||||||
if (p1->br_next == NULL)
|
if (p1->br_next == NULL)
|
||||||
{
|
{
|
||||||
p1->br_this->rn_float.rn_area += width * (TOP(tile) - BOTTOM(tile));
|
p1->br_this->rn_float.rn_area += width * (TOP(tile) - BOTTOM(tile));
|
||||||
freeMagic((char *)p1);
|
freeMagic((char *)p1);
|
||||||
junk->breakList = NULL;
|
info->breakList = NULL;
|
||||||
return(merged);
|
return(merged);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Re-sort nodes south to north. */
|
/* Re-sort nodes south to north. */
|
||||||
ResSortBreaks(&junk->breakList, FALSE);
|
ResSortBreaks(&info->breakList, FALSE);
|
||||||
|
|
||||||
/* Simplified split tile handling */
|
/* Simplified split tile handling */
|
||||||
if (IsSplit(tile))
|
if (IsSplit(tile))
|
||||||
|
|
@ -350,7 +346,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
||||||
* their nodes.
|
* their nodes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
p2 = junk->breakList;
|
p2 = info->breakList;
|
||||||
|
|
||||||
/* Add extra left area to leftmost node */
|
/* Add extra left area to leftmost node */
|
||||||
|
|
||||||
|
|
@ -392,7 +388,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Was the node used in another junk or breakpoint?
|
* Was the node used in another info or breakpoint?
|
||||||
* If so, replace the old node with the new one.
|
* If so, replace the old node with the new one.
|
||||||
*/
|
*/
|
||||||
p3 = p2->br_next;
|
p3 = p2->br_next;
|
||||||
|
|
@ -440,10 +436,6 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
||||||
{
|
{
|
||||||
resistor->rr_status = RES_NS;
|
resistor->rr_status = RES_NS;
|
||||||
}
|
}
|
||||||
#ifdef ARIEL
|
|
||||||
resistor->rr_csArea = width
|
|
||||||
* ExtCurStyle->exts_thick[resistor->rr_tt];
|
|
||||||
#endif
|
|
||||||
resistor->rr_value =
|
resistor->rr_value =
|
||||||
(float)ExtCurStyle->exts_sheetResist[resistor->rr_tt]
|
(float)ExtCurStyle->exts_sheetResist[resistor->rr_tt]
|
||||||
* (float)(p2->br_loc.p_y - p1->br_loc.p_y)
|
* (float)(p2->br_loc.p_y - p1->br_loc.p_y)
|
||||||
|
|
@ -457,7 +449,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
||||||
}
|
}
|
||||||
p2->br_this->rn_float.rn_area += width * (TOP(tile) - p2->br_loc.p_y);
|
p2->br_this->rn_float.rn_area += width * (TOP(tile) - p2->br_loc.p_y);
|
||||||
freeMagic((char *)p2);
|
freeMagic((char *)p2);
|
||||||
junk->breakList = NULL;
|
info->breakList = NULL;
|
||||||
return(merged);
|
return(merged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -490,7 +482,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
||||||
bool merged;
|
bool merged;
|
||||||
int devcount, devedge, deltax, deltay;
|
int devcount, devedge, deltax, deltay;
|
||||||
Breakpoint *p1, *p2, *p3;
|
Breakpoint *p1, *p2, *p3;
|
||||||
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
|
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||||
|
|
||||||
merged = FALSE;
|
merged = FALSE;
|
||||||
|
|
||||||
|
|
@ -499,10 +491,10 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
||||||
* breakpoint, then return.
|
* breakpoint, then return.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (junk->breakList->br_next == NULL)
|
if (info->breakList->br_next == NULL)
|
||||||
{
|
{
|
||||||
freeMagic((char *)junk->breakList);
|
freeMagic((char *)info->breakList);
|
||||||
junk->breakList = NULL;
|
info->breakList = NULL;
|
||||||
return(merged);
|
return(merged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -511,7 +503,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
||||||
|
|
||||||
devcount = 0;
|
devcount = 0;
|
||||||
devedge = 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)
|
if (p1->br_this->rn_why == RES_NODE_DEVICE)
|
||||||
{
|
{
|
||||||
|
|
@ -533,9 +525,9 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
||||||
(devedge & TOPEDGE) == devedge ||
|
(devedge & TOPEDGE) == devedge ||
|
||||||
(devedge & BOTTOMEDGE) == devedge)
|
(devedge & BOTTOMEDGE) == devedge)
|
||||||
{
|
{
|
||||||
ResSortBreaks(&junk->breakList,TRUE);
|
ResSortBreaks(&info->breakList,TRUE);
|
||||||
p2 = NULL;
|
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)
|
if (p1->br_this->rn_why == RES_NODE_DEVICE)
|
||||||
break;
|
break;
|
||||||
|
|
@ -595,9 +587,9 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Re-sort nodes south to north. */
|
/* Re-sort nodes south to north. */
|
||||||
ResSortBreaks(&junk->breakList, FALSE);
|
ResSortBreaks(&info->breakList, FALSE);
|
||||||
p2 = NULL;
|
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)
|
if (p1->br_this->rn_why == RES_NODE_DEVICE)
|
||||||
{
|
{
|
||||||
|
|
@ -692,17 +684,17 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
||||||
(RIGHT(tile) - LEFT(tile)) > (TOP(tile) - BOTTOM(tile))))
|
(RIGHT(tile) - LEFT(tile)) > (TOP(tile) - BOTTOM(tile))))
|
||||||
{
|
{
|
||||||
/* re-sort nodes south to north. */
|
/* re-sort nodes south to north. */
|
||||||
ResSortBreaks(&junk->breakList, FALSE);
|
ResSortBreaks(&info->breakList, FALSE);
|
||||||
|
|
||||||
/* eliminate duplicate S/D pointers */
|
/* 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 &&
|
if (p1->br_this->rn_why == RES_NODE_DEVICE &&
|
||||||
(p1->br_loc.p_y == BOTTOM(tile) ||
|
(p1->br_loc.p_y == BOTTOM(tile) ||
|
||||||
p1->br_loc.p_y == TOP(tile)))
|
p1->br_loc.p_y == TOP(tile)))
|
||||||
{
|
{
|
||||||
p3 = NULL;
|
p3 = NULL;
|
||||||
p2 = junk->breakList;
|
p2 = info->breakList;
|
||||||
while (p2 != NULL)
|
while (p2 != NULL)
|
||||||
{
|
{
|
||||||
if (p2->br_this == p1->br_this && p2 != p1 &&
|
if (p2->br_this == p1->br_this && p2 != p1 &&
|
||||||
|
|
@ -711,9 +703,9 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
||||||
{
|
{
|
||||||
if (p3 == NULL)
|
if (p3 == NULL)
|
||||||
{
|
{
|
||||||
junk->breakList = p2->br_next;
|
info->breakList = p2->br_next;
|
||||||
freeMagic((char *) p2);
|
freeMagic((char *) p2);
|
||||||
p2 = junk->breakList;
|
p2 = info->breakList;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -735,14 +727,14 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Eliminate duplicate S/D pointers */
|
/* 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 &&
|
if (p1->br_this->rn_why == RES_NODE_DEVICE &&
|
||||||
(p1->br_loc.p_x == LEFT(tile) ||
|
(p1->br_loc.p_x == LEFT(tile) ||
|
||||||
p1->br_loc.p_x == RIGHT(tile)))
|
p1->br_loc.p_x == RIGHT(tile)))
|
||||||
{
|
{
|
||||||
p3 = NULL;
|
p3 = NULL;
|
||||||
p2 = junk->breakList;
|
p2 = info->breakList;
|
||||||
while (p2 != NULL)
|
while (p2 != NULL)
|
||||||
{
|
{
|
||||||
if (p2->br_this == p1->br_this && p2 != p1 &&
|
if (p2->br_this == p1->br_this && p2 != p1 &&
|
||||||
|
|
@ -751,9 +743,9 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
||||||
{
|
{
|
||||||
if (p3 == NULL)
|
if (p3 == NULL)
|
||||||
{
|
{
|
||||||
junk->breakList = p2->br_next;
|
info->breakList = p2->br_next;
|
||||||
freeMagic((char *) p2);
|
freeMagic((char *) p2);
|
||||||
p2 = junk->breakList;
|
p2 = info->breakList;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -813,7 +805,7 @@ ResDoContacts(contact, nodes, resList)
|
||||||
int y = contact->cp_center.p_y;
|
int y = contact->cp_center.p_y;
|
||||||
|
|
||||||
resptr = (resNode *) mallocMagic((unsigned) (sizeof(resNode)));
|
resptr = (resNode *) mallocMagic((unsigned) (sizeof(resNode)));
|
||||||
InitializeNode(resptr, x, y, RES_NODE_CONTACT);
|
InitializeResNode(resptr, x, y, RES_NODE_CONTACT);
|
||||||
ResAddToQueue(resptr, nodes);
|
ResAddToQueue(resptr, nodes);
|
||||||
|
|
||||||
ccell = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
|
ccell = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
|
||||||
|
|
@ -866,7 +858,7 @@ ResDoContacts(contact, nodes, resList)
|
||||||
Tile *tile = contact->cp_tile[tilenum];
|
Tile *tile = contact->cp_tile[tilenum];
|
||||||
|
|
||||||
resptr = (resNode *) mallocMagic((unsigned) (sizeof(resNode)));
|
resptr = (resNode *) mallocMagic((unsigned) (sizeof(resNode)));
|
||||||
InitializeNode(resptr, x, y, RES_NODE_CONTACT);
|
InitializeResNode(resptr, x, y, RES_NODE_CONTACT);
|
||||||
ResAddToQueue(resptr, nodes);
|
ResAddToQueue(resptr, nodes);
|
||||||
|
|
||||||
/* Add contact pointer to node */
|
/* Add contact pointer to node */
|
||||||
|
|
@ -916,11 +908,6 @@ ResDoContacts(contact, nodes, resList)
|
||||||
resistor->rr_value =
|
resistor->rr_value =
|
||||||
(float)ExtCurStyle->exts_viaResist[contact->cp_type] /
|
(float)ExtCurStyle->exts_viaResist[contact->cp_type] /
|
||||||
(float)(squaresx * squaresy);
|
(float)(squaresx * squaresy);
|
||||||
#ifdef ARIEL
|
|
||||||
resistor->rr_csArea =
|
|
||||||
(float)ExtCurStyle->exts_thick[contact->cp_type] /
|
|
||||||
(float)(squaresx * squaresy);
|
|
||||||
#endif
|
|
||||||
resistor->rr_tt = contact->cp_type;
|
resistor->rr_tt = contact->cp_type;
|
||||||
resistor->rr_float.rr_area = 0;
|
resistor->rr_float.rr_area = 0;
|
||||||
resistor->rr_status = 0;
|
resistor->rr_status = 0;
|
||||||
|
|
|
||||||
135
resis/ResMerge.c
135
resis/ResMerge.c
|
|
@ -53,7 +53,7 @@ ResDoneWithNode(resptr)
|
||||||
resResistor *rr1;
|
resResistor *rr1;
|
||||||
|
|
||||||
resptr2 = NULL;
|
resptr2 = NULL;
|
||||||
resptr->rn_status |= RESTRUE;
|
resptr->rn_status |= RES_TRUE;
|
||||||
status = UNTOUCHED;
|
status = UNTOUCHED;
|
||||||
|
|
||||||
/* are there any resistors? */
|
/* are there any resistors? */
|
||||||
|
|
@ -93,9 +93,9 @@ ResDoneWithNode(resptr)
|
||||||
ResMergeNodes(resptr2, resptr, &ResNodeQueue, &ResNodeList);
|
ResMergeNodes(resptr2, resptr, &ResNodeQueue, &ResNodeList);
|
||||||
resptr2->rn_float.rn_area += rr1->rr_float.rr_area;
|
resptr2->rn_float.rn_area += rr1->rr_float.rr_area;
|
||||||
ResEliminateResistor(rr1, &ResResList);
|
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);
|
ResDoneWithNode(resptr2);
|
||||||
}
|
}
|
||||||
resptr2 = NULL;
|
resptr2 = NULL;
|
||||||
|
|
@ -108,14 +108,16 @@ ResDoneWithNode(resptr)
|
||||||
/* Eliminations that can be only if there are no devices connected */
|
/* Eliminations that can be only if there are no devices connected */
|
||||||
/* to node. Series and dangling connections fall in this group. */
|
/* to node. Series and dangling connections fall in this group. */
|
||||||
|
|
||||||
if ((resptr->rn_te == NULL) && (resptr->rn_why != RES_NODE_ORIGIN)
|
if ((status == UNTOUCHED) && (resptr->rn_te == NULL) &&
|
||||||
&& (status == UNTOUCHED))
|
!(resptr->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK)))
|
||||||
status = ResSeriesCheck(resptr);
|
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);
|
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);
|
status = ResTriangleCheck(resptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,14 +152,6 @@ ResFixRes(resptr, resptr2, resptr3, elimResis, newResis)
|
||||||
ASSERT(newResis->rr_value > 0, "series");
|
ASSERT(newResis->rr_value > 0, "series");
|
||||||
newResis->rr_float.rr_area += elimResis->rr_float.rr_area;
|
newResis->rr_float.rr_area += elimResis->rr_float.rr_area;
|
||||||
|
|
||||||
#ifdef ARIEL
|
|
||||||
if (elimResis->rr_csArea && elimResis->rr_csArea < newResis->rr_csArea
|
|
||||||
|| newResis->rr_csArea == 0)
|
|
||||||
{
|
|
||||||
newResis->rr_csArea = elimResis->rr_csArea;
|
|
||||||
newResis->rr_tt = elimResis->rr_tt;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
for (thisREl = resptr3->rn_re; (thisREl != NULL); thisREl = thisREl->re_nextEl)
|
for (thisREl = resptr3->rn_re; (thisREl != NULL); thisREl = thisREl->re_nextEl)
|
||||||
{
|
{
|
||||||
if (thisREl->re_thisEl == elimResis)
|
if (thisREl->re_thisEl == elimResis)
|
||||||
|
|
@ -206,9 +200,6 @@ ResFixParallel(elimResis, newResis)
|
||||||
newResis->rr_value = 0;
|
newResis->rr_value = 0;
|
||||||
}
|
}
|
||||||
newResis->rr_float.rr_area += elimResis->rr_float.rr_area;
|
newResis->rr_float.rr_area += elimResis->rr_float.rr_area;
|
||||||
#ifdef ARIEL
|
|
||||||
newResis->rr_csArea += elimResis->rr_csArea;
|
|
||||||
#endif
|
|
||||||
ResDeleteResPointer(elimResis->rr_connection1, elimResis);
|
ResDeleteResPointer(elimResis->rr_connection1, elimResis);
|
||||||
ResDeleteResPointer(elimResis->rr_connection2, elimResis);
|
ResDeleteResPointer(elimResis->rr_connection2, elimResis);
|
||||||
ResEliminateResistor(elimResis, &ResResList);
|
ResEliminateResistor(elimResis, &ResResList);
|
||||||
|
|
@ -253,9 +244,9 @@ ResSeriesCheck(resptr)
|
||||||
ResEliminateResistor(rr1, &ResResList);
|
ResEliminateResistor(rr1, &ResResList);
|
||||||
ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue);
|
ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue);
|
||||||
status = SINGLE;
|
status = SINGLE;
|
||||||
if (resptr2->rn_status & RESTRUE)
|
if (resptr2->rn_status & RES_TRUE)
|
||||||
{
|
{
|
||||||
resptr2->rn_status &= ~RESTRUE;
|
resptr2->rn_status &= ~RES_TRUE;
|
||||||
ResDoneWithNode(resptr2);
|
ResDoneWithNode(resptr2);
|
||||||
}
|
}
|
||||||
resptr2 = NULL;
|
resptr2 = NULL;
|
||||||
|
|
@ -291,9 +282,9 @@ ResSeriesCheck(resptr)
|
||||||
rr1->rr_connection1 = rr2->rr_connection2;
|
rr1->rr_connection1 = rr2->rr_connection2;
|
||||||
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
|
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);
|
ResDoneWithNode(resptr2);
|
||||||
}
|
}
|
||||||
resptr2 = NULL;
|
resptr2 = NULL;
|
||||||
|
|
@ -322,9 +313,9 @@ ResSeriesCheck(resptr)
|
||||||
rr1->rr_connection1 = rr2->rr_connection1;
|
rr1->rr_connection1 = rr2->rr_connection1;
|
||||||
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
|
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);
|
ResDoneWithNode(resptr2);
|
||||||
}
|
}
|
||||||
resptr2 = NULL;
|
resptr2 = NULL;
|
||||||
|
|
@ -356,9 +347,9 @@ ResSeriesCheck(resptr)
|
||||||
rr1->rr_connection2 = rr2->rr_connection2;
|
rr1->rr_connection2 = rr2->rr_connection2;
|
||||||
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
|
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);
|
ResDoneWithNode(resptr2);
|
||||||
}
|
}
|
||||||
resptr2 = NULL;
|
resptr2 = NULL;
|
||||||
|
|
@ -387,9 +378,9 @@ ResSeriesCheck(resptr)
|
||||||
rr1->rr_connection2 = rr2->rr_connection1;
|
rr1->rr_connection2 = rr2->rr_connection1;
|
||||||
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
|
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);
|
ResDoneWithNode(resptr2);
|
||||||
}
|
}
|
||||||
resptr2 = NULL;
|
resptr2 = NULL;
|
||||||
|
|
@ -444,10 +435,10 @@ ResParallelCheck(resptr)
|
||||||
ResFixParallel(r1, r2);
|
ResFixParallel(r1, r2);
|
||||||
status = PARALLEL;
|
status = PARALLEL;
|
||||||
resptr2 = NULL;
|
resptr2 = NULL;
|
||||||
if (resptr3->rn_status & RESTRUE)
|
if (resptr3->rn_status & RES_TRUE)
|
||||||
{
|
{
|
||||||
resptr2 = resptr3;
|
resptr2 = resptr3;
|
||||||
resptr2->rn_status &= ~RESTRUE;
|
resptr2->rn_status &= ~RES_TRUE;
|
||||||
}
|
}
|
||||||
ResDoneWithNode(resptr);
|
ResDoneWithNode(resptr);
|
||||||
if (resptr2 != NULL) ResDoneWithNode(resptr2);
|
if (resptr2 != NULL) ResDoneWithNode(resptr2);
|
||||||
|
|
@ -542,8 +533,8 @@ ResTriangleCheck(resptr)
|
||||||
/* is arbitrarily assigned to the location */
|
/* is arbitrarily assigned to the location */
|
||||||
/* occupied by the first node. */
|
/* occupied by the first node. */
|
||||||
|
|
||||||
InitializeNode(n3, resptr->rn_loc.p_x, resptr->rn_loc.p_y, TRIANGLE);
|
InitializeResNode(n3, resptr->rn_loc.p_x, resptr->rn_loc.p_y, TRIANGLE);
|
||||||
n3->rn_status = FINISHED | RESTRUE | MARKED;
|
n3->rn_status = RES_FINISHED | RES_TRUE | RES_MARKED;
|
||||||
|
|
||||||
n3->rn_less = NULL;
|
n3->rn_less = NULL;
|
||||||
n3->rn_more = ResNodeList;
|
n3->rn_more = ResNodeList;
|
||||||
|
|
@ -591,13 +582,13 @@ ResTriangleCheck(resptr)
|
||||||
element->re_nextEl = n3->rn_re;
|
element->re_nextEl = n3->rn_re;
|
||||||
element->re_thisEl = rr3;
|
element->re_thisEl = rr3;
|
||||||
n3->rn_re = element;
|
n3->rn_re = element;
|
||||||
if ((n1->rn_status & RESTRUE) == RESTRUE)
|
if ((n1->rn_status & RES_TRUE) == RES_TRUE)
|
||||||
n1->rn_status &= ~RESTRUE;
|
n1->rn_status &= ~RES_TRUE;
|
||||||
else
|
else
|
||||||
n1 = NULL;
|
n1 = NULL;
|
||||||
|
|
||||||
if ((n2->rn_status & RESTRUE) == RESTRUE)
|
if ((n2->rn_status & RES_TRUE) == RES_TRUE)
|
||||||
n2->rn_status &= ~RESTRUE;
|
n2->rn_status &= ~RES_TRUE;
|
||||||
else
|
else
|
||||||
n2 = NULL;
|
n2 = NULL;
|
||||||
|
|
||||||
|
|
@ -648,15 +639,18 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
||||||
return;
|
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)
|
if (node2->rn_why & RES_NODE_ORIGIN)
|
||||||
node1->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 */
|
/* set node resistance */
|
||||||
if (node1->rn_noderes > node2->rn_noderes)
|
if (node1->rn_noderes > node2->rn_noderes)
|
||||||
{
|
{
|
||||||
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);
|
ResRemoveFromQueue(node1, pendingList);
|
||||||
ResAddToQueue(node1, pendingList);
|
ResAddToQueue(node1, pendingList);
|
||||||
|
|
@ -665,37 +659,22 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
||||||
node1->rn_float.rn_area += node2->rn_float.rn_area;
|
node1->rn_float.rn_area += node2->rn_float.rn_area;
|
||||||
|
|
||||||
/* combine relevant flags */
|
/* combine relevant flags */
|
||||||
node1->rn_status |= (node2->rn_status & RN_MAXTDI);
|
node1->rn_status |= (node2->rn_status & RES_MAXTDI);
|
||||||
|
|
||||||
/* merge device lists */
|
/* merge device lists */
|
||||||
workingDev = node2->rn_te;
|
workingDev = node2->rn_te;
|
||||||
while (workingDev != NULL)
|
while (workingDev != NULL)
|
||||||
{
|
{
|
||||||
if (workingDev->te_thist->rd_status & RES_DEV_PLUG)
|
int j;
|
||||||
{
|
|
||||||
ResPlug *plug = (ResPlug *) workingDev->te_thist;
|
|
||||||
if (plug->rpl_node == node2)
|
|
||||||
plug->rpl_node = node1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TxError("Bad plug node: is (%d %d), should be (%d %d)\n",
|
|
||||||
plug->rpl_node->rn_loc.p_x, plug->rpl_node->rn_loc.p_y,
|
|
||||||
node2->rn_loc.p_x, node2->rn_loc.p_y);
|
|
||||||
plug->rpl_node = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int j;
|
|
||||||
|
|
||||||
for (j = 0; j != workingDev->te_thist->rd_nterms; j++)
|
for (j = 0; j != workingDev->te_thist->rd_nterms; j++)
|
||||||
if (workingDev->te_thist->rd_terminals[j] == node2)
|
if (workingDev->te_thist->rd_terminals[j] == node2)
|
||||||
workingDev->te_thist->rd_terminals[j] = node1;
|
workingDev->te_thist->rd_terminals[j] = node1;
|
||||||
}
|
|
||||||
tDev = workingDev;
|
tDev = workingDev;
|
||||||
workingDev = workingDev->te_nextt;
|
workingDev = workingDev->te_nextt;
|
||||||
tDev->te_nextt = node1->rn_te;
|
tDev->te_nextt = node1->rn_te;
|
||||||
node1->rn_te = tDev;
|
node1->rn_te = tDev;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* append junction lists */
|
/* append junction lists */
|
||||||
|
|
@ -706,13 +685,13 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
||||||
tJunc = workingJunc;
|
tJunc = workingJunc;
|
||||||
for (i = 0; i < TILES_PER_JUNCTION; i++)
|
for (i = 0; i < TILES_PER_JUNCTION; i++)
|
||||||
{
|
{
|
||||||
tileJunk *junk;
|
resInfo *info;
|
||||||
|
|
||||||
tile = tJunc->je_thisj->rj_Tile[i];
|
tile = tJunc->je_thisj->rj_Tile[i];
|
||||||
junk = (tileJunk *) TiGetClientPTR(tile);
|
info = (resInfo *) TiGetClientPTR(tile);
|
||||||
|
|
||||||
if ((junk->tj_status & RES_TILE_DONE) == FALSE)
|
if ((info->ri_status & RES_TILE_DONE) == FALSE)
|
||||||
ResFixBreakPoint(&junk->breakList, node2, node1);
|
ResFixBreakPoint(&info->breakList, node2, node1);
|
||||||
}
|
}
|
||||||
tJunc->je_thisj->rj_jnode = node1;
|
tJunc->je_thisj->rj_jnode = node1;
|
||||||
workingJunc = workingJunc->je_nextj;
|
workingJunc = workingJunc->je_nextj;
|
||||||
|
|
@ -729,13 +708,13 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
||||||
{
|
{
|
||||||
if (workingCon->ce_thisc->cp_cnode[i] == node2)
|
if (workingCon->ce_thisc->cp_cnode[i] == node2)
|
||||||
{
|
{
|
||||||
tileJunk *junk;
|
resInfo *info;
|
||||||
|
|
||||||
workingCon->ce_thisc->cp_cnode[i] = node1;
|
workingCon->ce_thisc->cp_cnode[i] = node1;
|
||||||
tile =tCon->ce_thisc->cp_tile[i];
|
tile =tCon->ce_thisc->cp_tile[i];
|
||||||
junk = (tileJunk *) TiGetClientPTR(tile);
|
info = (resInfo *) TiGetClientPTR(tile);
|
||||||
if ((junk->tj_status & RES_TILE_DONE) == FALSE)
|
if ((info->ri_status & RES_TILE_DONE) == FALSE)
|
||||||
ResFixBreakPoint(&junk->breakList, node2, node1);
|
ResFixBreakPoint(&info->breakList, node2, node1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
workingCon = workingCon->ce_nextc;
|
workingCon = workingCon->ce_nextc;
|
||||||
|
|
@ -749,11 +728,11 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
||||||
else if ((node2->rn_name != NULL) && (node2->rn_name != node1->rn_name))
|
else if ((node2->rn_name != NULL) && (node2->rn_name != node1->rn_name))
|
||||||
{
|
{
|
||||||
HashEntry *entry;
|
HashEntry *entry;
|
||||||
ResSimNode *node;
|
ResExtNode *node;
|
||||||
|
|
||||||
/* Check if node2 is a port */
|
/* Check if node2 is a port */
|
||||||
entry = HashFind(&ResNodeTable, node2->rn_name);
|
entry = HashFind(&ResNodeTable, node2->rn_name);
|
||||||
node = (ResSimNode *)HashGetValue(entry);
|
node = (ResExtNode *)HashGetValue(entry);
|
||||||
if (node && (node->status & PORTNODE))
|
if (node && (node->status & PORTNODE))
|
||||||
node1->rn_name = node2->rn_name;
|
node1->rn_name = node2->rn_name;
|
||||||
}
|
}
|
||||||
|
|
@ -775,7 +754,7 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
||||||
tRes->re_nextEl = node1->rn_re;
|
tRes->re_nextEl = node1->rn_re;
|
||||||
node1->rn_re = tRes;
|
node1->rn_re = tRes;
|
||||||
}
|
}
|
||||||
if ((node2->rn_status & FINISHED) == FINISHED)
|
if ((node2->rn_status & RES_FINISHED) == RES_FINISHED)
|
||||||
ResRemoveFromQueue(node2, doneList);
|
ResRemoveFromQueue(node2, doneList);
|
||||||
else
|
else
|
||||||
ResRemoveFromQueue(node2, pendingList);
|
ResRemoveFromQueue(node2, pendingList);
|
||||||
|
|
@ -885,7 +864,7 @@ ResEliminateResistor(resistor, homelist)
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* ResCleanNode--removes the linked lists of junctions and contacts after
|
* 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.
|
* the node is eradicated.
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
|
|
@ -897,9 +876,9 @@ ResEliminateResistor(resistor, homelist)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
ResCleanNode(resptr, junk, homelist1, homelist2)
|
ResCleanNode(resptr, info, homelist1, homelist2)
|
||||||
resNode *resptr;
|
resNode *resptr;
|
||||||
int junk;
|
int info;
|
||||||
resNode **homelist1;
|
resNode **homelist1;
|
||||||
resNode **homelist2;
|
resNode **homelist2;
|
||||||
{
|
{
|
||||||
|
|
@ -922,7 +901,7 @@ ResCleanNode(resptr, junk, homelist1, homelist2)
|
||||||
freeMagic((char *)jcell->je_thisj);
|
freeMagic((char *)jcell->je_thisj);
|
||||||
freeMagic((char *)jcell);
|
freeMagic((char *)jcell);
|
||||||
}
|
}
|
||||||
if (junk == TRUE)
|
if (info == TRUE)
|
||||||
{
|
{
|
||||||
if (resptr->rn_client != (ClientData)NULL)
|
if (resptr->rn_client != (ClientData)NULL)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
#include "database/database.h"
|
#include "database/database.h"
|
||||||
#include "utils/malloc.h"
|
#include "utils/malloc.h"
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
|
#include "extflat/extparse.h"
|
||||||
#include "extract/extract.h"
|
#include "extract/extract.h"
|
||||||
#include "extract/extractInt.h"
|
#include "extract/extractInt.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
|
|
@ -32,9 +33,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
#define MAXNAME 1000
|
#define MAXNAME 1000
|
||||||
#define KV_TO_mV 1000000
|
#define KV_TO_mV 1000000
|
||||||
|
|
||||||
extern ResSimNode *ResInitializeNode();
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -57,7 +55,7 @@ ResPrintExtRes(outextfile, resistors, nodename)
|
||||||
int nodenum=0;
|
int nodenum=0;
|
||||||
char newname[MAXNAME];
|
char newname[MAXNAME];
|
||||||
HashEntry *entry;
|
HashEntry *entry;
|
||||||
ResSimNode *node, *ResInitializeNode();
|
ResExtNode *node;
|
||||||
|
|
||||||
for (; resistors != NULL; resistors = resistors->rr_nextResistor)
|
for (; resistors != NULL; resistors = resistors->rr_nextResistor)
|
||||||
{
|
{
|
||||||
|
|
@ -72,7 +70,7 @@ ResPrintExtRes(outextfile, resistors, nodename)
|
||||||
{
|
{
|
||||||
(void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++);
|
(void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++);
|
||||||
entry = HashFind(&ResNodeTable, newname);
|
entry = HashFind(&ResNodeTable, newname);
|
||||||
node = ResInitializeNode(entry);
|
node = ResExtInitNode(entry);
|
||||||
resistors->rr_connection1->rn_name = node->name;
|
resistors->rr_connection1->rn_name = node->name;
|
||||||
node->oldname = nodename;
|
node->oldname = nodename;
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +78,7 @@ ResPrintExtRes(outextfile, resistors, nodename)
|
||||||
{
|
{
|
||||||
(void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++);
|
(void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++);
|
||||||
entry = HashFind(&ResNodeTable, newname);
|
entry = HashFind(&ResNodeTable, newname);
|
||||||
node = ResInitializeNode(entry);
|
node = ResExtInitNode(entry);
|
||||||
resistors->rr_connection2->rn_name = node->name;
|
resistors->rr_connection2->rn_name = node->name;
|
||||||
node->oldname = nodename;
|
node->oldname = nodename;
|
||||||
}
|
}
|
||||||
|
|
@ -175,13 +173,13 @@ ResPrintExtDev(outextfile, devices)
|
||||||
fprintf(outextfile, " \"%s\" %d %s",
|
fprintf(outextfile, " \"%s\" %d %s",
|
||||||
devices->gate->name,
|
devices->gate->name,
|
||||||
devices->layout->rd_length * 2,
|
devices->layout->rd_length * 2,
|
||||||
devices->rs_gattr);
|
(*devices->rs_gattr == '\0') ? "0" : devices->rs_gattr);
|
||||||
|
|
||||||
if (devices->source != NULL)
|
if (devices->source != NULL)
|
||||||
fprintf(outextfile, " \"%s\" %d %s",
|
fprintf(outextfile, " \"%s\" %d %s",
|
||||||
devices->source->name,
|
devices->source->name,
|
||||||
devices->layout->rd_width,
|
devices->layout->rd_width,
|
||||||
devices->rs_sattr);
|
(*devices->rs_sattr == '\0') ? "0" : devices->rs_sattr);
|
||||||
|
|
||||||
/* Don't write drain values for 2-terminal devices */
|
/* Don't write drain values for 2-terminal devices */
|
||||||
if (devptr->exts_deviceSDCount > 1)
|
if (devptr->exts_deviceSDCount > 1)
|
||||||
|
|
@ -189,7 +187,7 @@ ResPrintExtDev(outextfile, devices)
|
||||||
fprintf(outextfile, " \"%s\" %d %s",
|
fprintf(outextfile, " \"%s\" %d %s",
|
||||||
devices->drain->name,
|
devices->drain->name,
|
||||||
devices->layout->rd_width,
|
devices->layout->rd_width,
|
||||||
devices->rs_dattr);
|
(*devices->rs_dattr == '\0') ? "0" : devices->rs_dattr);
|
||||||
|
|
||||||
fprintf(outextfile, "\n");
|
fprintf(outextfile, "\n");
|
||||||
}
|
}
|
||||||
|
|
@ -215,13 +213,13 @@ void
|
||||||
ResPrintExtNode(outextfile, nodelist, node)
|
ResPrintExtNode(outextfile, nodelist, node)
|
||||||
FILE *outextfile;
|
FILE *outextfile;
|
||||||
resNode *nodelist;
|
resNode *nodelist;
|
||||||
ResSimNode *node;
|
ResExtNode *node;
|
||||||
{
|
{
|
||||||
char *nodename = node->name;
|
char *nodename = node->name;
|
||||||
int nodenum = 0;
|
int nodenum = 0;
|
||||||
char newname[MAXNAME+32], tmpname[MAXNAME], *cp;
|
char newname[MAXNAME+32], tmpname[MAXNAME], *cp;
|
||||||
HashEntry *entry;
|
HashEntry *entry;
|
||||||
ResSimNode *newnode, *ResInitializeNode();
|
ResExtNode *newnode;
|
||||||
bool DoKillNode = TRUE;
|
bool DoKillNode = TRUE;
|
||||||
bool NeedFix = FALSE;
|
bool NeedFix = FALSE;
|
||||||
resNode *snode;
|
resNode *snode;
|
||||||
|
|
@ -270,7 +268,7 @@ ResPrintExtNode(outextfile, nodelist, node)
|
||||||
|
|
||||||
(void)sprintf(newname, "%s%s%d", tmpname, ".n", nodenum++);
|
(void)sprintf(newname, "%s%s%d", tmpname, ".n", nodenum++);
|
||||||
entry = HashFind(&ResNodeTable, newname);
|
entry = HashFind(&ResNodeTable, newname);
|
||||||
newnode = ResInitializeNode(entry);
|
newnode = ResExtInitNode(entry);
|
||||||
snode->rn_name = newnode->name;
|
snode->rn_name = newnode->name;
|
||||||
newnode->oldname = nodename;
|
newnode->oldname = nodename;
|
||||||
}
|
}
|
||||||
|
|
@ -290,6 +288,13 @@ ResPrintExtNode(outextfile, nodelist, node)
|
||||||
|
|
||||||
if (NeedFix)
|
if (NeedFix)
|
||||||
{
|
{
|
||||||
|
if (nodelist == NULL)
|
||||||
|
{
|
||||||
|
TxError("Error: Orphaned node \"%s\" not output.\n",
|
||||||
|
node->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Patch up the output netlist for an orphaned node by
|
/* Patch up the output netlist for an orphaned node by
|
||||||
* creating a zero-valued resistance between it and the
|
* creating a zero-valued resistance between it and the
|
||||||
* first subnode (arbitrary connection). Flag a warning.
|
* first subnode (arbitrary connection). Flag a warning.
|
||||||
|
|
@ -316,16 +321,16 @@ ResPrintExtNode(outextfile, nodelist, node)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
ResPrintStats(goodies, name)
|
ResPrintStats(resisdata, name)
|
||||||
ResGlobalParams *goodies;
|
ResisData *resisdata;
|
||||||
char *name;
|
char *name;
|
||||||
{
|
{
|
||||||
static int totalnets = 0, totalnodes = 0, totalresistors = 0;
|
static int totalnets = 0, totalnodes = 0, totalresistors = 0;
|
||||||
int nodes, resistors;
|
int nodes, resistors;
|
||||||
resNode *node;
|
resNode *node;
|
||||||
resResistor *res;
|
resResistor *res;
|
||||||
|
|
||||||
if (goodies == NULL)
|
if (resisdata == NULL)
|
||||||
{
|
{
|
||||||
TxError("nets:%d nodes:%d resistors:%d\n",
|
TxError("nets:%d nodes:%d resistors:%d\n",
|
||||||
totalnets, totalnodes, totalresistors);
|
totalnets, totalnodes, totalresistors);
|
||||||
|
|
@ -411,16 +416,16 @@ ResPrintFHNodes(fp, nodelist, nodename, nidx, celldef)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
HashEntry *entry;
|
HashEntry *entry;
|
||||||
ResSimNode *simnode;
|
ResExtNode *extnode;
|
||||||
|
|
||||||
/* If we process another sim file node while doing this */
|
/* If we process another sim file node while doing this */
|
||||||
/* one, mark it as status "REDUNDANT" so we don't duplicate */
|
/* one, mark it as status "REDUNDANT" so we don't duplicate */
|
||||||
/* the entry. */
|
/* the entry. */
|
||||||
|
|
||||||
entry = HashFind(&ResNodeTable, nodeptr->rn_name);
|
entry = HashFind(&ResNodeTable, nodeptr->rn_name);
|
||||||
simnode = (ResSimNode *)HashGetValue(entry);
|
extnode = (ResExtNode *)HashGetValue(entry);
|
||||||
if (simnode != NULL)
|
if (extnode != NULL)
|
||||||
simnode->status |= REDUNDANT;
|
extnode->status |= REDUNDANT;
|
||||||
}
|
}
|
||||||
resWriteNodeName(fp, nodeptr);
|
resWriteNodeName(fp, nodeptr);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,684 @@
|
||||||
|
|
||||||
|
#ifndef lint
|
||||||
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResReadExt.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* ResReadExt.c -- Routines to parse .ext files for information needed
|
||||||
|
* by extresist.
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "utils/magic.h"
|
||||||
|
#include "utils/main.h"
|
||||||
|
#include "utils/geometry.h"
|
||||||
|
#include "utils/geofast.h"
|
||||||
|
#include "tiles/tile.h"
|
||||||
|
#include "utils/hash.h"
|
||||||
|
#include "database/database.h"
|
||||||
|
#include "utils/malloc.h"
|
||||||
|
#include "textio/textio.h"
|
||||||
|
#include "extract/extract.h"
|
||||||
|
#include "extract/extractInt.h"
|
||||||
|
#include "extflat/extflat.h"
|
||||||
|
#include "extflat/extparse.h"
|
||||||
|
#include "windows/windows.h"
|
||||||
|
#include "dbwind/dbwind.h"
|
||||||
|
#include "utils/utils.h"
|
||||||
|
#include "utils/tech.h"
|
||||||
|
#include "textio/txcommands.h"
|
||||||
|
#include "resis/resis.h"
|
||||||
|
|
||||||
|
/* constants defining where various fields can be found in .ext files. */
|
||||||
|
/* The value corresponds to the argument number on the list after */
|
||||||
|
/* parsing by efReadLine(). */
|
||||||
|
|
||||||
|
#define FET_NAME 1
|
||||||
|
#define FET_X 2
|
||||||
|
#define FET_Y 3
|
||||||
|
#define FET_AREA 4
|
||||||
|
#define FET_PERIM 5
|
||||||
|
#define FET_SUBS 6
|
||||||
|
#define FET_GATE 7
|
||||||
|
#define FET_GATE_ATTR 9
|
||||||
|
#define FET_SOURCE 10
|
||||||
|
#define FET_SOURCE_ATTR 12
|
||||||
|
#define FET_DRAIN 13
|
||||||
|
#define FET_DRAIN_ATTR 15
|
||||||
|
|
||||||
|
#define DEV_NAME 2
|
||||||
|
#define DEV_X 3
|
||||||
|
#define DEV_Y 4
|
||||||
|
#define DEV_PARAM_START 7
|
||||||
|
|
||||||
|
#define NODES_NODENAME 1
|
||||||
|
#define NODES_NODEX 4
|
||||||
|
#define NODES_NODEY 5
|
||||||
|
#define NODES_NODETYPE 6
|
||||||
|
|
||||||
|
#define COUPLETERMINAL1 1
|
||||||
|
#define COUPLETERMINAL2 2
|
||||||
|
#define COUPLEVALUE 3
|
||||||
|
|
||||||
|
#define RES_EXT_ATTR_NAME 1
|
||||||
|
#define RES_EXT_ATTR_X 2
|
||||||
|
#define RES_EXT_ATTR_Y 3
|
||||||
|
#define RES_EXT_ATTR_TYPE 6
|
||||||
|
#define RES_EXT_ATTR_TEXT 7
|
||||||
|
|
||||||
|
#define PORT_NAME 1
|
||||||
|
#define PORT_LLX 3
|
||||||
|
#define PORT_LLY 4
|
||||||
|
#define PORT_URX 5
|
||||||
|
#define PORT_URY 6
|
||||||
|
#define PORT_TYPE 7
|
||||||
|
|
||||||
|
#define MAXDIGIT 20
|
||||||
|
|
||||||
|
ResExtNode *ResOriginalNodes; /*Linked List of Nodes */
|
||||||
|
char RDEV_NOATTR[1] = {'0'};
|
||||||
|
ResFixPoint *ResFixList;
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* ResReadExt--
|
||||||
|
*
|
||||||
|
* Results: returns 0 if ext file is correct, 1 if not.
|
||||||
|
*
|
||||||
|
* Side Effects:Reads in ExtTable and makes a hash table of nodes.
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ResReadExt(CellDef *def)
|
||||||
|
{
|
||||||
|
char *line = NULL, *argv[128];
|
||||||
|
int result, locresult;
|
||||||
|
int argc, n, size = 0;
|
||||||
|
FILE *fp;
|
||||||
|
CellDef *dbdef;
|
||||||
|
ResExtNode *curnode;
|
||||||
|
|
||||||
|
/* Search for the .ext file in the same way that efReadDef() does. */
|
||||||
|
|
||||||
|
fp = ExtFileOpen(def, (char *)NULL, "r", (char **)NULL);
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
TxError("Cannot open file %s%s\n", def->cd_name, ".ext");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read in the file. Makes use of various functions
|
||||||
|
* from extflat, mostly in EFread.c.
|
||||||
|
*/
|
||||||
|
|
||||||
|
EFSaveLocs = FALSE;
|
||||||
|
efReadLineNum = 0;
|
||||||
|
result = 0;
|
||||||
|
|
||||||
|
while ((argc = efReadLine(&line, &size, fp, argv)) >= 0)
|
||||||
|
{
|
||||||
|
n = LookupStruct(argv[0], (const LookupTable *)keyTable, sizeof keyTable[0]);
|
||||||
|
if (n < 0)
|
||||||
|
{
|
||||||
|
efReadError("Unrecognized token \"%s\" (ignored)\n", argv[0]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (argc < keyTable[n].k_mintokens)
|
||||||
|
{
|
||||||
|
efReadError("Not enough tokens for %s line\n", argv[0]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We don't care about most tokens, only DEVICE, NODE, PORT,
|
||||||
|
* and SUBSTRATE; and MERGE is used to locate drive points.
|
||||||
|
*/
|
||||||
|
switch (keyTable[n].k_key)
|
||||||
|
{
|
||||||
|
case SCALE:
|
||||||
|
/* NOTE: Currently the code assumes that the .ext
|
||||||
|
* file is read back immediately and has the same
|
||||||
|
* scale values currently in the extraction style.
|
||||||
|
* However, this should be style-independent and
|
||||||
|
* scale values should be read back and used.
|
||||||
|
* (to be completed).
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
case DEVICE:
|
||||||
|
locresult = ResReadDevice(argc, argv);
|
||||||
|
break;
|
||||||
|
case FET:
|
||||||
|
locresult = ResReadFET(argc, argv);
|
||||||
|
break;
|
||||||
|
case MERGE:
|
||||||
|
/* To be completed */
|
||||||
|
/* ResReadDrivePoint(argc, argv); */
|
||||||
|
break;
|
||||||
|
case NODE:
|
||||||
|
case SUBSTRATE:
|
||||||
|
curnode = ResReadNode(argc, argv);
|
||||||
|
break;
|
||||||
|
case PORT:
|
||||||
|
locresult = ResReadPort(argc, argv);
|
||||||
|
break;
|
||||||
|
case ATTR:
|
||||||
|
locresult = ResReadAttribute(curnode, argc, argv);
|
||||||
|
break;
|
||||||
|
case CAP:
|
||||||
|
locresult = ResReadCapacitor(argc, argv);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (locresult == 1) result = 1;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* ResReadNode-- Reads in a node statement, puts location and type of
|
||||||
|
* node into a node structure.
|
||||||
|
*
|
||||||
|
* Results: Pointer to the node record if the node was read correctly,
|
||||||
|
* NULL otherwise.
|
||||||
|
*
|
||||||
|
* Side Effects: see above
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
ResExtNode *
|
||||||
|
ResReadNode(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
HashEntry *entry;
|
||||||
|
ResExtNode *node;
|
||||||
|
|
||||||
|
entry = HashFind(&ResNodeTable, argv[NODES_NODENAME]);
|
||||||
|
node = ResExtInitNode(entry);
|
||||||
|
|
||||||
|
node->location.p_x = atoi(argv[NODES_NODEX]);
|
||||||
|
node->location.p_y = atoi(argv[NODES_NODEY]);
|
||||||
|
|
||||||
|
/* If this node was previously read as a port, then don't change the
|
||||||
|
* node type, which is tracking the type at the drivepoint.
|
||||||
|
*/
|
||||||
|
if (!(node->status & PORTNODE))
|
||||||
|
{
|
||||||
|
node->type = DBTechNameType(argv[NODES_NODETYPE]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type == -1)
|
||||||
|
{
|
||||||
|
TxError("Bad tile type name in .ext file for node %s\n", node->name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* ResReadPort-- Reads in a port statement from the .ext file and sets
|
||||||
|
* node records accordingly to mark the node as a drivepoint.
|
||||||
|
*
|
||||||
|
* Results: 0 if successful and 1 otherwise.
|
||||||
|
*
|
||||||
|
* Side Effects: see above
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ResReadPort(int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
HashEntry *entry;
|
||||||
|
ResExtNode *node;
|
||||||
|
|
||||||
|
entry = HashFind(&ResNodeTable, argv[PORT_NAME]);
|
||||||
|
node = ResExtInitNode(entry);
|
||||||
|
|
||||||
|
node->drivepoint.p_x = atoi(argv[PORT_LLX]);
|
||||||
|
node->drivepoint.p_y = atoi(argv[PORT_LLY]);
|
||||||
|
node->status |= FORCE;
|
||||||
|
/* To do: Check for multiple ports on a net; each port needs its
|
||||||
|
* own drivepoint.
|
||||||
|
*/
|
||||||
|
node->status |= DRIVELOC | PORTNODE;
|
||||||
|
node->rs_bbox.r_ll = node->drivepoint;
|
||||||
|
node->rs_bbox.r_ur.p_x = atoi(argv[PORT_URX]);
|
||||||
|
node->rs_bbox.r_ur.p_y = atoi(argv[PORT_URY]);
|
||||||
|
node->rs_ttype = DBTechNoisyNameType(argv[PORT_TYPE]);
|
||||||
|
node->type = node->rs_ttype;
|
||||||
|
|
||||||
|
if (node->type == -1)
|
||||||
|
{
|
||||||
|
TxError("Bad tile type name in .ext file for node %s\n", node->name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* ResNodeAddDevice --
|
||||||
|
*
|
||||||
|
* Given a device and a node which connects to one of its terminals,
|
||||||
|
* add the device to the node's device list. Device type is one
|
||||||
|
* of the indexes defined by GATE, SOURCE, or DRAIN (to do: generalize
|
||||||
|
* this).
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* None.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* Allocates memory for a devPtr, adds to the node's firstDev linked
|
||||||
|
* list.
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
ResNodeAddDevice(ResExtNode *node,
|
||||||
|
RDev *device,
|
||||||
|
int termtype)
|
||||||
|
{
|
||||||
|
devPtr *tptr;
|
||||||
|
|
||||||
|
tptr = (devPtr *)mallocMagic((unsigned)(sizeof(devPtr)));
|
||||||
|
tptr->thisDev = device;
|
||||||
|
tptr->nextDev = node->firstDev;
|
||||||
|
node->firstDev = tptr;
|
||||||
|
tptr->terminal = termtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* ResReadDevice--
|
||||||
|
*
|
||||||
|
* Process a "device" line from a ext file.
|
||||||
|
*
|
||||||
|
* Results: returns 0 if line was added correctly.
|
||||||
|
*
|
||||||
|
* Side Effects: Allocates devicesl
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ResReadDevice(int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
RDev *device;
|
||||||
|
int rvalue, i, j, k;
|
||||||
|
ExtDevice *devptr;
|
||||||
|
TileType ttype;
|
||||||
|
HashEntry *entry;
|
||||||
|
ResExtNode *node;
|
||||||
|
ResValue rpersquare;
|
||||||
|
float wval;
|
||||||
|
|
||||||
|
device = (RDev *)mallocMagic((unsigned)(sizeof(RDev)));
|
||||||
|
|
||||||
|
device->status = FALSE;
|
||||||
|
device->nextDev = ResRDevList;
|
||||||
|
|
||||||
|
/* Find the device definition record corresponding to the device name */
|
||||||
|
devptr = (ExtDevice *)NULL;
|
||||||
|
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
|
||||||
|
{
|
||||||
|
for (devptr = ExtCurStyle->exts_device[ttype]; devptr;
|
||||||
|
devptr = devptr->exts_next)
|
||||||
|
if (!strcmp(devptr->exts_deviceName, argv[DEV_NAME])) break;
|
||||||
|
if (devptr != NULL) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
device->location.p_x = atoi(argv[DEV_X]);
|
||||||
|
device->location.p_y = atoi(argv[DEV_Y]);
|
||||||
|
|
||||||
|
device->rs_gattr = RDEV_NOATTR;
|
||||||
|
device->rs_sattr = RDEV_NOATTR;
|
||||||
|
device->rs_dattr = RDEV_NOATTR;
|
||||||
|
device->rs_devptr = devptr;
|
||||||
|
|
||||||
|
device->source = (ResExtNode *)NULL;
|
||||||
|
device->drain = (ResExtNode *)NULL;
|
||||||
|
device->subs = (ResExtNode *)NULL;
|
||||||
|
|
||||||
|
entry = HashLookOnly(&devptr->exts_deviceResist, "linear");
|
||||||
|
if (entry != NULL)
|
||||||
|
rpersquare = (ResValue)(spointertype)HashGetValue(entry);
|
||||||
|
else
|
||||||
|
rpersquare = (ResValue)10000.0; /* Default to a sane value */
|
||||||
|
|
||||||
|
/* For devices, the device width is in the parameter list */
|
||||||
|
wval = 0.0;
|
||||||
|
for (i = DEV_Y; i < argc; i++)
|
||||||
|
{
|
||||||
|
char *eptr;
|
||||||
|
if ((eptr = strchr(argv[i], '=')) != NULL)
|
||||||
|
{
|
||||||
|
if (*argv[i] == 'w')
|
||||||
|
sscanf(eptr + 1, "%f", &wval);
|
||||||
|
}
|
||||||
|
else if (!StrIsInt(argv[i]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == argc)
|
||||||
|
{
|
||||||
|
TxError("Bad device %s: Too few arguments in .ext file\n",
|
||||||
|
argv[DEV_NAME]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
device->resistance = wval * rpersquare; /* Channel resistance */
|
||||||
|
|
||||||
|
/* Find and record the device terminal nodes */
|
||||||
|
/* Note that this only records up to two terminals matching FET
|
||||||
|
* source and drain; it needs to be expanded to include an
|
||||||
|
* arbitrary number of terminals.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (strcmp(argv[i], "None"))
|
||||||
|
{
|
||||||
|
entry = HashFind(&ResNodeTable, argv[i]);
|
||||||
|
device->subs = (ResExtNode *)HashGetValue(entry);
|
||||||
|
ResNodeAddDevice(device->subs, device, SUBS);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
entry = HashFind(&ResNodeTable, argv[i]);
|
||||||
|
device->gate = (ResExtNode *)HashGetValue(entry);
|
||||||
|
device->rs_gattr = StrDup((char **)NULL, argv[i + 2]);
|
||||||
|
ResNodeAddDevice(device->gate, device, GATE);
|
||||||
|
i += 3;
|
||||||
|
|
||||||
|
if (i < argc - 2)
|
||||||
|
{
|
||||||
|
entry = HashFind(&ResNodeTable, argv[i]);
|
||||||
|
device->source = (ResExtNode *)HashGetValue(entry);
|
||||||
|
device->rs_sattr = StrDup((char **)NULL, argv[i + 2]);
|
||||||
|
ResNodeAddDevice(device->source, device, SOURCE);
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < argc - 2)
|
||||||
|
{
|
||||||
|
entry = HashFind(&ResNodeTable, argv[i]);
|
||||||
|
device->drain = (ResExtNode *)HashGetValue(entry);
|
||||||
|
device->rs_dattr = StrDup((char **)NULL, argv[i + 2]);
|
||||||
|
ResNodeAddDevice(device->drain, device, DRAIN);
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
if (i < argc - 2)
|
||||||
|
{
|
||||||
|
TxError("Warning: Device %s has more than 4 ports (not handled).\n",
|
||||||
|
argv[DEV_NAME]);
|
||||||
|
}
|
||||||
|
|
||||||
|
device->rs_ttype = extGetDevType(devptr->exts_deviceName);
|
||||||
|
|
||||||
|
ResRDevList = device;
|
||||||
|
device->layout = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* ResReadFET-- Processes a "fet" line from a ext file.
|
||||||
|
*
|
||||||
|
* Results: returns 0 if line was added correctly.
|
||||||
|
*
|
||||||
|
* Side Effects: Allocates devices.
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ResReadFET(int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
RDev *device;
|
||||||
|
int rvalue, i, j, k;
|
||||||
|
ExtDevice *devptr;
|
||||||
|
TileType ttype;
|
||||||
|
HashEntry *entry;
|
||||||
|
ResExtNode *node;
|
||||||
|
ResValue rpersquare;
|
||||||
|
float area, perim, wval, lval;
|
||||||
|
|
||||||
|
device = (RDev *)mallocMagic((unsigned)(sizeof(RDev)));
|
||||||
|
|
||||||
|
device->status = FALSE;
|
||||||
|
device->nextDev = ResRDevList;
|
||||||
|
|
||||||
|
/* Find the device definition record corresponding to the device name */
|
||||||
|
devptr = (ExtDevice *)NULL;
|
||||||
|
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
|
||||||
|
{
|
||||||
|
for (devptr = ExtCurStyle->exts_device[ttype]; devptr;
|
||||||
|
devptr = devptr->exts_next)
|
||||||
|
if (!strcmp(devptr->exts_deviceName, argv[FET_NAME])) break;
|
||||||
|
if (devptr != NULL) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
device->location.p_x = atoi(argv[FET_X]);
|
||||||
|
device->location.p_y = atoi(argv[FET_Y]);
|
||||||
|
|
||||||
|
device->rs_gattr = RDEV_NOATTR;
|
||||||
|
device->rs_sattr = RDEV_NOATTR;
|
||||||
|
device->rs_dattr = RDEV_NOATTR;
|
||||||
|
device->rs_devptr = devptr;
|
||||||
|
|
||||||
|
entry = HashLookOnly(&devptr->exts_deviceResist, "linear");
|
||||||
|
if (entry != NULL)
|
||||||
|
rpersquare = (ResValue)(spointertype)HashGetValue(entry);
|
||||||
|
else
|
||||||
|
rpersquare = (ResValue)10000.0; /* Default to a sane value */
|
||||||
|
|
||||||
|
/* For old-style FETs, the width is determined from area and perimeter */
|
||||||
|
area = MagAtof(argv[FET_AREA]);
|
||||||
|
perim = MagAtof(argv[FET_PERIM]);
|
||||||
|
lval = 0.5 * (perim + sqrt(perim * perim - 4 * area));
|
||||||
|
wval = area / lval;
|
||||||
|
|
||||||
|
device->resistance = wval * rpersquare; /* Channel resistance */
|
||||||
|
|
||||||
|
/* Find and record the FET terminal nodes */
|
||||||
|
|
||||||
|
entry = HashFind(&ResNodeTable, argv[FET_GATE]);
|
||||||
|
device->gate = (ResExtNode *)HashGetValue(entry);
|
||||||
|
|
||||||
|
entry = HashFind(&ResNodeTable, argv[FET_SOURCE]);
|
||||||
|
device->source = (ResExtNode *)HashGetValue(entry);
|
||||||
|
|
||||||
|
entry = HashFind(&ResNodeTable, argv[FET_DRAIN]);
|
||||||
|
device->drain = (ResExtNode *)HashGetValue(entry);
|
||||||
|
|
||||||
|
entry = HashFind(&ResNodeTable, argv[FET_SUBS]);
|
||||||
|
device->subs = (ResExtNode *)HashGetValue(entry);
|
||||||
|
|
||||||
|
device->rs_ttype = extGetDevType(devptr->exts_deviceName);
|
||||||
|
|
||||||
|
/* Copy attributes verbatim */
|
||||||
|
device->rs_gattr = StrDup((char **)NULL, argv[FET_GATE_ATTR]);
|
||||||
|
device->rs_sattr = StrDup((char **)NULL, argv[FET_SOURCE_ATTR]);
|
||||||
|
device->rs_dattr = StrDup((char **)NULL, argv[FET_DRAIN_ATTR]);
|
||||||
|
|
||||||
|
ResRDevList = device;
|
||||||
|
device->layout = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* ResReadCapacitor-- Adds the capacitance from a C line to the appropriate
|
||||||
|
* node. Coupling capacitors are added twice, moving the capacitance
|
||||||
|
* to the substrate.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* Always return 0
|
||||||
|
*
|
||||||
|
* Side Effects: modifies capacitance field of ResExtNode.
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ResReadCapacitor(int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
HashEntry *entry1, *entry2;
|
||||||
|
ResExtNode *node1, *node2;
|
||||||
|
|
||||||
|
entry1 = HashFind(&ResNodeTable, argv[COUPLETERMINAL1]);
|
||||||
|
node1 = ResExtInitNode(entry1);
|
||||||
|
|
||||||
|
if (ResOptionsFlags & ResOpt_Signal)
|
||||||
|
{
|
||||||
|
node1->capacitance += MagAtof(argv[COUPLEVALUE]);
|
||||||
|
entry2 = HashFind(&ResNodeTable, argv[COUPLETERMINAL2]);
|
||||||
|
node2 = ResExtInitNode(entry2);
|
||||||
|
node2->capacitance += MagAtof(argv[COUPLEVALUE]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry2 = HashFind(&ResNodeTable, argv[COUPLETERMINAL2]);
|
||||||
|
node2 = ResExtInitNode(entry2);
|
||||||
|
|
||||||
|
node1->cap_couple += MagAtof(argv[COUPLEVALUE]);
|
||||||
|
node2->cap_couple += MagAtof(argv[COUPLEVALUE]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* ResReadAttribute--checks to see if a node attribute is a resistance
|
||||||
|
* attribute. If it is, add it to the correct node's status flag.
|
||||||
|
* Only works with 5.0 1/line attributes
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* Return 0 to keep search going, 1 to abort
|
||||||
|
*
|
||||||
|
* Side Effects: modifies resistance field of ResExtNode
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ResReadAttribute(ResExtNode *node,
|
||||||
|
int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
char *aname, *avalue;
|
||||||
|
char digit[MAXDIGIT];
|
||||||
|
int i;
|
||||||
|
static int notwarned = TRUE;
|
||||||
|
|
||||||
|
aname = argv[RES_EXT_ATTR_NAME];
|
||||||
|
avalue = argv[RES_EXT_ATTR_TEXT];
|
||||||
|
|
||||||
|
if (strncmp(avalue, "res:skip", 8) == 0)
|
||||||
|
{
|
||||||
|
if (node->status & FORCE)
|
||||||
|
{
|
||||||
|
TxError("Warning: Node %s is both forced and skipped\n", aname);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node->status |= SKIP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strncmp(avalue, "res:force", 9) == 0)
|
||||||
|
{
|
||||||
|
if (node->status & SKIP)
|
||||||
|
TxError("Warning: Node %s is both skipped and forced \n", aname);
|
||||||
|
else
|
||||||
|
node->status |= FORCE;
|
||||||
|
}
|
||||||
|
else if (strncmp(avalue, "res:min=", 8) == 0)
|
||||||
|
{
|
||||||
|
node->status |= MINSIZE;
|
||||||
|
for (i = 0, avalue += 8; *avalue != '\0'; avalue++)
|
||||||
|
{
|
||||||
|
digit[i++] = *avalue;
|
||||||
|
}
|
||||||
|
digit[i++] = '\0';
|
||||||
|
node->minsizeres = MagAtof(digit);
|
||||||
|
}
|
||||||
|
else if (strncmp(avalue, "res:drive", 9) == 0 &&
|
||||||
|
(ResOptionsFlags & ResOpt_Signal))
|
||||||
|
{
|
||||||
|
node->drivepoint.p_x = atoi(argv[RES_EXT_ATTR_X]);
|
||||||
|
node->drivepoint.p_y = atoi(argv[RES_EXT_ATTR_Y]);
|
||||||
|
node->rs_ttype = DBTechNoisyNameType(argv[RES_EXT_ATTR_TYPE]);
|
||||||
|
node->status |= DRIVELOC;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* ResExtInitNode --
|
||||||
|
* Gets the node corresponding to a given hash table entry. If no
|
||||||
|
* such node exists, one is created.
|
||||||
|
*
|
||||||
|
* Results: Returns ResExtNode corresponding to entry.
|
||||||
|
*
|
||||||
|
* Side Effects: May allocate a new ResExtNode.
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
ResExtNode *
|
||||||
|
ResExtInitNode(entry)
|
||||||
|
HashEntry *entry;
|
||||||
|
{
|
||||||
|
ResExtNode *node;
|
||||||
|
|
||||||
|
if ((node = (ResExtNode *) HashGetValue(entry)) == NULL)
|
||||||
|
{
|
||||||
|
node = (ResExtNode *)mallocMagic((unsigned)(sizeof(ResExtNode)));
|
||||||
|
HashSetValue(entry, (char *) node);
|
||||||
|
node->nextnode = ResOriginalNodes;
|
||||||
|
ResOriginalNodes = node;
|
||||||
|
node->status = FALSE;
|
||||||
|
node->forward = (ResExtNode *) NULL;
|
||||||
|
node->capacitance = 0;
|
||||||
|
node->cap_couple = 0;
|
||||||
|
node->resistance = 0;
|
||||||
|
node->type = 0;
|
||||||
|
node->firstDev = NULL;
|
||||||
|
node->name = entry->h_key.h_name;
|
||||||
|
node->oldname = NULL;
|
||||||
|
node->drivepoint.p_x = INFINITY;
|
||||||
|
node->drivepoint.p_y = INFINITY;
|
||||||
|
node->location.p_x = INFINITY;
|
||||||
|
node->location.p_y = INFINITY;
|
||||||
|
}
|
||||||
|
while (node->status & FORWARD)
|
||||||
|
{
|
||||||
|
node = node->forward;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue