Compare commits
44 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
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 |
|
|
@ -138,6 +138,8 @@ jobs:
|
|||
echo "BUILD_GCC_VERSION=$BUILD_GCC_VERSION" >> $GITHUB_ENV
|
||||
echo "BUILD_CLANG_VERSION=$BUILD_CLANG_VERSION" >> $GITHUB_ENV
|
||||
|
||||
sudo apt-get update
|
||||
|
||||
if [ -n "$BUILD_GCC_VERSION" ]
|
||||
then
|
||||
GCCV=$BUILD_GCC_VERSION
|
||||
|
|
|
|||
|
|
@ -33,10 +33,22 @@ jobs:
|
|||
cd emsdk
|
||||
./emsdk install latest
|
||||
./emsdk activate latest
|
||||
- name: Emscripten Diagnostic
|
||||
run: |
|
||||
source ./emsdk/emsdk_env.sh
|
||||
echo "===== gcc -dM -E - ====="
|
||||
echo | gcc -dM -E - | sort
|
||||
echo "===== g++ -dM -E - ====="
|
||||
echo | g++ -dM -E - | sort
|
||||
echo "===== emcc -dM -E - ====="
|
||||
echo | emcc -dM -E - | sort
|
||||
echo "===== em++ -dM -E - ====="
|
||||
echo | em++ -dM -E - | sort
|
||||
- name: Build
|
||||
run: |
|
||||
source ./emsdk/emsdk_env.sh
|
||||
emconfigure ./configure --without-cairo --without-opengl --without-x --disable-readline --disable-compression --target=asmjs-unknown-emscripten
|
||||
# The --without and --disable in these build options is due to no WASM library being available for that feature
|
||||
CFLAGS="--std=c17 -D_DEFAULT_SOURCE=1 -DEMSCRIPTEN=1 -g" emconfigure ./configure --without-cairo --without-opengl --without-x --without-tk --without-tcl --disable-readline --disable-compression --target=asmjs-unknown-emscripten
|
||||
echo "===== defs.mak ====="
|
||||
cat defs.mak
|
||||
echo "===== defs.mak ====="
|
||||
|
|
|
|||
|
|
@ -10,19 +10,6 @@ on:
|
|||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
vezzal:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ubuntu-latest
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
- name: Pulling the docker image
|
||||
run: docker pull vezzal/vezzal:v1
|
||||
|
||||
- name: Start the container with the docker image
|
||||
run: docker run -id --name test_magic vezzal/vezzal:v1 bash | exit
|
||||
|
||||
- name: Run the testing on the container and send the mail
|
||||
run: docker exec test_magic /vezzal/test_magic.sh "lankasaicharan123@gmail.com,tim@opencircuitdesign.com" ${{secrets.MAILING_KEY}}
|
||||
simple_build_linux:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
|
|
@ -45,10 +32,22 @@ jobs:
|
|||
cd emsdk
|
||||
./emsdk install latest
|
||||
./emsdk activate latest
|
||||
- name: Emscripten Diagnostic
|
||||
run: |
|
||||
source ./emsdk/emsdk_env.sh
|
||||
echo "===== gcc -dM -E - ====="
|
||||
echo | gcc -dM -E - | sort
|
||||
echo "===== g++ -dM -E - ====="
|
||||
echo | g++ -dM -E - | sort
|
||||
echo "===== emcc -dM -E - ====="
|
||||
echo | emcc -dM -E - | sort
|
||||
echo "===== em++ -dM -E - ====="
|
||||
echo | em++ -dM -E - | sort
|
||||
- name: Build
|
||||
run: |
|
||||
source ./emsdk/emsdk_env.sh
|
||||
emconfigure ./configure --without-cairo --without-opengl --without-x --disable-readline --disable-compression --target=asmjs-unknown-emscripten
|
||||
# The --without and --disable in these build options is due to no WASM library being available for that feature
|
||||
CFLAGS="--std=c17 -D_DEFAULT_SOURCE=1 -DEMSCRIPTEN=1 -g" emconfigure ./configure --without-cairo --without-opengl --without-x --without-tk --without-tcl --disable-readline --disable-compression --target=asmjs-unknown-emscripten
|
||||
echo "===== defs.mak ====="
|
||||
cat defs.mak
|
||||
echo "===== defs.mak ====="
|
||||
|
|
|
|||
|
|
@ -789,8 +789,8 @@ calmaElementSref(
|
|||
char *filename)
|
||||
{
|
||||
int nbytes, rtype, cols, rows, nref, n, i, savescale;
|
||||
int xlo, ylo, xhi, yhi, xsep, ysep;
|
||||
bool madeinst = FALSE;
|
||||
int xlo, ylo, xhi, yhi, xsep, ysep, angle;
|
||||
bool madeinst = FALSE, rotated = FALSE;
|
||||
char *sname = NULL;
|
||||
bool isArray = FALSE;
|
||||
bool dolookahead = FALSE;
|
||||
|
|
@ -990,6 +990,14 @@ calmaElementSref(
|
|||
refarray[2].p_x = refarray[2].p_y = 0;
|
||||
}
|
||||
|
||||
/* If the array is given an angle, then the meaning of rows and
|
||||
* columns needs to be swapped for the purpose of ignoring
|
||||
* X or Y values in the case of a 1-row or 1-column entry.
|
||||
*/
|
||||
angle = GeoTransAngle(&trans, 0);
|
||||
if ((angle == 90) || (angle == 270) || (angle == -90) || (angle == -270))
|
||||
rotated = TRUE;
|
||||
|
||||
/* If this is a cell reference, then we scale to magic coordinates
|
||||
* and place the cell in the magic database. However, if this is
|
||||
* a cell to be flattened a la "gds flatten", then we keep the GDS
|
||||
|
|
@ -1000,6 +1008,7 @@ calmaElementSref(
|
|||
* is problematic, and probably incorrect.
|
||||
*/
|
||||
|
||||
|
||||
for (n = 0; n < nref; n++)
|
||||
{
|
||||
savescale = calmaReadScale1;
|
||||
|
|
@ -1011,17 +1020,17 @@ calmaElementSref(
|
|||
* them as needed.
|
||||
*/
|
||||
|
||||
if ((n > 0) && (rows == 1))
|
||||
if ((n > 0) && ((!rotated && (rows == 1)) || (rotated && (cols == 1))))
|
||||
{
|
||||
calmaReadX(&refarray[n], 1);
|
||||
calmaSkipBytes(4);
|
||||
refarray[n].p_y = 0;
|
||||
refarray[n].p_y = refarray[0].p_y;
|
||||
}
|
||||
else if ((n > 0) && (cols == 1))
|
||||
else if ((n > 0) && ((!rotated && (cols == 1)) || (rotated && (rows == 1))))
|
||||
{
|
||||
calmaSkipBytes(4);
|
||||
calmaReadY(&refarray[n], 1);
|
||||
refarray[n].p_x = 0;
|
||||
refarray[n].p_x = refarray[0].p_x;
|
||||
}
|
||||
else
|
||||
calmaReadPoint(&refarray[n], 1);
|
||||
|
|
|
|||
182
cif/CIFgen.c
182
cif/CIFgen.c
|
|
@ -25,6 +25,7 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
|
|||
#include <stdlib.h> /* for abs() */
|
||||
#include <math.h> /* for ceil() and sqrt() */
|
||||
#include <ctype.h>
|
||||
#include <string.h> /* for strcmp() */
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
|
|
@ -5044,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;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -5095,12 +5137,13 @@ CIFGenLayer(
|
|||
CIFSquaresInfo csi;
|
||||
SearchContext scx;
|
||||
TileType ttype;
|
||||
char *netname;
|
||||
char *netname, *text;
|
||||
Label *label;
|
||||
BloatStruct bls;
|
||||
BridgeStruct brs;
|
||||
BridgeLimStruct brlims;
|
||||
BridgeData *bridge;
|
||||
BloatData *bloats;
|
||||
BloatData *bloats, locbloat;
|
||||
bool hstop = FALSE;
|
||||
PropertyRecord *proprec;
|
||||
char *propvalue;
|
||||
|
|
@ -5419,9 +5462,12 @@ CIFGenLayer(
|
|||
(ClientData)NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
TTMaskSetMask(&bls.connect, &op->co_paintMask);
|
||||
DBSrPaintArea((Tile *)NULL, cellDef->cd_planes[bloats->bl_plane],
|
||||
&TiPlaneRect, &bls.connect, cifProcessResetFunc,
|
||||
(ClientData)NULL);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
|
@ -5560,6 +5606,108 @@ CIFGenLayer(
|
|||
}
|
||||
break;
|
||||
|
||||
case CIFOP_TAGGED:
|
||||
if (hier)
|
||||
{
|
||||
hstop = TRUE; /* Stop hierarchical processing */
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find all relevant labels by text matching and then continue
|
||||
* like CIFOP_BLOATALL. CIFOP_BLOATALL uses a BloatData record
|
||||
* which is not part of CIFOP_TAGGED. Create a BloatData record
|
||||
* on the fly for each tagged area based on type, and swap it for
|
||||
* the text, so that cifBloatAllFunc believes this is actually a
|
||||
* CIFOP_BLOATALL operation. Note that we don't actually care
|
||||
* what layer the label is attached to (lab_type). We are looking
|
||||
* for labels whose lab_rect values overlap the types that are given
|
||||
* in the rule.
|
||||
*/
|
||||
|
||||
cifPlane = curPlane;
|
||||
bls.op = op;
|
||||
bls.def = cellDef;
|
||||
bls.temps = temps;
|
||||
|
||||
text = (char *)op->co_client;
|
||||
|
||||
bloats = &locbloat;
|
||||
if (!TTMaskIsZero(&op->co_cifMask))
|
||||
{
|
||||
bloats->bl_plane = -1;
|
||||
for (ttype = 0; ttype < TT_MAXTYPES; ttype++)
|
||||
{
|
||||
if (TTMaskHasType(&op->co_cifMask, ttype))
|
||||
bloats->bl_distance[ttype] = 1;
|
||||
else
|
||||
bloats->bl_distance[ttype] = 0;
|
||||
}
|
||||
}
|
||||
else if (!TTMaskIsZero(&op->co_paintMask))
|
||||
{
|
||||
int plane, pmask;
|
||||
pmask = DBTechTypesToPlanes(&op->co_paintMask);
|
||||
for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
|
||||
if (PlaneMaskHasPlane(pmask, plane))
|
||||
break;
|
||||
bloats->bl_plane = plane;
|
||||
for (ttype = 0; ttype < TT_MAXTYPES; ttype++)
|
||||
{
|
||||
if (TTMaskHasType(&op->co_paintMask, ttype))
|
||||
bloats->bl_distance[ttype] = 1;
|
||||
else
|
||||
bloats->bl_distance[ttype] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Replace the client data with the bloat record */
|
||||
op->co_client = (ClientData)bloats;
|
||||
|
||||
if (bloats->bl_plane < 0)
|
||||
{
|
||||
/* bl_plane == -1 indicates bloating into a CIF templayer, */
|
||||
/* so the only connecting type should be CIF_SOLIDTYPE. */
|
||||
TTMaskSetOnlyType(&bls.connect, CIF_SOLIDTYPE);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
TTMaskZero(&bls.connect);
|
||||
for (i = 0; i < TT_MAXTYPES; i++)
|
||||
if (bloats->bl_distance[i] != 0)
|
||||
TTMaskSetType(&bls.connect, i);
|
||||
}
|
||||
|
||||
for (label = cellDef->cd_labels; label; label = label->lab_next)
|
||||
if (!strcmp(label->lab_text, text))
|
||||
cifSrTiles(op, &label->lab_rect, cellDef, temps,
|
||||
cifBloatAllFunc, (ClientData)&bls);
|
||||
|
||||
/* Reset marked tiles */
|
||||
|
||||
if (bloats->bl_plane < 0) /* Bloat types are CIF types */
|
||||
{
|
||||
bls.temps = temps;
|
||||
for (ttype = 0; ttype < TT_MAXTYPES; ttype++, bls.temps++)
|
||||
if (bloats->bl_distance[ttype] > 0)
|
||||
(void) DBSrPaintArea((Tile *)NULL, *bls.temps, &TiPlaneRect,
|
||||
&CIFSolidBits, cifProcessResetFunc,
|
||||
(ClientData)NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
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:
|
||||
if (hier)
|
||||
{
|
||||
|
|
@ -5646,6 +5794,7 @@ CIFGenLayer(
|
|||
int n;
|
||||
char propname[512];
|
||||
char *layername = (char *)op->co_client;
|
||||
Tile *t;
|
||||
|
||||
snprintf(propname, 512, "MASKHINTS_%s", layername);
|
||||
|
||||
|
|
@ -5653,30 +5802,11 @@ CIFGenLayer(
|
|||
proprec = DBPropGet(cellDef, propname, &found);
|
||||
if (!found) break; /* No mask hints available */
|
||||
|
||||
if (proprec->prop_type == PROPERTY_TYPE_DIMENSION)
|
||||
{
|
||||
for (n = 0; n < proprec->prop_len; n += 4)
|
||||
{
|
||||
if ((n + 3) >= proprec->prop_len) break;
|
||||
|
||||
cifPlane = curPlane;
|
||||
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
|
||||
|
||||
bbox.r_xbot = proprec->prop_value.prop_integer[n];
|
||||
bbox.r_ybot = proprec->prop_value.prop_integer[n + 1];
|
||||
bbox.r_xtop = proprec->prop_value.prop_integer[n + 2];
|
||||
bbox.r_ytop = proprec->prop_value.prop_integer[n + 3];
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
ASSERT (proprec->prop_type == PROPERTY_TYPE_PLANE, "CIFGenLayer");
|
||||
t = PlaneGetHint(proprec->prop_value.prop_plane);
|
||||
DBSrPaintArea(t, proprec->prop_value.prop_plane,
|
||||
&TiPlaneRect, &CIFSolidBits,
|
||||
cifCopyPropPlaneFunc, (ClientData)curPlane);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
140
cif/CIFhier.c
140
cif/CIFhier.c
|
|
@ -209,16 +209,52 @@ typedef struct _maskHintsData
|
|||
{
|
||||
Transform *mh_trans;
|
||||
CellDef *mh_def;
|
||||
Plane *mh_plane;
|
||||
} MaskHintsData;
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifCopyMaskHintFunc --
|
||||
*
|
||||
* Callback function used by cifFlatMaskHints. Transforms a tile
|
||||
* from the original plane and paints it into the target plane,
|
||||
* both of which are properties.
|
||||
*
|
||||
* Results:
|
||||
* Zero to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* Paints geometry into the target plane.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifCopyMaskHintFunc(Tile *tile,
|
||||
TileType dinfo,
|
||||
ClientData cdata)
|
||||
{
|
||||
MaskHintsData *mhd = (MaskHintsData *)cdata;
|
||||
Rect r, newr;
|
||||
|
||||
TiToRect(tile, &r);
|
||||
|
||||
/* Transform tile area to coordinates of mhd->mh_plane and paint */
|
||||
GeoTransRect(mhd->mh_trans, &r, &newr);
|
||||
DBPaintPlane(mhd->mh_plane, &newr, CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifFlatMaskHints --
|
||||
*
|
||||
* Copy a mask hint into a flattened cell by transforming it into the
|
||||
* coordinate system of the flattened cell, and adding it to the
|
||||
* property list of the flattened cell.
|
||||
* coordinate system of the flattened cell, and painting it into the
|
||||
* property plane of the flattened cell.
|
||||
*
|
||||
* Returns:
|
||||
* 0 to keep the search going.
|
||||
|
|
@ -240,6 +276,7 @@ cifFlatMaskHints(
|
|||
bool propfound;
|
||||
int i, lastlen, numvals;
|
||||
PropertyRecord *newproprec, *oldproprec;
|
||||
Plane *plane;
|
||||
|
||||
if (!strncmp(name, "MASKHINTS_", 10))
|
||||
{
|
||||
|
|
@ -247,53 +284,24 @@ cifFlatMaskHints(
|
|||
oldproprec = (PropertyRecord *)DBPropGet(mhd->mh_def, name, &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
(oldproprec->prop_len + proprec->prop_len - 2) * sizeof(int));
|
||||
newproprec->prop_len = oldproprec->prop_len + proprec->prop_len;
|
||||
newproprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||
ASSERT(oldproprec->prop_value.prop_type == PROPERTY_TYPE_PLANE,
|
||||
"cifFlatMaskHints");
|
||||
plane = oldproprec->prop_value.prop_plane;
|
||||
}
|
||||
else
|
||||
{
|
||||
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
(proprec->prop_len - 2) * sizeof(int));
|
||||
newproprec->prop_len = proprec->prop_len;
|
||||
newproprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||
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);
|
||||
}
|
||||
|
||||
for (i = 0; i < proprec->prop_len; i += 4)
|
||||
{
|
||||
/* There should be a multiple of 4 values but avoid an array overrun
|
||||
* if not.
|
||||
*/
|
||||
if ((i + 3) >= proprec->prop_len)
|
||||
{
|
||||
TxError("MASKHINTS_%s: Expected 4 values, found only %d\n",
|
||||
name + 10, numvals);
|
||||
break;
|
||||
}
|
||||
|
||||
r.r_xbot = proprec->prop_value.prop_integer[i];
|
||||
r.r_ybot = proprec->prop_value.prop_integer[i + 1];
|
||||
r.r_xtop = proprec->prop_value.prop_integer[i + 2];
|
||||
r.r_ytop = proprec->prop_value.prop_integer[i + 3];
|
||||
|
||||
/* Transform rectangle to top level coordinates */
|
||||
GeoTransRect(mhd->mh_trans, &r, &newr);
|
||||
|
||||
newproprec->prop_value.prop_integer[i] = newr.r_xbot;
|
||||
newproprec->prop_value.prop_integer[i + 1] = newr.r_ybot;
|
||||
newproprec->prop_value.prop_integer[i + 2] = newr.r_xtop;
|
||||
newproprec->prop_value.prop_integer[i + 3] = newr.r_ytop;
|
||||
}
|
||||
|
||||
/* If there were existing entries, copy them into the new property */
|
||||
if (propfound)
|
||||
{
|
||||
for (i = 0; i < oldproprec->prop_len; i++)
|
||||
newproprec->prop_value.prop_integer[i + proprec->prop_len] =
|
||||
oldproprec->prop_value.prop_integer[i];
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
@ -304,9 +312,10 @@ cifFlatMaskHints(
|
|||
* CIFCopyMaskHints --
|
||||
*
|
||||
* Callback function to copy mask hints from one cell into another.
|
||||
* (Occasionally called as a standalone function, not as a callback.)
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
* Return 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* May modify properties in the target cell.
|
||||
|
|
@ -314,7 +323,7 @@ cifFlatMaskHints(
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
int
|
||||
CIFCopyMaskHints(
|
||||
SearchContext *scx,
|
||||
CellDef *targetDef)
|
||||
|
|
@ -324,38 +333,9 @@ CIFCopyMaskHints(
|
|||
CellDef *sourceDef = scx->scx_use->cu_def;
|
||||
mhd.mh_trans = &scx->scx_trans;
|
||||
mhd.mh_def = targetDef;
|
||||
mhd.mh_plane = (Plane *)NULL;
|
||||
|
||||
DBPropEnum(sourceDef, cifFlatMaskHints, &mhd);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifHierCopyMaskHints --
|
||||
*
|
||||
* Callback function to copy mask hints from a subcell into a flattened
|
||||
* cell, which is passed in the clientData record.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0 to keep the search alive.
|
||||
*
|
||||
* Side effects:
|
||||
* May modify properties in the flattened cell.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifHierCopyMaskHints(
|
||||
SearchContext *scx,
|
||||
ClientData clientData)
|
||||
{
|
||||
MaskHintsData mhd;
|
||||
|
||||
mhd.mh_trans = &scx->scx_trans;
|
||||
mhd.mh_def = (CellDef *)clientData;
|
||||
|
||||
DBPropEnum(scx->scx_use->cu_def, cifFlatMaskHints, &mhd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -480,7 +460,7 @@ cifHierCellFunc(
|
|||
|
||||
/* Flatten mask hints in the area of interest */
|
||||
CIFCopyMaskHints(scx, CIFComponentDef);
|
||||
DBTreeSrCells(&newscx, 0, cifHierCopyMaskHints,
|
||||
DBTreeSrCells(&newscx, 0, CIFCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
/* Set CIFErrorDef to NULL to ignore errors here... these will
|
||||
|
|
@ -808,7 +788,7 @@ CIFGenSubcells(
|
|||
cifHierCopyFunc, (ClientData) CIFTotalDef);
|
||||
/* Flatten mask hints in the area of interest */
|
||||
CIFCopyMaskHints(&scx, CIFTotalDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||
(ClientData)CIFTotalDef);
|
||||
|
||||
CIFErrorDef = def;
|
||||
|
|
@ -986,14 +966,14 @@ cifHierElementFunc(
|
|||
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFTotalDef);
|
||||
CIFCopyMaskHints(&scx, CIFTotalDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||
(ClientData)CIFTotalDef);
|
||||
|
||||
DBCellClearDef(CIFComponentDef);
|
||||
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
CIFErrorDef = (CellDef *) NULL;
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ typedef struct cifop
|
|||
* CIFOP_BRIDGELIM - Added 27/07/20---Bridge across catecorner gaps, but with limiting layers
|
||||
* CIFOP_MASKHINTS - Added 12/14/20---Add geometry from cell properties, if any.
|
||||
* CIFOP_NOTSQUARE - Added 2/26/26---Keep only geometry which is not square.
|
||||
* CIFOP_TAGGED - Added 3/11/26---Find geometry attached to the given text label
|
||||
*/
|
||||
|
||||
#define CIFOP_AND 1
|
||||
|
|
@ -174,6 +175,7 @@ typedef struct cifop
|
|||
#define CIFOP_BRIDGELIM 24
|
||||
#define CIFOP_MASKHINTS 25
|
||||
#define CIFOP_NOTSQUARE 26
|
||||
#define CIFOP_TAGGED 27
|
||||
|
||||
/* Definitions of bit fields used in the value of co_client for CIFOP_INTERACT */
|
||||
#define CIFOP_INT_NOT 0x1 /* Inverted sense (not interacting) */
|
||||
|
|
@ -338,9 +340,8 @@ extern Plane *CIFGenLayer(CIFOp *op, const Rect *area, CellDef *cellDef, CellDef
|
|||
bool hier, ClientData clientdata);
|
||||
extern void CIFInitCells(void);
|
||||
extern int cifHierCopyFunc(Tile *tile, TileType dinfo, TreeContext *cxp);
|
||||
extern int cifHierCopyMaskHints(SearchContext *scx, ClientData clientData);
|
||||
extern void CIFLoadStyle(char *stylename);
|
||||
extern void CIFCopyMaskHints(SearchContext *scx, CellDef *targetDef);
|
||||
extern int CIFCopyMaskHints(SearchContext *scx, CellDef *targetDef);
|
||||
|
||||
/* C99 compat */
|
||||
extern void CIFCoverageLayer(CellDef *rootDef, Rect *area, char *layer, bool dolist);
|
||||
|
|
|
|||
108
cif/CIFrdcl.c
108
cif/CIFrdcl.c
|
|
@ -613,7 +613,7 @@ CIFPaintCurrent(
|
|||
CIFOp *op;
|
||||
|
||||
plane = CIFGenLayer(cifCurReadStyle->crs_layers[i]->crl_ops,
|
||||
&TiPlaneRect, (CellDef *)NULL, (CellDef *)NULL,
|
||||
&TiPlaneRect, cifReadCellDef, cifReadCellDef,
|
||||
cifCurReadPlanes, FALSE, (ClientData)NULL);
|
||||
|
||||
/* Generate a paint/erase table, then paint from the CIF
|
||||
|
|
@ -718,6 +718,9 @@ CIFPaintCurrent(
|
|||
&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);
|
||||
|
|
@ -728,30 +731,29 @@ CIFPaintCurrent(
|
|||
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);
|
||||
|
||||
/* Turn all linked Rects into a mask-hints property in the
|
||||
* target cell.
|
||||
/* If there is already a mask hint plane for this layer,
|
||||
* then add to it; otherwise, create a new plane.
|
||||
*/
|
||||
proplen = 0;
|
||||
for (lsrch = lrec; lsrch; lsrch = lsrch->r_next)
|
||||
proplen += 4;
|
||||
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);
|
||||
}
|
||||
|
||||
/* If there is already a mask hint for this layer, then
|
||||
* prepend to its data.
|
||||
*/
|
||||
proporig = DBPropGet(cifReadCellDef, layername, &origfound);
|
||||
if (origfound) proplen += proporig->prop_len;
|
||||
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) *
|
||||
(proplen - 2) * sizeof(int));
|
||||
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||
proprec->prop_len = proplen;
|
||||
|
||||
proplen = 0;
|
||||
while (lrec != NULL)
|
||||
{
|
||||
lrec->r_r.r_xtop =
|
||||
|
|
@ -787,29 +789,14 @@ CIFPaintCurrent(
|
|||
(savescale / cifCurReadStyle->crs_scaleFactor);
|
||||
}
|
||||
|
||||
proprec->prop_value.prop_integer[proplen] =
|
||||
lrec->r_r.r_xbot;
|
||||
proprec->prop_value.prop_integer[proplen + 1] =
|
||||
lrec->r_r.r_ybot;
|
||||
proprec->prop_value.prop_integer[proplen + 2] =
|
||||
lrec->r_r.r_xtop;
|
||||
proprec->prop_value.prop_integer[proplen + 3] =
|
||||
lrec->r_r.r_ytop;
|
||||
DBPaintPlane(plane, &lrec->r_r, CIFPaintTable,
|
||||
(PaintUndoInfo *)NULL);
|
||||
|
||||
free_magic1_t mm1 = freeMagic1_init();
|
||||
freeMagic1(&mm1, lrec);
|
||||
lrec = lrec->r_next;
|
||||
freeMagic1_end(&mm1);
|
||||
|
||||
proplen += 4;
|
||||
}
|
||||
|
||||
if (origfound)
|
||||
for (i = 0; i < proporig->prop_len; i++)
|
||||
proprec->prop_value.prop_integer[proplen++] =
|
||||
proporig->prop_value.prop_integer[i];
|
||||
|
||||
DBPropPut(cifReadCellDef, propname, proprec);
|
||||
freeMagic(propname);
|
||||
}
|
||||
}
|
||||
|
|
@ -926,7 +913,9 @@ CIFPaintCurrent(
|
|||
(CellDef *)NULL, CIFPlanes, FALSE, (ClientData)NULL);
|
||||
|
||||
/* Scan the resulting plane and generate linked Rect structures for
|
||||
* each shape found.
|
||||
* each shape found. (To do: Remove the linked Rects and paint
|
||||
* directly into the plane in cifMaskHintFunc(), which is more
|
||||
* efficient but not hugely so.)
|
||||
*/
|
||||
DBSrPaintArea((Tile *)NULL, presult, &TiPlaneRect, &CIFSolidBits,
|
||||
cifMaskHintFunc, (ClientData)&lrec);
|
||||
|
|
@ -934,44 +923,45 @@ CIFPaintCurrent(
|
|||
if (lrec != NULL)
|
||||
{
|
||||
PropertyRecord *proprec;
|
||||
bool propfound;
|
||||
char *propname;
|
||||
int proplen;
|
||||
Plane *plane;
|
||||
|
||||
propname = (char *)mallocMagic(11 + strlen(cifReadLayers[i]));
|
||||
sprintf(propname, "MASKHINTS_%s", cifReadLayers[i]);
|
||||
|
||||
/* Turn all linked Rects into a mask-hints property in the
|
||||
* target cell.
|
||||
/* Paint all linked Rects into a mask-hints property plane
|
||||
* in the target cell.
|
||||
*/
|
||||
proplen = 0;
|
||||
for (lsrch = lrec; lsrch; lsrch = lsrch->r_next)
|
||||
proplen += 4;
|
||||
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) *
|
||||
(proplen - 2) * sizeof(int));
|
||||
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||
proprec->prop_len = proplen;
|
||||
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;
|
||||
|
||||
proplen = 0;
|
||||
while (lrec != NULL)
|
||||
{
|
||||
proprec->prop_value.prop_integer[proplen] =
|
||||
lrec->r_r.r_xbot / CIFCurStyle->cs_scaleFactor;
|
||||
proprec->prop_value.prop_integer[proplen + 1] =
|
||||
lrec->r_r.r_ybot / CIFCurStyle->cs_scaleFactor;
|
||||
proprec->prop_value.prop_integer[proplen + 2] =
|
||||
lrec->r_r.r_xtop / CIFCurStyle->cs_scaleFactor;
|
||||
proprec->prop_value.prop_integer[proplen + 3] =
|
||||
lrec->r_r.r_ytop / CIFCurStyle->cs_scaleFactor;
|
||||
lrec->r_r.r_xbot /= CIFCurStyle->cs_scaleFactor;
|
||||
lrec->r_r.r_ybot /= CIFCurStyle->cs_scaleFactor;
|
||||
lrec->r_r.r_xtop /= CIFCurStyle->cs_scaleFactor;
|
||||
lrec->r_r.r_ytop /= CIFCurStyle->cs_scaleFactor;
|
||||
|
||||
DBPaintPlane(plane, &lrec->r_r, CIFPaintTable,
|
||||
(PaintUndoInfo *)NULL);
|
||||
|
||||
free_magic1_t mm1 = freeMagic1_init();
|
||||
freeMagic1(&mm1, lrec);
|
||||
lrec = lrec->r_next;
|
||||
freeMagic1_end(&mm1);
|
||||
|
||||
proplen += 4;
|
||||
}
|
||||
DBPropPut(cifReadCellDef, propname, proprec);
|
||||
freeMagic(propname);
|
||||
}
|
||||
|
||||
|
|
@ -1796,8 +1786,8 @@ CIFReadCellCleanup(
|
|||
}
|
||||
|
||||
/* Do geometrical processing on the top-level cell. */
|
||||
if (filetype == FILE_CIF) CIFPaintCurrent(filetype);
|
||||
|
||||
CIFPaintCurrent(FILE_CIF);
|
||||
DBAdjustLabels(EditCellUse->cu_def, &TiPlaneRect);
|
||||
DBReComputeBbox(EditCellUse->cu_def);
|
||||
DBWAreaChanged(EditCellUse->cu_def, &EditCellUse->cu_def->cd_bbox,
|
||||
|
|
|
|||
|
|
@ -332,7 +332,8 @@ cifNewReadStyle(void)
|
|||
free_magic1_t mm1 = freeMagic1_init();
|
||||
for (op = layer->crl_ops; op != NULL; op = op->co_next)
|
||||
{
|
||||
if (op->co_opcode == CIFOP_MASKHINTS)
|
||||
if (op->co_opcode == CIFOP_MASKHINTS ||
|
||||
op->co_opcode == CIFOP_TAGGED)
|
||||
freeMagic((char *)op->co_client);
|
||||
freeMagic1(&mm1, (char *)op);
|
||||
}
|
||||
|
|
@ -998,6 +999,8 @@ CIFReadTechLine(
|
|||
newOp->co_opcode = CIFOP_NOTSQUARE;
|
||||
else if (strcmp(argv[0], "mask-hints") == 0)
|
||||
newOp->co_opcode = CIFOP_MASKHINTS;
|
||||
else if (strcmp(argv[0], "tagged") == 0)
|
||||
newOp->co_opcode = CIFOP_TAGGED;
|
||||
else
|
||||
{
|
||||
TechError("Unknown statement \"%s\".\n", argv[0]);
|
||||
|
|
@ -1028,6 +1031,11 @@ CIFReadTechLine(
|
|||
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. */
|
||||
|
|
|
|||
12
cif/CIFsee.c
12
cif/CIFsee.c
|
|
@ -166,9 +166,9 @@ CIFPaintLayer(
|
|||
scx.scx_use = CIFDummyUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
oldCount = DBWFeedbackCount;
|
||||
|
|
@ -287,9 +287,9 @@ CIFSeeLayer(
|
|||
scx.scx_use = CIFDummyUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
oldCount = DBWFeedbackCount;
|
||||
|
|
@ -459,9 +459,9 @@ CIFCoverageLayer(
|
|||
scx.scx_use = CIFDummyUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
||||
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||
(ClientData)CIFComponentDef);
|
||||
|
||||
CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE,
|
||||
|
|
|
|||
|
|
@ -1107,6 +1107,8 @@ CIFTechLine(
|
|||
newOp->co_opcode = CIFOP_BBOX;
|
||||
else if (strcmp(argv[0], "net") == 0)
|
||||
newOp->co_opcode = CIFOP_NET;
|
||||
else if (strcmp(argv[0], "tagged") == 0)
|
||||
newOp->co_opcode = CIFOP_TAGGED;
|
||||
else if (strcmp(argv[0], "maxrect") == 0)
|
||||
newOp->co_opcode = CIFOP_MAXRECT;
|
||||
else if (strcmp(argv[0], "boundary") == 0)
|
||||
|
|
@ -1357,6 +1359,7 @@ bloatCheck:
|
|||
bloatDone: break;
|
||||
|
||||
case CIFOP_NET:
|
||||
case CIFOP_TAGGED:
|
||||
if (argc != 3) goto wrongNumArgs;
|
||||
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
|
||||
cifParseLayers(argv[2], CIFCurStyle, &newOp->co_paintMask,
|
||||
|
|
@ -1671,12 +1674,12 @@ cifComputeRadii(
|
|||
|
||||
for (op = layer->cl_ops; op != NULL; op = op->co_next)
|
||||
{
|
||||
/* BBOX, NET, and MASKHINTS operators should never be used */
|
||||
/* hierarchically so ignore any grow/shrink operators that */
|
||||
/* BBOX, NET, TAGGED, and MASKHINTS operators should never be */
|
||||
/* used hierarchically so ignore any grow/shrink operators that */
|
||||
/* come after them. */
|
||||
|
||||
if (op->co_opcode == CIFOP_BBOX || op->co_opcode == CIFOP_NET ||
|
||||
op->co_opcode == CIFOP_MASKHINTS)
|
||||
op->co_opcode == CIFOP_TAGGED || op->co_opcode == CIFOP_MASKHINTS)
|
||||
break;
|
||||
|
||||
/* If CIF layers are used, switch to the max of current
|
||||
|
|
@ -1988,8 +1991,8 @@ CIFTechFinal(void)
|
|||
/* Presence of op->co_opcode in CIFOP_OR indicates a copy */
|
||||
/* of the SquaresData pointer from a following operator. */
|
||||
/* CIFOP_BBOX and CIFOP_MAXRECT uses the co_client field */
|
||||
/* as a flag field, while CIFOP_NET and CIFOP_MASKHINTS */
|
||||
/* uses it for a string. */
|
||||
/* as a flag field, while CIFOP_NET, CIFOP_MASKHINTS, and */
|
||||
/* CIFOP_TAGGED use it for a string. */
|
||||
else
|
||||
{
|
||||
switch (op->co_opcode)
|
||||
|
|
@ -2001,6 +2004,7 @@ CIFTechFinal(void)
|
|||
case CIFOP_MAXRECT:
|
||||
case CIFOP_MANHATTAN:
|
||||
case CIFOP_NET:
|
||||
case CIFOP_TAGGED:
|
||||
break;
|
||||
case CIFOP_BRIDGELIM:
|
||||
case CIFOP_BRIDGE:
|
||||
|
|
@ -2536,6 +2540,7 @@ CIFTechOutputScale(
|
|||
case CIFOP_MAXRECT:
|
||||
case CIFOP_MANHATTAN:
|
||||
case CIFOP_NET:
|
||||
case CIFOP_TAGGED:
|
||||
case CIFOP_INTERACT:
|
||||
break;
|
||||
case CIFOP_BRIDGELIM:
|
||||
|
|
@ -2651,8 +2656,8 @@ CIFTechOutputScale(
|
|||
default:
|
||||
/* op->co_opcode in CIFOP_OR is a pointer copy, */
|
||||
/* in CIFOP_BBOX and CIFOP_MAXRECT is a flag, */
|
||||
/* and in CIFOP_NET and CIFOP_MASKHINTS is a */
|
||||
/* string. */
|
||||
/* and in CIFOP_NET, CIFOP_MASKHINTS, and */
|
||||
/* CIFOP_TAGGED is a string. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
149
commands/CmdE.c
149
commands/CmdE.c
|
|
@ -781,39 +781,82 @@ cmdEraseCellsFunc(
|
|||
* Implement the "expand" command.
|
||||
*
|
||||
* Usage:
|
||||
* expand
|
||||
* expand toggle
|
||||
* expand [selection|surround|overlap|all] [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:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* If "toggle" is specified, flips the expanded/unexpanded status
|
||||
* of all selected cells. Otherwise, aren't any unexpanded cells
|
||||
* left under the box. May read cells in from disk, and updates
|
||||
* bounding boxes that have changed.
|
||||
* Expansion state of cells is changed. May read cells in from
|
||||
* disk, and update 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
|
||||
CmdExpand(
|
||||
MagWindow *w,
|
||||
TxCommand *cmd)
|
||||
{
|
||||
int windowMask, boxMask, d;
|
||||
int windowMask, boxMask, d, option;
|
||||
bool doToggle = FALSE;
|
||||
const char * const *msg;
|
||||
Rect rootRect;
|
||||
CellUse *rootBoxUse;
|
||||
CellDef *rootBoxDef;
|
||||
|
||||
int cmdExpandFunc(CellUse *use, int windowMask); /* Forward reference. */
|
||||
|
||||
if (cmd->tx_argc > 2 || (cmd->tx_argc == 2
|
||||
&& (strncmp(cmd->tx_argv[1], "toggle", strlen(cmd->tx_argv[1])) != 0)))
|
||||
static const char * const cmdExpandOption[] = {
|
||||
"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]);
|
||||
return;
|
||||
if (!strncmp(cmd->tx_argv[cmd->tx_argc - 1], "toggle",
|
||||
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);
|
||||
if (w == (MagWindow *) NULL)
|
||||
{
|
||||
|
|
@ -844,23 +887,95 @@ CmdExpand(
|
|||
WindScale(d, 1);
|
||||
TxPrintf("expand: rescaled by %d\n", d);
|
||||
d = DBLambda[1];
|
||||
if (cmd->tx_argc == 2) break; /* Don't toggle twice */
|
||||
if (doToggle) break; /* Don't toggle twice */
|
||||
}
|
||||
(void) ToolGetBoxWindow(&rootRect, &boxMask);
|
||||
|
||||
if (cmd->tx_argc == 2)
|
||||
SelectExpand(windowMask);
|
||||
else
|
||||
if (option != EXPAND_SELECTION)
|
||||
{
|
||||
if ((boxMask & windowMask) != windowMask)
|
||||
{
|
||||
TxError("The box isn't in the same window as the cursor.\n");
|
||||
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]);
|
||||
|
||||
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.
|
||||
|
|
|
|||
222
commands/CmdLQ.c
222
commands/CmdLQ.c
|
|
@ -45,9 +45,8 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
|
|||
#include "utils/undo.h"
|
||||
#include "select/select.h"
|
||||
#include "netmenu/netmenu.h"
|
||||
|
||||
/* C99 compat */
|
||||
#include "cif/cif.h"
|
||||
#include "cif/CIFint.h"
|
||||
|
||||
/* Forward declarations */
|
||||
|
||||
|
|
@ -518,14 +517,14 @@ CmdLoad(
|
|||
|
||||
DBExpandAll(topuse, &(topuse->cu_bbox),
|
||||
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
||||
TRUE, keepGoing, NULL);
|
||||
DB_EXPAND, keepGoing, NULL);
|
||||
|
||||
DBExpandAll(topuse, &(topuse->cu_bbox),
|
||||
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
||||
FALSE, keepGoing, NULL);
|
||||
DB_UNEXPAND, keepGoing, NULL);
|
||||
DBExpand(topuse,
|
||||
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
||||
TRUE);
|
||||
DB_EXPAND);
|
||||
|
||||
/* We don't want to save and restore DBLambda, because */
|
||||
/* loading the file may change their values. Instead, we */
|
||||
|
|
@ -2327,7 +2326,7 @@ CmdDoProperty(
|
|||
{
|
||||
PropertyRecord *proprec;
|
||||
char *value;
|
||||
bool propfound;
|
||||
bool propfound, dolist;
|
||||
int proptype, proplen, propvalue, i;
|
||||
dlong dvalue;
|
||||
int locargc = cmd->tx_argc - argstart + 1;
|
||||
|
|
@ -2335,15 +2334,31 @@ CmdDoProperty(
|
|||
Tcl_Obj *tobj;
|
||||
#endif
|
||||
|
||||
int printPropertiesFunc(); /* Forward declaration */
|
||||
/* 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", "compat", NULL
|
||||
"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.
|
||||
*/
|
||||
|
|
@ -2393,7 +2408,7 @@ CmdDoProperty(
|
|||
return;
|
||||
}
|
||||
|
||||
/* print the value of the indicated property */
|
||||
/* Print the value of the indicated property */
|
||||
proprec = (PropertyRecord *)DBPropGet(def, cmd->tx_argv[argstart], &propfound);
|
||||
if (propfound)
|
||||
{
|
||||
|
|
@ -2434,6 +2449,14 @@ CmdDoProperty(
|
|||
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,
|
||||
|
|
@ -2465,10 +2488,17 @@ CmdDoProperty(
|
|||
for (i = 0; i < proprec->prop_len; i++)
|
||||
TxPrintf("%s ", DBWPrintValue(
|
||||
proprec->prop_value.prop_integer[i], w,
|
||||
((i % 2) == 0) ? TRUE : FALSE);
|
||||
((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",
|
||||
|
|
@ -2482,9 +2512,9 @@ CmdDoProperty(
|
|||
#ifdef MAGIC_WRAPPER
|
||||
/* If the command was "cellname list property ...", then */
|
||||
/* just return NULL if the property was not found. */
|
||||
if (strcmp(cmd->tx_argv[1], "list"))
|
||||
if (!dolist)
|
||||
#endif
|
||||
TxError("Property name \"%s\" is not defined\n", cmd->tx_argv[1]);
|
||||
TxError("Property name \"%s\" is not defined\n", cmd->tx_argv[argstart]);
|
||||
}
|
||||
}
|
||||
else if (locargc >= 3)
|
||||
|
|
@ -2514,7 +2544,7 @@ CmdDoProperty(
|
|||
* keyword functions work correctly.
|
||||
*
|
||||
* GDS_START, GDS_END: PROPERTY_TYPE_DOUBLE
|
||||
* MASKHINTS_*: PROPERTY_TYPE_DIMENSION
|
||||
* MASKHINTS_*: PROPERTY_TYPE_PLANE
|
||||
* FIXED_BBOX: PROPERTY_TYPE_DIMENSION
|
||||
*/
|
||||
if (!strcmp(cmd->tx_argv[argstart], "GDS_START"))
|
||||
|
|
@ -2528,7 +2558,7 @@ CmdDoProperty(
|
|||
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_DIMENSION;
|
||||
proptype = PROPERTY_TYPE_PLANE;
|
||||
|
||||
if (strlen(cmd->tx_argv[argstart + 1]) == 0)
|
||||
DBPropPut(def, cmd->tx_argv[argstart], NULL);
|
||||
|
|
@ -2543,8 +2573,11 @@ CmdDoProperty(
|
|||
proprec->prop_len = proplen;
|
||||
strcpy(proprec->prop_value.prop_string, cmd->tx_argv[argstart + 1]);
|
||||
}
|
||||
else /* PROPERTY_TYPE_INTEGER or PROPERTY_TYPE_DIMENSION */
|
||||
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.
|
||||
|
|
@ -2555,6 +2588,12 @@ CmdDoProperty(
|
|||
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));
|
||||
|
|
@ -2587,6 +2626,28 @@ CmdDoProperty(
|
|||
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],
|
||||
|
|
@ -2601,23 +2662,32 @@ CmdDoProperty(
|
|||
* the valid number of arguments, then again to parse the
|
||||
* values, once the property record has been allocated
|
||||
*/
|
||||
value = cmd->tx_argv[argstart + 1];
|
||||
for (proplen = 0; *value != '\0'; )
|
||||
if (proptype == PROPERTY_TYPE_PLANE)
|
||||
{
|
||||
if (isspace(*value) && (*value != '\0')) value++;
|
||||
if (!isspace(*value))
|
||||
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'; )
|
||||
{
|
||||
proplen++;
|
||||
while (!isspace(*value) && (*value != '\0')) value++;
|
||||
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));
|
||||
}
|
||||
if (proplen > 0)
|
||||
{
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
(proplen - 2)*sizeof(int));
|
||||
proprec->prop_type = proptype;
|
||||
proprec->prop_len = proplen;
|
||||
}
|
||||
proprec->prop_type = proptype;
|
||||
proprec->prop_len = proplen;
|
||||
|
||||
/* Second pass */
|
||||
value = cmd->tx_argv[argstart + 1];
|
||||
for (proplen = 0; proplen < proprec->prop_len; proplen++)
|
||||
|
|
@ -2657,6 +2727,28 @@ CmdDoProperty(
|
|||
}
|
||||
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,
|
||||
|
|
@ -2727,6 +2819,59 @@ CmdProperty(
|
|||
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
|
||||
|
|
@ -2766,6 +2911,12 @@ printPropertiesFunc(
|
|||
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,
|
||||
|
|
@ -2779,25 +2930,32 @@ printPropertiesFunc(
|
|||
switch (proprec->prop_type)
|
||||
{
|
||||
case PROPERTY_TYPE_STRING:
|
||||
TxPrintf("%s = %s\n", name, (const char *)proprec->prop_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_integer[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);
|
||||
w, ((i % 2) == 0) ? TRUE : FALSE));
|
||||
TxPrintf("\n");
|
||||
break;
|
||||
case PROPERTY_TYPE_PLANE:
|
||||
TxPrintf("%s = ", name);
|
||||
DBSrPaintArea((Tile *)NULL, proprec->prop_value.prop_plane,
|
||||
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
|
||||
(ClientData)NULL);
|
||||
TxPrintf("\n");
|
||||
break;
|
||||
case PROPERTY_TYPE_DOUBLE:
|
||||
TxPrintf("%s = ", name);
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
TxPrintf("%"DLONG_PREFIX"d ", proprec->prop_double[i]);
|
||||
TxPrintf("%"DLONG_PREFIX"d ", proprec->prop_value.prop_double[i]);
|
||||
TxPrintf("\n");
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
110
commands/CmdRS.c
110
commands/CmdRS.c
|
|
@ -1801,13 +1801,18 @@ cmdLabelSizeFunc(
|
|||
|
||||
if (value == NULL)
|
||||
{
|
||||
char *labsize;
|
||||
MagWindow *w;
|
||||
|
||||
windCheckOnlyWindow(&w, DBWclientID);
|
||||
labsize = DBWPrintValue(label->lab_size / 8, w, FALSE);
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
lobj = Tcl_GetObjResult(magicinterp);
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewDoubleObj((double)label->lab_size / 8.0));
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_NewStringObj(labsize, -1));
|
||||
Tcl_SetObjResult(magicinterp, lobj);
|
||||
#else
|
||||
TxPrintf("%g\n", (double)label->lab_size / 8.0);
|
||||
TxPrintf("%s\n", labsize);
|
||||
#endif
|
||||
}
|
||||
else if (label->lab_size != *value)
|
||||
|
|
@ -1952,18 +1957,22 @@ cmdLabelOffsetFunc(
|
|||
|
||||
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
|
||||
lobj = Tcl_GetObjResult(magicinterp);
|
||||
pobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj,
|
||||
Tcl_NewDoubleObj((double)label->lab_offset.p_x / 8.0));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj,
|
||||
Tcl_NewDoubleObj((double)label->lab_offset.p_y / 8.0));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laboffx, -1));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laboffy, -1));
|
||||
Tcl_SetObjResult(magicinterp, lobj);
|
||||
#else
|
||||
TxPrintf("%g %g\n", (double)(label->lab_offset.p_x) / 8.0,
|
||||
(double)(label->lab_offset.p_y) / 8.0);
|
||||
TxPrintf("%s %s\n", laboffx, laboffy);
|
||||
#endif
|
||||
}
|
||||
else if (!GEO_SAMEPOINT(label->lab_offset, *point))
|
||||
|
|
@ -2212,9 +2221,13 @@ CmdSetLabel(
|
|||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelTextFunc, (locargc == 3) ?
|
||||
(ClientData)cmd->tx_argv[argstart + 1] : (ClientData)NULL);
|
||||
if (locargc == 2)
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelTextFunc, (ClientData)NULL);
|
||||
else
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelTextFunc,
|
||||
(ClientData)cmd->tx_argv[argstart + 1]);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -2280,9 +2293,12 @@ CmdSetLabel(
|
|||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelFontFunc, (locargc == 3) ?
|
||||
(ClientData)&font : (ClientData)NULL);
|
||||
if (locargc == 2)
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelFontFunc, (ClientData)NULL);
|
||||
else
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelFontFunc, (ClientData)&font);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -2310,9 +2326,12 @@ CmdSetLabel(
|
|||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelJustFunc, (locargc == 3) ?
|
||||
(ClientData)&pos : (ClientData)NULL);
|
||||
if (locargc == 2)
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelJustFunc, (ClientData)NULL);
|
||||
else
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelJustFunc, (ClientData)&pos);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -2341,9 +2360,12 @@ CmdSetLabel(
|
|||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelSizeFunc, (locargc == 3) ?
|
||||
(ClientData)&size : (ClientData)NULL);
|
||||
if (locargc == 2)
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelSizeFunc, (ClientData)NULL);
|
||||
else
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelSizeFunc, (ClientData)&size);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -2393,9 +2415,12 @@ CmdSetLabel(
|
|||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelOffsetFunc, (locargc != 2) ?
|
||||
(ClientData)&offset : (ClientData)NULL);
|
||||
if (locargc == 2)
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelOffsetFunc, (ClientData)NULL);
|
||||
else
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelOffsetFunc, (ClientData)&offset);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -2459,10 +2484,12 @@ CmdSetLabel(
|
|||
rect.r_ytop = cmdScaleCoord(w, cmd->tx_argv[argstart + 4],
|
||||
TRUE, FALSE, 1);
|
||||
}
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelRectFunc,
|
||||
((locargc == 6) || (locargc == 3)) ?
|
||||
(ClientData)&rect : (ClientData)NULL);
|
||||
if ((locargc == 3) || (locargc == 6))
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelRectFunc, (ClientData)&rect);
|
||||
else
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelRectFunc, (ClientData)NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -2488,9 +2515,12 @@ CmdSetLabel(
|
|||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelRotateFunc, (locargc == 3) ?
|
||||
(ClientData)&rotate : (ClientData)NULL);
|
||||
if (locargc == 2)
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelRotateFunc, (ClientData)NULL);
|
||||
else
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelRotateFunc, (ClientData)&rotate);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -2522,9 +2552,12 @@ CmdSetLabel(
|
|||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelStickyFunc, (locargc == 3) ?
|
||||
(ClientData)&flags : (ClientData)NULL);
|
||||
if (locargc == 2)
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelStickyFunc, (ClientData)NULL);
|
||||
else
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelStickyFunc, (ClientData)&flags);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -2563,9 +2596,12 @@ CmdSetLabel(
|
|||
}
|
||||
else if (EditCellUse)
|
||||
{
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelLayerFunc, (locargc == 3) ?
|
||||
(ClientData)&ttype : (ClientData)NULL);
|
||||
if (locargc == 2)
|
||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelLayerFunc, (ClientData)NULL);
|
||||
else
|
||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||
cmdLabelLayerFunc, (ClientData)&ttype);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -1239,7 +1239,7 @@ cmdExpandOneLevel(
|
|||
extern int cmdExpand1func(CellUse *cu, ClientData bitmask);
|
||||
|
||||
/* 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) */
|
||||
if (expand)
|
||||
|
|
@ -1251,7 +1251,7 @@ cmdExpand1func(
|
|||
CellUse *cu,
|
||||
ClientData bitmask)
|
||||
{
|
||||
DBExpand(cu, (int)CD2INT(bitmask), FALSE);
|
||||
DBExpand(cu, (int)CD2INT(bitmask), DB_UNEXPAND);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -702,32 +702,62 @@ CmdTool(
|
|||
* Implement the "unexpand" command.
|
||||
*
|
||||
* 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:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Unexpands all cells under the box that don't completely
|
||||
* contain the box.
|
||||
* Changes the expansion state of cells.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define UNEXPAND_SELECTION 0
|
||||
#define UNEXPAND_SURROUND 1
|
||||
#define UNEXPAND_OVERLAP 2
|
||||
#define UNEXPAND_ALL 3
|
||||
#define UNEXPAND_HELP 4
|
||||
|
||||
void
|
||||
CmdUnexpand(
|
||||
MagWindow *w,
|
||||
TxCommand *cmd)
|
||||
{
|
||||
int windowMask, boxMask;
|
||||
int windowMask, boxMask, option;
|
||||
const char * const *msg;
|
||||
Rect rootRect;
|
||||
|
||||
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]);
|
||||
return;
|
||||
option = Lookup(cmd->tx_argv[1], cmdUnexpandOption);
|
||||
if (option < 0) option = UNEXPAND_HELP;
|
||||
}
|
||||
else
|
||||
option = UNEXPAND_SURROUND;
|
||||
|
||||
if (option == UNEXPAND_HELP) goto badusage;
|
||||
|
||||
windCheckOnlyWindow(&w, DBWclientID);
|
||||
if (w == (MagWindow *) NULL)
|
||||
|
|
@ -743,8 +773,42 @@ CmdUnexpand(
|
|||
TxError("The box isn't in the same window as the cursor.\n");
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -37,9 +37,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "windows/windows.h"
|
||||
#include "dbwind/dbwind.h"
|
||||
#include "commands/commands.h"
|
||||
|
||||
/* C99 compat */
|
||||
#include "graphics/graphics.h"
|
||||
#include "cif/CIFint.h"
|
||||
|
||||
/*
|
||||
* The following variable points to the tables currently used for
|
||||
|
|
@ -357,9 +356,43 @@ DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func)
|
|||
struct propUseDefStruct {
|
||||
CellDef *puds_source;
|
||||
CellDef *puds_dest;
|
||||
Plane *puds_plane; /* Mask hint plane in dest */
|
||||
Transform *puds_trans; /* Transform from source use to dest */
|
||||
Rect *puds_area; /* Clip area in source coordinates */
|
||||
};
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* dbCopyMaskHintPlaneFunc --
|
||||
*
|
||||
* Translate tiles from a child mask-hint property plane into the
|
||||
* coordinate system of the parent, and paint the mask-hint area
|
||||
* into the mask-hint property plane of the parent.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
dbCopyMaskHintPlaneFunc(Tile *tile,
|
||||
TileType dinfo,
|
||||
struct propUseDefStruct *puds)
|
||||
{
|
||||
Transform *trans = puds->puds_trans;
|
||||
Rect *clip = puds->puds_area;
|
||||
Rect r, rnew;
|
||||
Plane *plane = puds->puds_plane;
|
||||
|
||||
TiToRect(tile, &r);
|
||||
GeoClip(&r, clip);
|
||||
if (!GEO_RECTNULL(&r))
|
||||
{
|
||||
GeoTransRect(trans, &r, &rnew);
|
||||
DBPaintPlane(plane, &rnew, CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -387,62 +420,45 @@ dbCopyMaskHintsFunc(key, proprec, puds)
|
|||
{
|
||||
CellDef *dest = puds->puds_dest;
|
||||
Transform *trans = puds->puds_trans;
|
||||
Rect *clip = puds->puds_area;
|
||||
PropertyRecord *parentproprec, *newproprec;
|
||||
char *parentprop, *newvalue, *vptr;
|
||||
Rect r, rnew;
|
||||
bool propfound;
|
||||
int i;
|
||||
int i, j;
|
||||
|
||||
if (!strncmp(key, "MASKHINTS_", 10))
|
||||
{
|
||||
char *vptr, *lastval;
|
||||
int lastlen;
|
||||
Plane *plane;
|
||||
|
||||
/* Append to existing mask hint (if any) */
|
||||
ASSERT(proprec->prop_type == PROPERTY_TYPE_PLANE, "dbCopyMaskHintsFunc");
|
||||
|
||||
/* Get the existing mask hint plane in the parent cell, and
|
||||
* create it if it does not already exist.
|
||||
*/
|
||||
parentproprec = (PropertyRecord *)DBPropGet(dest, key, &propfound);
|
||||
|
||||
if (propfound)
|
||||
{
|
||||
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
(proprec->prop_len + parentproprec->prop_len - 2) *
|
||||
sizeof(int));
|
||||
newproprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||
newproprec->prop_len = proprec->prop_len + parentproprec->prop_len;
|
||||
}
|
||||
plane = parentproprec->prop_value.prop_plane;
|
||||
else
|
||||
{
|
||||
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||
(proprec->prop_len - 2) * sizeof(int));
|
||||
newproprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||
newproprec->prop_len = proprec->prop_len;
|
||||
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||
newproprec->prop_type = PROPERTY_TYPE_PLANE;
|
||||
newproprec->prop_len = 0;
|
||||
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||
newproprec->prop_value.prop_plane = plane;
|
||||
DBPropPut(dest, key, newproprec);
|
||||
}
|
||||
puds->puds_plane = plane;
|
||||
|
||||
for (i = 0; i < proprec->prop_len; i += 4)
|
||||
{
|
||||
r.r_xbot = proprec->prop_value.prop_integer[i];
|
||||
r.r_ybot = proprec->prop_value.prop_integer[i + 1];
|
||||
r.r_xtop = proprec->prop_value.prop_integer[i + 2];
|
||||
r.r_ytop = proprec->prop_value.prop_integer[i + 3];
|
||||
|
||||
GeoTransRect(trans, &r, &rnew);
|
||||
|
||||
newproprec->prop_value.prop_integer[i] = rnew.r_xbot;
|
||||
newproprec->prop_value.prop_integer[i + 1] = rnew.r_ybot;
|
||||
newproprec->prop_value.prop_integer[i + 2] = rnew.r_xtop;
|
||||
newproprec->prop_value.prop_integer[i + 3] = rnew.r_ytop;
|
||||
}
|
||||
|
||||
if (propfound)
|
||||
{
|
||||
/* Append the original values to the end of the list */
|
||||
for (i = 0; i < parentproprec->prop_len; i++)
|
||||
newproprec->prop_value.prop_integer[i + proprec->prop_len] =
|
||||
parentproprec->prop_value.prop_integer[i];
|
||||
}
|
||||
|
||||
DBPropPut(dest, key, newproprec);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
|
@ -474,6 +490,7 @@ DBCellCopyMaskHints(child, parent, transform)
|
|||
puds.puds_source = child->cu_def;
|
||||
puds.puds_dest = parent;
|
||||
puds.puds_trans = transform;
|
||||
puds.puds_area = (Rect *)&TiPlaneRect;
|
||||
DBPropEnum(child->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
|
||||
}
|
||||
|
||||
|
|
@ -507,6 +524,7 @@ dbFlatCopyMaskHintsFunc(scx, def)
|
|||
puds.puds_source = scx->scx_use->cu_def;
|
||||
puds.puds_dest = def;
|
||||
puds.puds_trans = &scx->scx_trans;
|
||||
puds.puds_area = &scx->scx_area;
|
||||
|
||||
DBPropEnum(use->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
|
||||
|
||||
|
|
|
|||
|
|
@ -588,6 +588,25 @@ DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
|
|||
if (!DBCellRead(def, TRUE, TRUE, NULL))
|
||||
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)
|
||||
{
|
||||
if (SigInterruptPending) break;
|
||||
|
|
@ -640,6 +659,8 @@ DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
|
|||
return (1);
|
||||
}
|
||||
|
||||
if (flags & TF_LABEL_REVERSE_SEARCH) return 0; /* children already searched */
|
||||
|
||||
filter.tf_func = func;
|
||||
filter.tf_arg = cdarg;
|
||||
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. */
|
||||
|
||||
result = 0;
|
||||
|
|
@ -732,9 +763,11 @@ dbCellLabelSrFunc(scx, fp)
|
|||
}
|
||||
}
|
||||
|
||||
/* Now visit each child use recursively */
|
||||
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
|
||||
result = 1;
|
||||
/* Now visit each child use recursively, if not doing a reverse search */
|
||||
|
||||
if (!(fp->tf_flags & TF_LABEL_REVERSE_SEARCH))
|
||||
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
|
||||
result = 1;
|
||||
|
||||
cleanup:
|
||||
/* Remove the trailing pathname component from the TerminalPath */
|
||||
|
|
@ -1713,7 +1746,7 @@ dbTileMoveFunc(tile, dinfo, mvvals)
|
|||
if (IsSplit(tile))
|
||||
type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
|
||||
DBNMPaintPlane(mvvals->ptarget, exact, &targetRect,
|
||||
DBStdPaintTbl(type, mvvals->pnum),
|
||||
(mvvals->pnum < 0) ? CIFPaintTable : DBStdPaintTbl(type, mvvals->pnum),
|
||||
(PaintUndoInfo *)NULL);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1814,7 +1847,22 @@ int dbScaleProp(name, proprec, cps)
|
|||
int i, scalen, scaled;
|
||||
Point p;
|
||||
|
||||
/* Only "dimension" type properties get scaled */
|
||||
/* Only "dimension" and "plane" type properties get scaled */
|
||||
|
||||
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
|
||||
{
|
||||
Plane *newplane;
|
||||
newplane = DBNewPlane((ClientData)TT_SPACE);
|
||||
DBClearPaintPlane(newplane);
|
||||
/* Plane index is unused; arbitrarily substitute -1 */
|
||||
dbScalePlane(proprec->prop_value.prop_plane, newplane, -1,
|
||||
scalen, scaled, TRUE);
|
||||
DBFreePaintPlane(proprec->prop_value.prop_plane);
|
||||
TiFreePlane(proprec->prop_value.prop_plane);
|
||||
proprec->prop_value.prop_plane = newplane;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
|
||||
|
||||
/* Scale numerator held in point X value, */
|
||||
|
|
@ -1857,7 +1905,22 @@ int dbMoveProp(name, proprec, cps)
|
|||
char *newvalue;
|
||||
Point p;
|
||||
|
||||
/* Only "dimension" type properties get scaled */
|
||||
/* Only "dimension" and "plane" type properties get scaled */
|
||||
|
||||
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
|
||||
{
|
||||
Plane *newplane;
|
||||
|
||||
newplane = DBNewPlane((ClientData) TT_SPACE);
|
||||
DBClearPaintPlane(newplane);
|
||||
/* Use plane index -1 to indicate use of CIFPaintTable */
|
||||
dbMovePlane(proprec->prop_value.prop_plane, newplane, -1, origx, origy);
|
||||
DBFreePaintPlane(proprec->prop_value.prop_plane);
|
||||
TiFreePlane(proprec->prop_value.prop_plane);
|
||||
proprec->prop_value.prop_plane = newplane;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
|
||||
|
||||
origx = cps->cps_point.p_x;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ struct expandArg
|
|||
{
|
||||
bool ea_deref; /* TRUE if root def dereference flag is set */
|
||||
int ea_xmask; /* Expand mask. */
|
||||
int ea_type; /* Expand, unexpand, or toggle */
|
||||
int (*ea_func)(); /* Function to call for each cell whose
|
||||
* status is changed.
|
||||
*/
|
||||
|
|
@ -67,15 +68,22 @@ struct expandArg
|
|||
*/
|
||||
|
||||
void
|
||||
DBExpand(cellUse, expandMask, expandFlag)
|
||||
DBExpand(cellUse, expandMask, expandType)
|
||||
CellUse *cellUse;
|
||||
int expandMask;
|
||||
bool expandFlag;
|
||||
int expandType;
|
||||
{
|
||||
CellDef *def;
|
||||
|
||||
if (DBDescendSubcell(cellUse, expandMask) == expandFlag)
|
||||
return;
|
||||
bool expandFlag, expandTest;
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
@ -130,17 +138,17 @@ DBExpand(cellUse, expandMask, expandFlag)
|
|||
*/
|
||||
|
||||
void
|
||||
DBExpandAll(rootUse, rootRect, expandMask, expandFlag, func, cdarg)
|
||||
DBExpandAll(rootUse, rootRect, expandMask, expandType, func, cdarg)
|
||||
CellUse *rootUse; /* Root cell use from which search begins */
|
||||
Rect *rootRect; /* Area to be expanded, in root coordinates */
|
||||
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
|
||||
* status is modified. NULL means don't call anyone.
|
||||
*/
|
||||
ClientData cdarg; /* Argument to pass to func. */
|
||||
{
|
||||
int dbExpandFunc(), dbUnexpandFunc();
|
||||
int dbExpandFunc();
|
||||
SearchContext scontext;
|
||||
struct expandArg arg;
|
||||
|
||||
|
|
@ -148,29 +156,26 @@ DBExpandAll(rootUse, rootRect, expandMask, expandFlag, func, cdarg)
|
|||
(void) DBCellRead(rootUse->cu_def, TRUE, TRUE, NULL);
|
||||
|
||||
/*
|
||||
* Walk through the area and set the expansion state
|
||||
* appropriately.
|
||||
* Walk through the area and set the expansion state appropriately.
|
||||
*/
|
||||
|
||||
arg.ea_xmask = expandMask;
|
||||
arg.ea_func = func;
|
||||
arg.ea_arg = cdarg;
|
||||
arg.ea_type = expandType;
|
||||
arg.ea_deref = (rootUse->cu_def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||
|
||||
scontext.scx_use = rootUse;
|
||||
scontext.scx_trans = GeoIdentityTransform;
|
||||
scontext.scx_area = *rootRect;
|
||||
if (expandFlag)
|
||||
DBCellSrArea(&scontext, dbExpandFunc, (ClientData) &arg);
|
||||
else
|
||||
DBCellSrArea(&scontext, dbUnexpandFunc, (ClientData) &arg);
|
||||
DBCellSrArea(&scontext, dbExpandFunc, (ClientData) &arg);
|
||||
}
|
||||
|
||||
/*
|
||||
* dbExpandFunc --
|
||||
*
|
||||
* Filter function called by DBCellSrArea on behalf of DBExpandAll above
|
||||
* when cells are being expanded.
|
||||
* when cells are being expanded, unexpanded, or toggled.
|
||||
*/
|
||||
|
||||
int
|
||||
|
|
@ -184,68 +189,55 @@ dbExpandFunc(scx, arg)
|
|||
{
|
||||
CellUse *childUse = scx->scx_use;
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
if ((childUse->cu_def->cd_flags & CDAVAILABLE) == 0)
|
||||
surround = (!GEO_SURROUND(&childUse->cu_def->cd_bbox, &scx->scx_area)
|
||||
|| GEO_SURROUND(&scx->scx_area, &childUse->cu_def->cd_bbox));
|
||||
if (surround || (expandSurround == DB_EXPAND_OVERLAP))
|
||||
{
|
||||
/* If the parent is dereferenced, then the child should be, too */
|
||||
if (arg->ea_deref) childUse->cu_def->cd_flags |= CDDEREFERENCE;
|
||||
if(!DBCellRead(childUse->cu_def, TRUE, TRUE, NULL))
|
||||
/* If the cell is unavailable, then don't expand it.
|
||||
*/
|
||||
if ((childUse->cu_def->cd_flags & CDAVAILABLE) == 0)
|
||||
{
|
||||
TxError("Cell %s is unavailable. It could not be expanded.\n",
|
||||
childUse->cu_def->cd_name);
|
||||
return 2;
|
||||
/* If the parent is dereferenced, then the child should be, too */
|
||||
if (arg->ea_deref) childUse->cu_def->cd_flags |= CDDEREFERENCE;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (DBCellSrArea(scx, dbExpandFunc, (ClientData) arg))
|
||||
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))
|
||||
else if (expandTest && ((expandType == DB_UNEXPAND) ||
|
||||
(expandType == DB_EXPAND_TOGGLE)))
|
||||
{
|
||||
if (!GEO_SURROUND(&childUse->cu_def->cd_bbox, &scx->scx_area)
|
||||
|| GEO_SURROUND(&scx->scx_area, &childUse->cu_def->cd_bbox))
|
||||
surround = (!GEO_SURROUND(&childUse->cu_def->cd_bbox, &scx->scx_area)
|
||||
|| GEO_SURROUND(&scx->scx_area, &childUse->cu_def->cd_bbox));
|
||||
if (surround || (expandSurround == DB_EXPAND_OVERLAP))
|
||||
{
|
||||
childUse->cu_expandMask &= ~arg->ea_xmask;
|
||||
expandTest = FALSE;
|
||||
|
||||
/* 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. */
|
||||
|
||||
else return 2;
|
||||
|
||||
if (DBCellSrArea(scx, dbUnexpandFunc, (ClientData) arg))
|
||||
if (DBCellSrArea(scx, dbExpandFunc, (ClientData) arg))
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
|
|
|||
351
database/DBio.c
351
database/DBio.c
|
|
@ -73,10 +73,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/undo.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "utils/signals.h"
|
||||
|
||||
/* C99 compat */
|
||||
#include "dbwind/dbwtech.h"
|
||||
#include "cif/cif.h"
|
||||
#include "cif/CIFint.h"
|
||||
#include "lef/lef.h"
|
||||
#include "commands/commands.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
|
@ -2492,10 +2491,24 @@ dbReadProperties(cellDef, line, len, f, scalen, scaled)
|
|||
* (2) "integer" (a fixed integer or list of integers)
|
||||
* (3) "dimension" (an integer that scales with internal units)
|
||||
* (4) "double" (a fixed double-wide integer or list thereof)
|
||||
* (5) "plane" (a tile plane structure)
|
||||
*/
|
||||
|
||||
switch (option)
|
||||
{
|
||||
case PROPERTY_TYPE_PLANE:
|
||||
/* Treat this like "string" but make sure property is a
|
||||
* mask hint. There is currently no method to specify
|
||||
* a plane property other than to write out the bounding
|
||||
* box coordinates of all the tiles in a list.
|
||||
*/
|
||||
if (strncmp(propertyname, "MASKHINTS_", 10))
|
||||
{
|
||||
TxError("Plane type specified for property \"%s\" but "
|
||||
"property is not a mask hint!\n", propertyname);
|
||||
break;
|
||||
}
|
||||
/* Else drop through */
|
||||
case PROPERTY_TYPE_STRING:
|
||||
/* Go ahead and process the vendor GDS property */
|
||||
if (!strcmp(propertyname, "GDS_FILE"))
|
||||
|
|
@ -2565,70 +2578,65 @@ dbReadProperties(cellDef, line, len, f, scalen, scaled)
|
|||
else if (!strncmp(propertyname, "MASKHINTS_", 10))
|
||||
{
|
||||
pptr = pvalueptr;
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||
proprec->prop_type = PROPERTY_TYPE_PLANE;
|
||||
proprec->prop_len = 0;
|
||||
|
||||
/* Do one pass through the string to count the number of
|
||||
* values and make sure they all parse as integers.
|
||||
proprec->prop_value.prop_plane = DBNewPlane((ClientData)TT_SPACE);
|
||||
|
||||
/* Parse the string and convert sets of four values
|
||||
* to coordinates and paint into the plane.
|
||||
*/
|
||||
numvals = 0;
|
||||
while (*pptr != '\0')
|
||||
{
|
||||
Rect r;
|
||||
while (isspace(*pptr) && (*pptr != '\0')) pptr++;
|
||||
if (!isspace(*pptr))
|
||||
{
|
||||
char *endptr;
|
||||
long result;
|
||||
|
||||
/* Check that the value is an integer */
|
||||
result = strtol(pptr, &endptr, 0);
|
||||
if (endptr == pptr)
|
||||
if (sscanf(pptr, "%d", &ival) != 1)
|
||||
{
|
||||
/* Unable to parse correctly. Save as a string value */
|
||||
proplen = strlen(pvalueptr);
|
||||
proprec = (PropertyRecord *)mallocMagic(
|
||||
sizeof(PropertyRecord) - 7 + proplen);
|
||||
proprec->prop_type = PROPERTY_TYPE_STRING;
|
||||
proprec->prop_len = proplen;
|
||||
strcpy(proprec->prop_value.prop_string, pvalueptr);
|
||||
(void) DBPropPut(cellDef, propertyname, proprec);
|
||||
TxError("Mask-hint \"%s\" has non-integer values!",
|
||||
pptr);
|
||||
DBFreePaintPlane(proprec->prop_value.prop_plane);
|
||||
TiFreePlane(proprec->prop_value.prop_plane);
|
||||
freeMagic((char *)proprec);
|
||||
proprec = (PropertyRecord *)NULL;
|
||||
break;
|
||||
}
|
||||
while (!isspace(*pptr) && (*pptr != '\0')) pptr++;
|
||||
numvals++;
|
||||
}
|
||||
}
|
||||
if (numvals % 4 != 0)
|
||||
{
|
||||
TxError("Cannot read bounding box values in %s property",
|
||||
propertyname);
|
||||
/* This does not need to be a fatal error. Extra
|
||||
* values will be unused.
|
||||
*/
|
||||
}
|
||||
|
||||
pptr = pvalueptr;
|
||||
proprec = (PropertyRecord *)mallocMagic(
|
||||
sizeof(PropertyRecord) + ((numvals - 2) * sizeof(int)));
|
||||
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
||||
proprec->prop_len = numvals;
|
||||
|
||||
/* Do a second pass through the string to convert the values
|
||||
* to dimensions and save as an integer array.
|
||||
*/
|
||||
numvals = 0;
|
||||
while (*pptr != '\0')
|
||||
{
|
||||
while (isspace(*pptr) && (*pptr != '\0')) pptr++;
|
||||
if (!isspace(*pptr))
|
||||
{
|
||||
sscanf(pptr, "%d", &ival);
|
||||
if (scalen > 1) ival *= scalen;
|
||||
if (scaled > 1) ival /= scaled;
|
||||
proprec->prop_value.prop_integer[numvals] = ival;
|
||||
|
||||
switch (numvals)
|
||||
{
|
||||
case 0:
|
||||
r.r_xbot = ival;
|
||||
numvals++;
|
||||
break;
|
||||
case 1:
|
||||
r.r_ybot = ival;
|
||||
numvals++;
|
||||
break;
|
||||
case 2:
|
||||
r.r_xtop = ival;
|
||||
numvals++;
|
||||
break;
|
||||
case 3:
|
||||
r.r_ytop = ival;
|
||||
numvals = 0;
|
||||
/* Paint this into the plane */
|
||||
DBPaintPlane(proprec->prop_value.prop_plane,
|
||||
&r, CIFPaintTable,
|
||||
(PaintUndoInfo *)NULL);
|
||||
break;
|
||||
}
|
||||
while (!isspace(*pptr) && (*pptr != '\0')) pptr++;
|
||||
numvals++;
|
||||
}
|
||||
}
|
||||
if (numvals != 0)
|
||||
{
|
||||
TxError("Mask-hint property number of values is not"
|
||||
" divisible by four. Truncated.\n");
|
||||
}
|
||||
(void) DBPropPut(cellDef, propertyname, proprec);
|
||||
}
|
||||
else if ((!strncmp(propertyname, "GDS_START", 9)) ||
|
||||
|
|
@ -3481,6 +3489,23 @@ DBCellFindScale(cellDef)
|
|||
return ggcf;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* dbFindGCFFunc ---
|
||||
*
|
||||
* Find the greatest common factor between the current GCF and each point
|
||||
* in a tile.
|
||||
*
|
||||
* Results:
|
||||
* 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* May modify the GCF passed as client data to the function.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
dbFindGCFFunc(tile, dinfo, ggcf)
|
||||
Tile *tile;
|
||||
|
|
@ -3503,6 +3528,24 @@ dbFindGCFFunc(tile, dinfo, ggcf)
|
|||
return (*ggcf == 1) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* dbFindCellGCFFunc ---
|
||||
*
|
||||
* Find the greatest common factor between the current GCF and each point
|
||||
* of a uses bounding box, each component of the use's transform , and
|
||||
* for arrays, the array pitch.
|
||||
*
|
||||
* Results:
|
||||
* 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* May modify the GCF passed as client data to the function.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
dbFindCellGCFFunc(cellUse, ggcf)
|
||||
CellUse *cellUse; /* Cell use whose "call" is to be written to a file */
|
||||
|
|
@ -3543,6 +3586,23 @@ dbFindCellGCFFunc(cellUse, ggcf)
|
|||
return (*ggcf == 1) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* dbFindPropGCFFunc ---
|
||||
*
|
||||
* Find the greatest common factor between the current GCF and each point
|
||||
* of a dimension property, or each point of each tile in a plane property.
|
||||
*
|
||||
* Results:
|
||||
* 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* May modify the GCF passed as client data to the function.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
dbFindPropGCFFunc(key, proprec, ggcf)
|
||||
char *key;
|
||||
|
|
@ -3551,20 +3611,28 @@ dbFindPropGCFFunc(key, proprec, ggcf)
|
|||
{
|
||||
int value, n;
|
||||
|
||||
/* Only PROPERTY_TYPE_DIMENSION properties get handled */
|
||||
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
|
||||
|
||||
for (n = 0; n < proprec->prop_len; n++)
|
||||
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
|
||||
{
|
||||
value = proprec->prop_value.prop_integer[n];
|
||||
if (value % (*ggcf) != 0)
|
||||
*ggcf = FindGCF(value, *ggcf);
|
||||
if (DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||
proprec->prop_value.prop_plane,
|
||||
&TiPlaneRect, &CIFSolidBits, dbFindGCFFunc, (ClientData)ggcf))
|
||||
return (*ggcf == 1) ? 1 : 0;
|
||||
}
|
||||
|
||||
return (*ggcf == 1) ? 1 : 0;
|
||||
else if (proprec->prop_type == PROPERTY_TYPE_DIMENSION)
|
||||
{
|
||||
for (n = 0; n < proprec->prop_len; n++)
|
||||
{
|
||||
value = proprec->prop_value.prop_integer[n];
|
||||
if (value % (*ggcf) != 0)
|
||||
*ggcf = FindGCF(value, *ggcf);
|
||||
}
|
||||
return (*ggcf == 1) ? 1 : 0;
|
||||
}
|
||||
else
|
||||
/* Only PROPERTY_TYPE_PLANE and PROPERTY_TYPE_DIMENSION get handled */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -3573,6 +3641,12 @@ dbFindPropGCFFunc(key, proprec, ggcf)
|
|||
* String comparison of two instance names, for the purpose of sorting
|
||||
* the instances in a .mag file output in a repeatable way.
|
||||
*
|
||||
* Results:
|
||||
* The string comparison, equivalent to the return value of strcmp().
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -3610,6 +3684,9 @@ struct cellUseList {
|
|||
* Return value:
|
||||
* Return 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* Adds to the list of cell uses passed as client data.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -3635,6 +3712,9 @@ dbGetUseFunc(cellUse, useRec)
|
|||
* Return value:
|
||||
* Return 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* Increments the count passed as client data.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -3663,6 +3743,12 @@ struct keyValuePair {
|
|||
* String comparison of two property keys, for the purpose of sorting
|
||||
* the properties in a .mag file output in a repeatable way.
|
||||
*
|
||||
* Results:
|
||||
* The string comparison, equivalent to the result of strcmp().
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -3698,6 +3784,9 @@ struct cellPropList {
|
|||
* Return value:
|
||||
* Return 0 to keep the search going.
|
||||
*
|
||||
* Side Effects:
|
||||
* Adds to the list of property records passed as client data.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -3727,6 +3816,9 @@ dbGetPropFunc(key, proprec, propRec)
|
|||
* Return value:
|
||||
* Return 0 to keep the search going.
|
||||
*
|
||||
* Side Effects:
|
||||
* Increments the count passed as client data.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -4064,6 +4156,52 @@ ioerror:
|
|||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* dbWritePropPaintFunc --
|
||||
*
|
||||
* Transform tiles in a plane into a set of four coordinate values and output
|
||||
* them to the file. This turns plane data into a PROP_TYPE_DIMENSION array,
|
||||
* which is not a very efficient form and may be revisited. For relatively
|
||||
* simple plane data, it suffices. The property planes are single-bit types.
|
||||
* Note that there is no support for non-Manhattan geometry in the property
|
||||
* plane at this time.
|
||||
*
|
||||
* Results:
|
||||
* 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* Writes output to a file.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
dbWritePropPaintFunc(Tile *tile,
|
||||
TileType dinfo,
|
||||
ClientData cdata)
|
||||
{
|
||||
pwfrec *pwf = (pwfrec *)cdata;
|
||||
FILE *f = pwf->pwf_file;
|
||||
int reducer = pwf->pwf_reducer;
|
||||
Rect r;
|
||||
char newvalue[20];
|
||||
|
||||
TiToRect(tile, &r);
|
||||
|
||||
snprintf(newvalue, 20, " %d", r.r_xbot / reducer);
|
||||
FPUTSR(f, newvalue);
|
||||
snprintf(newvalue, 20, " %d", r.r_ybot / reducer);
|
||||
FPUTSR(f, newvalue);
|
||||
snprintf(newvalue, 20, " %d", r.r_xtop / reducer);
|
||||
FPUTSR(f, newvalue);
|
||||
snprintf(newvalue, 20, " %d", r.r_ytop / reducer);
|
||||
FPUTSR(f, newvalue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -4111,6 +4249,12 @@ dbWritePropFunc(key, proprec, cdata)
|
|||
case PROPERTY_TYPE_INTEGER:
|
||||
FPUTSR(f, "integer ");
|
||||
break;
|
||||
case PROPERTY_TYPE_PLANE:
|
||||
/* A mask hint is a plane type property; declare it
|
||||
* as a dimension, but it's arbitrary anyway since
|
||||
* the prefix "MASKHINTS_" is detected on read-in and
|
||||
* the property is parsed as plane data.
|
||||
*/
|
||||
case PROPERTY_TYPE_DIMENSION:
|
||||
FPUTSR(f, "dimension ");
|
||||
break;
|
||||
|
|
@ -4143,6 +4287,13 @@ dbWritePropFunc(key, proprec, cdata)
|
|||
FPUTSR(f, newvalue);
|
||||
}
|
||||
break;
|
||||
case PROPERTY_TYPE_PLANE:
|
||||
/* Scan the plane and output each non-space tile as four values */
|
||||
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||
proprec->prop_value.prop_plane,
|
||||
&TiPlaneRect, &CIFSolidBits, dbWritePropPaintFunc,
|
||||
(ClientData)cdata);
|
||||
break;
|
||||
case PROPERTY_TYPE_DOUBLE:
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
{
|
||||
|
|
@ -4267,7 +4418,7 @@ DBCellWriteCommandFile(cellDef, f)
|
|||
}
|
||||
else
|
||||
{
|
||||
fprintf(f, "label %s %s %d %d %d %d %s %s\n",
|
||||
fprintf(f, "label %s %s %d %d %d %d %s %s%s\n",
|
||||
lab->lab_text,
|
||||
DBFontList[lab->lab_font]->mf_name,
|
||||
lab->lab_size >> 3,
|
||||
|
|
@ -4275,15 +4426,10 @@ DBCellWriteCommandFile(cellDef, f)
|
|||
lab->lab_offset.p_x,
|
||||
lab->lab_offset.p_y,
|
||||
directionNames[lab->lab_just],
|
||||
(lab->lab_flags & LABEL_STICKY) ? "-" : "",
|
||||
DBTypeLongName(lab->lab_type));
|
||||
}
|
||||
|
||||
if (lab->lab_flags & LABEL_STICKY)
|
||||
{
|
||||
fprintf(f, "select area label\n");
|
||||
fprintf(f, "setlabel sticky true\n");
|
||||
}
|
||||
|
||||
if (lab->lab_flags & PORT_DIR_MASK)
|
||||
{
|
||||
if (!(lab->lab_flags & LABEL_STICKY))
|
||||
|
|
@ -4395,6 +4541,12 @@ ioerror:
|
|||
* Callback function used by DBCellWriteCommandFile() to output
|
||||
* commands corresponding to cell layout geometry.
|
||||
*
|
||||
* Results:
|
||||
* 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* Writes output to a file.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -4460,6 +4612,12 @@ dbWritePaintCommandsFunc(tile, dinfo, cdarg)
|
|||
* Callback function used by DBCellWriteCommandFile() to output
|
||||
* commands corresponding to cell uses in the layout.
|
||||
*
|
||||
* Results:
|
||||
* 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* Writes output to a file.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -4479,6 +4637,45 @@ dbWriteUseCommandsFunc(cellUse, cdarg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* dbWritePropCommandPaintFunc --
|
||||
*
|
||||
* Transform tiles in a plane into a set of four coordinate values and output
|
||||
* them to the file. This turns plane data into a PROP_TYPE_DIMENSION array,
|
||||
* which is not a very efficient form and may be revisited. For relatively
|
||||
* simple plane data, it suffices. The property planes are single-bit types.
|
||||
* Note that there is no support for non-Manhattan geometry in the property
|
||||
* plane at this time.
|
||||
*
|
||||
* Results:
|
||||
* 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* Writes output to a file.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
dbWritePropCommandPaintFunc(Tile *tile,
|
||||
TileType dinfo,
|
||||
FILE *f)
|
||||
{
|
||||
Rect r;
|
||||
MagWindow *w;
|
||||
|
||||
TiToRect(tile, &r);
|
||||
windCheckOnlyWindow(&w, DBWclientID);
|
||||
fprintf(f, "%s ", DBWPrintValue(r.r_xbot, w, TRUE));
|
||||
fprintf(f, "%s ", DBWPrintValue(r.r_ybot, w, FALSE));
|
||||
fprintf(f, "%s ", DBWPrintValue(r.r_xtop, w, TRUE));
|
||||
fprintf(f, "%s ", DBWPrintValue(r.r_ytop, w, FALSE));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -4487,6 +4684,12 @@ dbWriteUseCommandsFunc(cellUse, cdarg)
|
|||
* Callback function used by DBCellWriteCommandFile() to output
|
||||
* commands corresponding to properties in the layout.
|
||||
*
|
||||
* Results:
|
||||
* 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* Writes output to a file.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -4540,6 +4743,19 @@ dbWritePropCommandsFunc(key, proprec, cdarg)
|
|||
fprintf(f, "\n");
|
||||
break;
|
||||
|
||||
case PROPERTY_TYPE_PLANE:
|
||||
/* Plane properties are automatically handled as plane data,
|
||||
* so the property type does not need to be declared.
|
||||
* Only mask hints can be plane properties.
|
||||
*/
|
||||
fprintf(f, "property %s ", key);
|
||||
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||
proprec->prop_value.prop_plane,
|
||||
&TiPlaneRect, &CIFSolidBits, dbWritePropCommandPaintFunc,
|
||||
(ClientData)f);
|
||||
fprintf(f, "\n");
|
||||
break;
|
||||
|
||||
case PROPERTY_TYPE_DOUBLE:
|
||||
fprintf(f, "property double %s ", key);
|
||||
for (i = 0; i < proprec->prop_len; i++)
|
||||
|
|
@ -4573,7 +4789,6 @@ dbWritePropCommandsFunc(key, proprec, cdarg)
|
|||
* the file. If successful, rewind the now-expanded file and
|
||||
* overwrite the beginning of the file, then truncate it.
|
||||
*
|
||||
*
|
||||
* Results:
|
||||
* TRUE if the cell could be written successfully, FALSE otherwise.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -106,7 +106,18 @@ DBPropPut(cellDef, name, value)
|
|||
|
||||
entry = HashFind(htab, name);
|
||||
oldvalue = (PropertyRecord *)HashGetValue(entry);
|
||||
if (oldvalue != NULL) freeMagic((char *)oldvalue);
|
||||
/* All properties are allocated as a single block and can just be freed,
|
||||
* except for plane properties, which require freeing the plane.
|
||||
*/
|
||||
if (oldvalue != NULL)
|
||||
{
|
||||
if (oldvalue->prop_type == PROPERTY_TYPE_PLANE)
|
||||
{
|
||||
DBFreePaintPlane(oldvalue->prop_value.prop_plane);
|
||||
TiFreePlane(oldvalue->prop_value.prop_plane);
|
||||
}
|
||||
freeMagic((char *)oldvalue);
|
||||
}
|
||||
if (value == (PropertyRecord *)NULL)
|
||||
HashRemove(htab, name);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -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_SW 0x20 /* Same as above, ignore tile SW corner */
|
||||
#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 */
|
||||
#define FLATTERMSIZE 4096 /* Used for generating flattened labels */
|
||||
|
|
@ -719,6 +720,7 @@ typedef struct
|
|||
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;
|
||||
|
||||
|
|
@ -760,6 +762,7 @@ typedef struct
|
|||
#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 -------------------- */
|
||||
|
||||
|
|
@ -1059,6 +1062,19 @@ extern unsigned char DBVerbose; /* If 0, don't print any messages */
|
|||
#define DB_VERBOSE_WARN 2
|
||||
#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 ------------------- */
|
||||
|
||||
/***
|
||||
|
|
|
|||
|
|
@ -131,8 +131,11 @@ DBWAddButtonHandler(
|
|||
for (i = 0; i < MAXBUTTONHANDLERS; i++)
|
||||
{
|
||||
if (dbwButtonHandlers[i] != NULL) continue;
|
||||
(void) StrDup(&dbwButtonHandlers[i], name);
|
||||
(void) StrDup(&dbwButtonDoc[i], doc);
|
||||
StrDup(&dbwButtonHandlers[i], name);
|
||||
if (doc != NULL)
|
||||
StrDup(&dbwButtonDoc[i], doc);
|
||||
else
|
||||
dbwButtonDoc[i] = (char *)NULL;
|
||||
dbwButtonProcs[i] = proc;
|
||||
dbwButtonCursors[i] = cursor;
|
||||
return;
|
||||
|
|
@ -273,6 +276,37 @@ DBWGetButtonHandler()
|
|||
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
|
||||
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 */
|
||||
GrSetStuff(STYLE_LABEL);
|
||||
(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));
|
||||
GrClipTo(&rootClip);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -546,12 +546,12 @@ DBWloadWindow(window, name, flags)
|
|||
newEditUse = DBCellNewUse(newEditDef, (char *) NULL);
|
||||
(void) StrDup(&(newEditUse->cu_id), "Topmost cell in the window");
|
||||
DBExpand(newEditUse,
|
||||
((DBWclientRec *)window->w_clientData)->dbw_bitmask, TRUE);
|
||||
((DBWclientRec *)window->w_clientData)->dbw_bitmask, DB_EXPAND);
|
||||
|
||||
if (expand)
|
||||
DBExpandAll(newEditUse, &(newEditUse->cu_bbox),
|
||||
((DBWclientRec *)window->w_clientData)->dbw_bitmask,
|
||||
FALSE, UnexpandFunc,
|
||||
DB_UNEXPAND, UnexpandFunc,
|
||||
INT2CD(((DBWclientRec *)window->w_clientData)->dbw_bitmask));
|
||||
|
||||
if (newEdit)
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ extern void DBWAddButtonHandler(const char *name, const cb_database_buttonhandle
|
|||
int cursor, const char *doc);
|
||||
extern char *DBWGetButtonHandler();
|
||||
extern char *DBWChangeButtonHandler();
|
||||
extern int DBWButtonHandlerIndex();
|
||||
extern void DBWPrintButtonDoc();
|
||||
extern void DBWBoxHandler();
|
||||
|
||||
|
|
|
|||
|
|
@ -71,12 +71,15 @@ Operations on cell definitions.
|
|||
<DT> <B>rename</B> <I>name newname</I>
|
||||
<DD> Change the name of the cell definition <I>name</I> to
|
||||
<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
|
||||
<I>name</I> is a descendent of another cell, the command
|
||||
will be prohibited. If the cell <I>name</I> is currently
|
||||
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>
|
||||
<DD> Perform a flush of the cell (per the "<B>flush</B>" command),
|
||||
first removing any file path associated with the cell, so
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ expanded/unexpanded cells in the current selection.
|
|||
|
||||
<H3>Usage:</H3>
|
||||
<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>
|
||||
|
||||
<H3>Shortcuts:</H3>
|
||||
|
|
@ -38,14 +39,32 @@ expanded/unexpanded cells in the current selection.
|
|||
<H3>Summary:</H3>
|
||||
<BLOCKQUOTE>
|
||||
The <B>expand</B> command expands the view of subcells to
|
||||
display the contents of the subcells. Without arguments,
|
||||
the <B>expand</B> command expands all unexpanded subcells that
|
||||
touch or intersect the cursor box in the layout window. <P>
|
||||
display the contents of the subcells.
|
||||
|
||||
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>
|
||||
|
||||
<H3>Implementation Notes:</H3>
|
||||
|
|
|
|||
|
|
@ -87,6 +87,50 @@ Place a label in the layout
|
|||
to another layer. <P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<B>Attribute labels:</B> <P>
|
||||
A handful of labels are referred to as "attribute" labels. These
|
||||
label types are placed on devices and affect how the device is
|
||||
extracted. <P>
|
||||
|
||||
A label that is placed inside a device (e.g., a MOSFET gate) which
|
||||
ends with the character "<B>^</B>" is a <I>gate attribute</I>. A
|
||||
gate attribute in the form of "<I>name</I><B>=</B><I>value</I><B>^</B>"
|
||||
specifies an extra parameter to be passed to the device in addition
|
||||
to the standard parameters calculated for that device. This is used
|
||||
to capture parameters which cannot easily be inferred from the layout.
|
||||
For example, an RF device model might be distinguished from a non-RF
|
||||
device model by a parameter such as <B>rfmode=1</B>. Whether or not
|
||||
a device is intended for RF use is not easily guessed from the layout,
|
||||
and so "tagging" the gate with the parameter allows the correct model
|
||||
parameters to be used for the device. <P>
|
||||
|
||||
A gate attribute that is not in the form of a parameter will be used
|
||||
as the device's instance index in the netlist; e.g., a label of
|
||||
"<B>1^</B>" on a MOSFET gate extracted as a MOSFET device would be an
|
||||
entry "<B>M1</B>" in the netlist. This can be used to better track
|
||||
device indexes between a schematic and layout. <P>
|
||||
|
||||
A label that is placed on the <I>edge</I> a device, specificlly a
|
||||
MOSFET gate, and which ends with the character "<B>$</B>", is a
|
||||
<I>terminal attribute</I>. The only terminal attributes recognized
|
||||
by magic are <B>S$</B> and <B>D$</B>, which specify which side of the
|
||||
gate is to be considered the source and which is to be considered the
|
||||
drain. Generally, MOSFET devices are symmetric, and their use in a
|
||||
simulation does not depend on which side is in the position of the
|
||||
"source" and which is in the position of the "drain". To the extent
|
||||
that it matters, the terminal attributes can be used to ensure that
|
||||
the source and drain connections appear in the netlist in their
|
||||
intended orientation. <P>
|
||||
|
||||
Labels ending with "<B>@</B>" are <I>node attributes</I>. There is
|
||||
currently no functional application for node attributes. When one
|
||||
is applied, it will appear in the output netlist in a SPICE comment
|
||||
line indicating the node and attribute. This could be used, say,
|
||||
by a post-processing script, but as it is in a comment line, it has
|
||||
no impact on simulation or LVS.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3>Implementation Notes:</H3>
|
||||
<BLOCKQUOTE>
|
||||
<B>label</B> is implemented as a built-in command in <B>magic</B>.
|
||||
|
|
|
|||
|
|
@ -20,22 +20,64 @@
|
|||
|
||||
<H2>macro</H2>
|
||||
<HR>
|
||||
Define or print a macro called char
|
||||
Define or print a key or button macro binding.
|
||||
<HR>
|
||||
|
||||
<H3>Usage:</H3>
|
||||
<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>
|
||||
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
|
||||
present, <I>window_type</I> must be one of the four window
|
||||
types accepted by the <B>specialopen</B> command: <B>layout</B>,
|
||||
<B>color</B>, <B>netlist</B>, and <B>wind3d</B>. If omitted,
|
||||
the layout window is assumed by default, unless the command has
|
||||
been called from inside a window (using the colon or semicolon
|
||||
present, <I>window_type</I> must be one of the known valid window
|
||||
types accepted by the <B>specialopen</B> command (<B>color</B>,
|
||||
<B>netlist</B>, and <B>wind3d</B>), or a known layout tool
|
||||
(<B>box</B>, <B>wiring</B>, <B>nettool</B>, or <B>pick</B>). If
|
||||
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
|
||||
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>
|
||||
|
||||
|
|
@ -72,7 +114,6 @@ Define or print a macro called char
|
|||
etc., the <B>macro</B> command accepts the abbreviated
|
||||
forms <B>Button1</B>, and so forth. <P>
|
||||
|
||||
|
||||
Finally, key modifiers may be prepended to the key name.
|
||||
Valid key modifiers are <B>Shift_</B>, <B>Control_</B>,
|
||||
<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>
|
||||
<BLOCKQUOTE>
|
||||
<A HREF=imacro.html><B>imacro</B></A> <BR>
|
||||
<A HREF=toolchange.html><B>tool</B></A> (Tcl version) <BR>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P><IMG SRC=graphics/line1.gif><P>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ Attach a "property" (string key and value pair) to the edit cell
|
|||
|
||||
<H3>Usage:</H3>
|
||||
<BLOCKQUOTE>
|
||||
<B>property</B> [<I>type</I>] [<I>key</I> [<I>value</I>]] <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>
|
||||
|
|
@ -64,6 +64,13 @@ Attach a "property" (string key and value pair) to the edit cell
|
|||
.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>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ Unexpand everything inside or touching the cursor box.
|
|||
|
||||
<H3>Usage:</H3>
|
||||
<BLOCKQUOTE>
|
||||
<B>unexpand</B> <BR><BR>
|
||||
<B>unexpand</B> [<B>selection</B>|<B>surround</B>|<B>overlap</B>|<B>all</B>]
|
||||
<BR><BR>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3>Shortcuts:</H3>
|
||||
|
|
@ -37,8 +38,23 @@ Unexpand everything inside or touching the cursor box.
|
|||
<BLOCKQUOTE>
|
||||
The <B>unexpand</B> command unexpands the view of subcells to
|
||||
hide the contents of the subcells and show the bounding box
|
||||
outline only. The <B>unexpand</B> command unexpands all subcells
|
||||
that touch or intersect the cursor box in the layout window. <P>
|
||||
outline only.
|
||||
|
||||
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>
|
||||
|
||||
<H3>Implementation Notes:</H3>
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ extern int drcArrayYankFunc(), drcArrayOverlapFunc();
|
|||
static DRCCookie drcArrayCookie = {
|
||||
0, 0, 0, 0,
|
||||
{ {0} }, { {0} },
|
||||
0, 0, 0,
|
||||
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||
DRC_ARRAY_OVERLAP_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
|
|
|||
130
drc/DRCbasic.c
130
drc/DRCbasic.c
|
|
@ -27,6 +27,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <stdio.h>
|
||||
#include <string.h> // for memcpy()
|
||||
#include <math.h> // for sqrt() for diagonal check
|
||||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "tiles/tile.h"
|
||||
|
|
@ -36,7 +38,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/signals.h"
|
||||
#include "utils/maxrect.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "utils/undo.h"
|
||||
#include "textio/textio.h"
|
||||
#include "cif/CIFint.h"
|
||||
|
||||
int dbDRCDebug = 0;
|
||||
|
||||
|
|
@ -48,7 +52,7 @@ int dbDRCDebug = 0;
|
|||
static DRCCookie drcOverlapCookie = {
|
||||
0, 0, 0, 0,
|
||||
{ {0} }, { {0} },
|
||||
0, 0, 0,
|
||||
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||
DRC_OVERLAP_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
|
@ -62,7 +66,33 @@ extern MaxRectsData *drcCanonicalMaxwidth();
|
|||
/*
|
||||
*-----------------------------------------------------------------------
|
||||
*
|
||||
* drcCifPointToSegment
|
||||
* drcFoundOneFunc --
|
||||
*
|
||||
* Simple callback for a plane search on a mask-hint plane inside
|
||||
* a DRC check area.
|
||||
*
|
||||
* Results:
|
||||
* Return 1 always, indicating that a tile has been found in the
|
||||
* DRC search area, and the search can end.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
drcFoundOneFunc(Tile *tile,
|
||||
TileType dinfo,
|
||||
ClientData cdata)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------
|
||||
*
|
||||
* drcCifPointToSegment --
|
||||
*
|
||||
* Euclidean-distance point-to-segment distance (squared)
|
||||
* calculation (borrowed from XCircuit)
|
||||
|
|
@ -468,6 +498,26 @@ DRCBasicCheck (celldef, checkRect, clipRect, function, cdata)
|
|||
DBResetTilePlane(celldef->cd_planes[planeNum], DRC_UNPROCESSED);
|
||||
(void) DBSrPaintArea ((Tile *) NULL, celldef->cd_planes[planeNum],
|
||||
checkRect, &DBAllTypeBits, drcTile, (ClientData) &arg);
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
/* Execute pending Tcl events, so the DRC process doesn't block. */
|
||||
|
||||
/* WARNING: This code cannot be enabled until some method is
|
||||
* worked out to determine if any event resulted in a change
|
||||
* to the DRC check plane which would invalidate the current
|
||||
* search. If so, the search must end immediately and the
|
||||
* area being checked must be reinstated. The code was added
|
||||
* to see how it speeds up the response time of magic when
|
||||
* some of the DRC rules are compute-intensive. It speeds up
|
||||
* performance enough that it is worthwhile to implement the
|
||||
* method just mentioned.
|
||||
*/
|
||||
#if 0
|
||||
UndoEnable();
|
||||
while (Tcl_DoOneEvent(TCL_DONT_WAIT));
|
||||
UndoDisable();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
drcCifCheck(&arg);
|
||||
if (arg.dCD_rlist != NULL) freeMagic(arg.dCD_rlist);
|
||||
|
|
@ -727,6 +777,44 @@ drcTile (tile, dinfo, arg)
|
|||
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
||||
cptr = cptr->drcc_next)
|
||||
{
|
||||
/* Handle rule exceptions and exemptions */
|
||||
if (cptr->drcc_exception != DRC_EXCEPTION_NONE)
|
||||
{
|
||||
PropertyRecord *proprec;
|
||||
bool propfound, isinside = FALSE;
|
||||
char *name;
|
||||
int idx = cptr->drcc_exception & ~DRC_EXCEPTION_MASK;
|
||||
name = DRCCurStyle->DRCExceptionList[idx];
|
||||
|
||||
/* Is there any exception area defined? */
|
||||
proprec = DBPropGet(arg->dCD_celldef, name, &propfound);
|
||||
|
||||
/* If an exception area exists, is the error edge inside? */
|
||||
if (propfound)
|
||||
{
|
||||
Rect redge;
|
||||
|
||||
redge.r_xbot = redge.r_xtop = edgeX;
|
||||
redge.r_ybot = edgeBot;
|
||||
redge.r_ytop = edgeTop;
|
||||
|
||||
if (DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||
proprec->prop_value.prop_plane,
|
||||
&redge, &CIFSolidBits, drcFoundOneFunc,
|
||||
(ClientData)NULL) == 1)
|
||||
isinside = TRUE;
|
||||
}
|
||||
|
||||
/* Exemption rules are ignored if the edge is inside
|
||||
* an exception area. Exception rules are ignored if
|
||||
* the edge is outside an exception area.
|
||||
*/
|
||||
if (!isinside && (!(cptr->drcc_exception & DRC_EXCEPTION_MASK) == 0))
|
||||
continue;
|
||||
if (isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) != 0))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
|
||||
/* the code above for non-Manhattan shapes and do not */
|
||||
/* need to be processed again. */
|
||||
|
|
@ -1136,6 +1224,44 @@ drcTile (tile, dinfo, arg)
|
|||
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
||||
cptr = cptr->drcc_next)
|
||||
{
|
||||
/* Handle rule exceptions and exemptions */
|
||||
if (cptr->drcc_exception != DRC_EXCEPTION_NONE)
|
||||
{
|
||||
PropertyRecord *proprec;
|
||||
bool propfound, isinside = FALSE;
|
||||
char *name;
|
||||
int idx = cptr->drcc_exception & ~DRC_EXCEPTION_MASK;
|
||||
name = DRCCurStyle->DRCExceptionList[idx];
|
||||
|
||||
/* Is there any exception area defined? */
|
||||
proprec = DBPropGet(arg->dCD_celldef, name, &propfound);
|
||||
|
||||
/* If an exception area exists, is the error edge inside? */
|
||||
if (propfound)
|
||||
{
|
||||
Rect redge;
|
||||
|
||||
redge.r_ybot = redge.r_ytop = edgeY;
|
||||
redge.r_xbot = edgeLeft;
|
||||
redge.r_xtop = edgeRight;
|
||||
|
||||
if (DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||
proprec->prop_value.prop_plane,
|
||||
&redge, &CIFSolidBits, drcFoundOneFunc,
|
||||
(ClientData)NULL) == 1)
|
||||
isinside = TRUE;
|
||||
}
|
||||
|
||||
/* Exemption rules are ignored if the edge is inside
|
||||
* an exception area. Exception rules are ignored if
|
||||
* the edge is outside an exception area.
|
||||
*/
|
||||
if (!isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) == 0))
|
||||
continue;
|
||||
if (isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) != 0))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
|
||||
/* the code above for non-Manhattan shapes and do not */
|
||||
/* need to be processed again. */
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ static ClientData drcSubClientData; /* To be passed to error function. */
|
|||
static DRCCookie drcSubcellCookie = {
|
||||
0, 0, 0, 0,
|
||||
{ {0} }, { {0} },
|
||||
0, 0, 0,
|
||||
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||
DRC_SUBCELL_OVERLAP_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
|
@ -65,7 +65,7 @@ static DRCCookie drcSubcellCookie = {
|
|||
static DRCCookie drcInSubCookie = {
|
||||
0, 0, 0, 0,
|
||||
{ {0} }, { {0} },
|
||||
0, 0, 0,
|
||||
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||
DRC_IN_SUBCELL_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
|
@ -79,7 +79,7 @@ static DRCCookie drcInSubCookie = {
|
|||
static DRCCookie drcOffGridCookie = {
|
||||
0, 0, 0, 0,
|
||||
{ {0} }, { {0} },
|
||||
0, 0, 0,
|
||||
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||
DRC_OFFGRID_TAG,
|
||||
(DRCCookie *) NULL
|
||||
};
|
||||
|
|
@ -826,6 +826,7 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
*/
|
||||
subArea = *erasebox;
|
||||
GeoClip(&subArea, &cliparea);
|
||||
if (GEO_RECTNULL(&subArea)) continue;
|
||||
GEO_EXPAND(&subArea, DRCTechHalo, &intArea);
|
||||
|
||||
errorSaveType = DRCErrorType;
|
||||
|
|
|
|||
202
drc/DRCtech.c
202
drc/DRCtech.c
|
|
@ -72,6 +72,12 @@ static int drcRulesOptimized = 0;
|
|||
|
||||
static int DRCtag = 0;
|
||||
|
||||
/* Keep track of what rule exemption or exception is in effect
|
||||
* while reading the DRC tech file section.
|
||||
*/
|
||||
|
||||
static unsigned char drcCurException = DRC_EXCEPTION_NONE;
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
|
|
@ -79,6 +85,7 @@ int drcWidth(), drcSpacing(), drcEdge(), drcNoOverlap();
|
|||
int drcExactOverlap(), drcExtend();
|
||||
int drcSurround(), drcRectOnly(), drcOverhang();
|
||||
int drcStepSize(), drcOption(), drcOffGrid();
|
||||
int drcException(), drcExemption();
|
||||
int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles();
|
||||
int drcCifSetStyle(), drcCifWidth(), drcCifSpacing();
|
||||
int drcCifMaxwidth(), drcCifArea();
|
||||
|
|
@ -301,6 +308,12 @@ drcTechFreeStyle()
|
|||
/* Clear the Why string list */
|
||||
freeMagic(DRCCurStyle->DRCWhyList);
|
||||
|
||||
/* Clear the exception list */
|
||||
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
|
||||
freeMagic(DRCCurStyle->DRCExceptionList[i]);
|
||||
if (DRCCurStyle->DRCExceptionList != (char **)NULL)
|
||||
freeMagic(DRCCurStyle->DRCExceptionList);
|
||||
|
||||
freeMagic(DRCCurStyle);
|
||||
DRCCurStyle = NULL;
|
||||
}
|
||||
|
|
@ -384,6 +397,63 @@ drcWhyCreate(whystring)
|
|||
return DRCCurStyle->DRCWhySize;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* drcExceptionCreate --
|
||||
*
|
||||
* Create an entry for a DRC rule exception/exemption type, if it does
|
||||
* not already exist.
|
||||
*
|
||||
* Results:
|
||||
* The index of the exception (which is an unsigned character containing
|
||||
* the index in the lower 7 bits and a high bit indicating if the rule
|
||||
* is an exception (0) or an exemption (1)).
|
||||
*
|
||||
* Side effects:
|
||||
* Adds to the DRCExceptionList if "name" has not been used before.
|
||||
* Calls StrDup() and increments DRCExceptionSize.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
unsigned char
|
||||
drcExceptionCreate(name)
|
||||
char *name;
|
||||
{
|
||||
int i;
|
||||
char **newlist;
|
||||
|
||||
/* NOTE: DRCExceptionList has "MASKHINTS_" prepended to the names */
|
||||
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
|
||||
if (!strcmp(name, DRCCurStyle->DRCExceptionList[i] + 10))
|
||||
return (unsigned char)i;
|
||||
|
||||
/* Note that i cannot be 127 as this is reserved for DRC_EXCEPTION_NONE */
|
||||
if (i > 126)
|
||||
{
|
||||
/* I would be shocked if this code ever got executed. */
|
||||
TxError("Error: Too many rule exceptions! Limit is 126.\n");
|
||||
return DRC_EXCEPTION_NONE;
|
||||
}
|
||||
|
||||
/* Create a new list that is one entry longer than the old list.
|
||||
* This is not elegant but there will never be more than a handful
|
||||
* of exceptions in a rule deck.
|
||||
*/
|
||||
newlist = (char **)mallocMagic((i + 1) * sizeof(char *));
|
||||
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
|
||||
newlist[i] = DRCCurStyle->DRCExceptionList[i];
|
||||
|
||||
/* The rule deck does not have the "MASKHINTS_" prefix on the name */
|
||||
newlist[i] = (char *)mallocMagic(strlen(name) + 11);
|
||||
sprintf(newlist[i], "MASKHINTS_%s", name);
|
||||
DRCCurStyle->DRCExceptionSize++;
|
||||
if (DRCCurStyle->DRCExceptionList != (char **)NULL)
|
||||
freeMagic(DRCCurStyle->DRCExceptionList);
|
||||
DRCCurStyle->DRCExceptionList = newlist;
|
||||
return (unsigned char)i;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -571,6 +641,8 @@ DRCTechStyleInit()
|
|||
DRCCurStyle->DRCStepSize = 0;
|
||||
DRCCurStyle->DRCFlags = (char)0;
|
||||
DRCCurStyle->DRCWhySize = 0;
|
||||
DRCCurStyle->DRCExceptionList = (char **)NULL;
|
||||
DRCCurStyle->DRCExceptionSize = 0;
|
||||
|
||||
HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS);
|
||||
|
||||
|
|
@ -663,6 +735,7 @@ DRCTechStyleInit()
|
|||
}
|
||||
|
||||
drcCifInit();
|
||||
drcCurException = DRC_EXCEPTION_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -955,6 +1028,7 @@ drcCifAssign(cookie, dist, next, mask, corner, tag, cdist, flags, planeto, plane
|
|||
(cookie)->drcc_plane = planeto;
|
||||
(cookie)->drcc_mod = 0;
|
||||
(cookie)->drcc_cmod = 0;
|
||||
(cookie)->drcc_exception = drcCurException;
|
||||
}
|
||||
|
||||
// This is like drcCifAssign, but checks for bad plane numbers in planeto and
|
||||
|
|
@ -1031,50 +1105,37 @@ DRCTechAddRule(sectionName, argc, argv)
|
|||
int (*rk_proc)(); /* Procedure implementing this keyword */
|
||||
const char *rk_err; /* Error message */
|
||||
} ruleKeys[] = {
|
||||
{"angles", 4, 4, drcAngles,
|
||||
"layers 45|90 why"},
|
||||
{"angles", 4, 4, drcAngles, "layers 45|90 why"},
|
||||
{"edge", 8, 10, drcEdge,
|
||||
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
|
||||
{"edge4way", 8, 10, drcEdge,
|
||||
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
|
||||
{"exact_overlap", 2, 2, drcExactOverlap,
|
||||
"layers"},
|
||||
{"exact_overlap", 2, 2, drcExactOverlap, "layers"},
|
||||
{"exception", 2, 2, drcException, "name"},
|
||||
{"exemption", 2, 2, drcExemption, "name"},
|
||||
{"extend", 5, 6, drcExtend,
|
||||
"layers1 layers2 distance [option] why"},
|
||||
{"no_overlap", 3, 3, drcNoOverlap,
|
||||
"layers1 layers2"},
|
||||
{"option", 2, 2, drcOption,
|
||||
"option_name option_value"},
|
||||
{"overhang", 5, 5, drcOverhang,
|
||||
"layers1 layers2 distance why"},
|
||||
{"rect_only", 3, 3, drcRectOnly,
|
||||
"layers why"},
|
||||
{"no_overlap", 3, 3, drcNoOverlap, "layers1 layers2"},
|
||||
{"option", 2, 2, drcOption, "option_name option_value"},
|
||||
{"overhang", 5, 5, drcOverhang, "layers1 layers2 distance why"},
|
||||
{"rect_only", 3, 3, drcRectOnly, "layers why"},
|
||||
{"spacing", 6, 7, drcSpacing,
|
||||
"layers1 layers2 separation [layers3] adjacency why"},
|
||||
{"stepsize", 2, 2, drcStepSize,
|
||||
"step_size"},
|
||||
{"stepsize", 2, 2, drcStepSize, "step_size"},
|
||||
{"surround", 6, 7, drcSurround,
|
||||
"layers1 layers2 distance presence why"},
|
||||
{"width", 4, 5, drcWidth,
|
||||
"layers width why"},
|
||||
{"width", 4, 5, drcWidth, "layers width why"},
|
||||
{"widespacing", 7, 8, drcSpacing,
|
||||
"layers1 width layers2 separation adjacency why"},
|
||||
{"area", 5, 5, drcArea,
|
||||
"layers area horizon why"},
|
||||
{"off_grid", 4, 4, drcOffGrid,
|
||||
"layers pitch why"},
|
||||
{"maxwidth", 4, 6, drcMaxwidth,
|
||||
"layers maxwidth bends why"},
|
||||
{"cifstyle", 2, 2, drcCifSetStyle,
|
||||
"cif_style"},
|
||||
{"cifwidth", 4, 4, drcCifWidth,
|
||||
"layers width why"},
|
||||
{"area", 5, 5, drcArea, "layers area horizon why"},
|
||||
{"off_grid", 4, 4, drcOffGrid, "layers pitch why"},
|
||||
{"maxwidth", 4, 6, drcMaxwidth, "layers maxwidth bends why"},
|
||||
{"cifstyle", 2, 2, drcCifSetStyle, "cif_style"},
|
||||
{"cifwidth", 4, 4, drcCifWidth, "layers width why"},
|
||||
{"cifspacing", 6, 6, drcCifSpacing,
|
||||
"layers1 layers2 separation adjacency why"},
|
||||
{"cifarea", 5, 5, drcCifArea,
|
||||
"layers area horizon why"},
|
||||
{"cifmaxwidth", 5, 5, drcCifMaxwidth,
|
||||
"layers maxwidth bends why"},
|
||||
{"cifarea", 5, 5, drcCifArea, "layers area horizon why"},
|
||||
{"cifmaxwidth", 5, 5, drcCifMaxwidth, "layers maxwidth bends why"},
|
||||
{"rectangle", 5, 5, drcRectangle,
|
||||
"layers maxwidth [even|odd|any] why"},
|
||||
{0}
|
||||
|
|
@ -1695,7 +1756,7 @@ drcMaxwidth(argc, argv)
|
|||
if (PlaneMaskHasPlane(pmask2, plane2))
|
||||
break;
|
||||
|
||||
if (plane2 == plane)
|
||||
if (PlaneMaskHasPlane(pmask, plane2))
|
||||
TechError("Warning: Exclude types for \"maxwidth\" are on the "
|
||||
"same plane and so cannot be checked.\n");
|
||||
}
|
||||
|
|
@ -3634,6 +3695,84 @@ drcRectangle(argc, argv)
|
|||
return maxwidth;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* drcException, drcExemption --
|
||||
*
|
||||
* Process a DRC exception declaration
|
||||
* This is of the form:
|
||||
*
|
||||
* exception exception_name|none
|
||||
* or
|
||||
* exemption exemption_name|none
|
||||
*
|
||||
* e.g,
|
||||
*
|
||||
* exception SRAM
|
||||
* exemption SRAM
|
||||
*
|
||||
* The exception_name or exemption_name is the suffix part of a MASKHINTS_*
|
||||
* property name; e.g., the name SRAM corresponds to a property called
|
||||
* MASKHINTS_SRAM. This declaration is followed by a block of DRC rules
|
||||
* that are subject to the exception or the exemption. An exception is the
|
||||
* opposite of an exemption: If a rule is excepted, then the rule applies
|
||||
* within areas delineated by bounding boxes defined by the
|
||||
* MASKHINTS_<exception_name> property. If a rule is exempted, then the
|
||||
* rule applies only outside of areas delineated by bounding boxes defined
|
||||
* by the MASKHINTS_<exemption_name> property. The block of rules subject
|
||||
* to the exemption or exception ends with another exception or exemption
|
||||
* declaration. If the following rules are not to be excepted or exempted
|
||||
* at all, then use "exception none" or "exemption none".
|
||||
*
|
||||
* Results:
|
||||
* Returns 0.
|
||||
*
|
||||
* Side effects:
|
||||
* Updates drcCurException. drcCurException contains the index in
|
||||
* the lower 7 bits, and a flag in the upper bit (0 = exception rule,
|
||||
* 1 = exemption rule). The index can be recovered by masking off
|
||||
* the upper bit.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
drcException(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int i;
|
||||
|
||||
if (DRCCurStyle == NULL) return 0;
|
||||
|
||||
/* Assume that argc must be 2 because the parser insists upon it */
|
||||
|
||||
if (!strcmp(argv[1], "none"))
|
||||
drcCurException = DRC_EXCEPTION_NONE;
|
||||
else
|
||||
drcCurException = drcExceptionCreate(argv[1]);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
drcExemption(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int i;
|
||||
|
||||
if (DRCCurStyle == NULL) return 0;
|
||||
|
||||
/* Assume that argc must be 2 because the parser insists upon it */
|
||||
|
||||
if (!strcmp(argv[1], "none"))
|
||||
drcCurException = DRC_EXCEPTION_NONE;
|
||||
else
|
||||
drcCurException = drcExceptionCreate(argv[1]) | DRC_EXCEPTION_MASK;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -4119,6 +4258,7 @@ drcTechFinalStyle(style)
|
|||
if (dp->drcc_dist > next->drcc_dist) continue;
|
||||
if (dp->drcc_cdist > next->drcc_cdist) continue;
|
||||
if (dp->drcc_plane != next->drcc_plane) continue;
|
||||
if (dp->drcc_exception != next->drcc_exception) continue;
|
||||
if (dp->drcc_flags & DRC_REVERSE)
|
||||
{
|
||||
if (!(next->drcc_flags & DRC_REVERSE)) continue;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ typedef struct drccookie
|
|||
TileTypeBitMask drcc_mask; /* Legal types on RHS */
|
||||
TileTypeBitMask drcc_corner; /* Types that trigger corner check */
|
||||
unsigned short drcc_flags; /* Miscellaneous flags, see below. */
|
||||
unsigned char drcc_exception; /* Index to list of exceptions */
|
||||
int drcc_edgeplane; /* Plane of edge */
|
||||
int drcc_plane; /* Index of plane on which to check
|
||||
* legal types. */
|
||||
|
|
@ -91,6 +92,11 @@ typedef struct drccookie
|
|||
#define DRC_UNPROCESSED CLIENTDEFAULT
|
||||
#define DRC_PROCESSED 1
|
||||
|
||||
/* drcc_exception defaults to 255 meaning no exceptions/exemptions */
|
||||
#define DRC_EXCEPTION_NONE ((unsigned char)0xff)
|
||||
/* The high bit of the value determines if this is an exception or an exemption. */
|
||||
#define DRC_EXCEPTION_MASK ((unsigned char)0x80)
|
||||
|
||||
/*
|
||||
* Background DRC (DRC Idle proc) for Tcl-based Magic
|
||||
*/
|
||||
|
|
@ -177,6 +183,8 @@ typedef struct drcstyle
|
|||
unsigned short DRCFlags; /* Option flags */
|
||||
char **DRCWhyList; /* Indexed list of "why" text strings */
|
||||
int DRCWhySize; /* Length of DRCWhyList */
|
||||
char **DRCExceptionList; /* Indexed list of DRC exceptions */
|
||||
int DRCExceptionSize; /* Length of DRCExceptionList */
|
||||
PaintResultType DRCPaintTable[NP][NT][NT];
|
||||
} DRCStyle;
|
||||
|
||||
|
|
|
|||
|
|
@ -634,7 +634,7 @@ subcktHierVisit(
|
|||
|
||||
if (hasports || is_top)
|
||||
return subcktVisit(use, hierName, is_top);
|
||||
else if (def->def_flags & DEF_NODEVICES)
|
||||
else if ((def->def_flags & DEF_NODEVICES) && (!isStub))
|
||||
return 0;
|
||||
else
|
||||
return subcktVisit(use, hierName, is_top);
|
||||
|
|
@ -1088,6 +1088,7 @@ spcdevHierVisit(
|
|||
|
||||
if (!has_model)
|
||||
{
|
||||
fprintf(esSpiceF, " ");
|
||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
||||
}
|
||||
|
|
@ -1138,6 +1139,7 @@ spcdevHierVisit(
|
|||
|
||||
if (!has_model)
|
||||
{
|
||||
fprintf(esSpiceF, " ");
|
||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3140,6 +3140,7 @@ spcdevVisit(
|
|||
|
||||
if (!has_model)
|
||||
{
|
||||
fprintf(esSpiceF, " ");
|
||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
|
||||
}
|
||||
|
|
@ -3186,6 +3187,7 @@ spcdevVisit(
|
|||
|
||||
if (!has_model)
|
||||
{
|
||||
fprintf(esSpiceF, " ");
|
||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1835,6 +1835,8 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
|
|||
ParamList *chkParam;
|
||||
HashEntry *he;
|
||||
ResValue resvalue;
|
||||
LabRegion *node; /* Node connected to gate terminal */
|
||||
LabelList *ll; /* Gate's label list */
|
||||
|
||||
for (chkParam = devptr->exts_deviceParams; chkParam
|
||||
!= NULL; chkParam = chkParam->pl_next)
|
||||
|
|
@ -1966,6 +1968,34 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there are device attribute labels (labels attached to the device
|
||||
* type ending with "^") with "=" in them, then treat them as extra
|
||||
* parameters. Output each one and remove the gate attribute property
|
||||
* from the label.
|
||||
*/
|
||||
|
||||
node = (LabRegion *)ExtGetRegion(reg->treg_tile, reg->treg_dinfo);
|
||||
for (ll = node->lreg_labels; ll; ll = ll->ll_next)
|
||||
{
|
||||
if (ll->ll_attr == LL_GATEATTR)
|
||||
{
|
||||
char cs, *ct, *cp = ll->ll_label->lab_text;
|
||||
if (strchr(cp, '=') != NULL)
|
||||
{
|
||||
/* Since this is an attribute label, it has a special character
|
||||
* at the end, which needs to be stripped off while printing
|
||||
* and then put back again.
|
||||
*/
|
||||
ct = ll->ll_label->lab_text + strlen(ll->ll_label->lab_text) - 1;
|
||||
cs = *ct;
|
||||
*ct = '\0';
|
||||
fprintf(outFile, " %s", ll->ll_label->lab_text);
|
||||
ll->ll_attr = LL_NOATTR;
|
||||
*ct = cs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Structures used by extTermAPFunc() for storing area and perimeter data */
|
||||
|
|
@ -2725,6 +2755,56 @@ extOutputDevices(def, transList, outFile)
|
|||
/* get corrected by extComputeEffectiveLW(). */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
|
|
|
|||
|
|
@ -1289,6 +1289,14 @@ extFindOverlap(tp, area, esws)
|
|||
TileType tin = TiGetType(bp->b_inside);
|
||||
TileType tout = TiGetType(bp->b_outside);
|
||||
|
||||
/* Get residues
|
||||
* (Note: Isn't it better to include contacts in the tables?)
|
||||
*/
|
||||
if (DBIsContact(tin))
|
||||
tin = DBPlaneToResidue(tin, esws->plane_of_boundary);
|
||||
if (DBIsContact(tout))
|
||||
tout = DBPlaneToResidue(tout, esws->plane_of_boundary);
|
||||
|
||||
pMask = ExtCurStyle->exts_sideOverlapOtherPlanes[tin][tout];
|
||||
extOverlapDef = esws->def;
|
||||
|
||||
|
|
|
|||
|
|
@ -354,8 +354,8 @@ extHierConnections(ha, cumFlat, oneFlat)
|
|||
if (!(lab->lab_flags & LABEL_STICKY)) continue;
|
||||
|
||||
r = lab->lab_rect;
|
||||
if (!GEO_TOUCH(&r, &ha->ha_subArea)) continue;
|
||||
GEOCLIP(&r, &ha->ha_subArea);
|
||||
if (GEO_RECTNULL(&r)) continue;
|
||||
|
||||
cumDef = cumFlat->et_use->cu_def;
|
||||
connected = &DBConnectTbl[lab->lab_type];
|
||||
|
|
|
|||
|
|
@ -614,6 +614,7 @@ termtop:
|
|||
|
||||
termdone:
|
||||
/* (continue) */
|
||||
(void)0; /* older compilers need a statement after the label to prevent a compile error */
|
||||
}
|
||||
|
||||
/* Clean up---Put the ClientData entries in the tiles back to
|
||||
|
|
|
|||
|
|
@ -251,6 +251,17 @@ extSubtree(parentUse, reg, f)
|
|||
if (result == 0) {
|
||||
/* If result == FALSE then ha.ha_interArea is invalid. */
|
||||
ha.ha_interArea = rlab;
|
||||
/* Ensure that the interaction area is not zero */
|
||||
if (ha.ha_interArea.r_xtop - ha.ha_interArea.r_xbot == 0)
|
||||
{
|
||||
ha.ha_interArea.r_xtop++;
|
||||
ha.ha_interArea.r_xbot--;
|
||||
}
|
||||
if (ha.ha_interArea.r_ytop - ha.ha_interArea.r_ybot == 0)
|
||||
{
|
||||
ha.ha_interArea.r_ytop++;
|
||||
ha.ha_interArea.r_ybot--;
|
||||
}
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
|
|
@ -779,6 +790,7 @@ extSubtreeFunc(scx, ha)
|
|||
*/
|
||||
ha->ha_subArea = use->cu_bbox;
|
||||
GEOCLIP(&ha->ha_subArea, &ha->ha_interArea);
|
||||
|
||||
hy.hy_area = &ha->ha_subArea;
|
||||
hy.hy_target = oneFlat->et_use;
|
||||
hy.hy_prefix = TRUE;
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <unistd.h>
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "utils/hash.h"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "windows/windows.h"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
#include <signal.h>
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "windows/windows.h"
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#include <X11/Xlib.h>
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
#include "utils/main.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "windows/windows.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "windows/windows.h"
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#include "utils/main.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "windows/windows.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "windows/windows.h"
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
#include "utils/main.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "windows/windows.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "windows/windows.h"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
#include <X11/Xutil.h>
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "textio/txcommands.h"
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#include <X11/Xlib.h>
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
|
|
|||
|
|
@ -1356,7 +1356,7 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename)
|
|||
}
|
||||
if (extDev->subs == extNode)
|
||||
{
|
||||
if ((subs = layoutDev->rd_fet_subs) != NULL)
|
||||
if ((layoutDev->rd_nterms >= 4) && ((subs = layoutDev->rd_fet_subs) != NULL))
|
||||
{
|
||||
if (subs->rn_name != NULL && notdecremented)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ ResMoveDevices(node1, node2)
|
|||
devptr = devptr->te_nextt;
|
||||
if (device->rd_fet_gate == node1)
|
||||
device->rd_fet_gate = node2;
|
||||
else if (device->rd_fet_subs == node1)
|
||||
else if ((device->rd_nterms >= 4) && (device->rd_fet_subs == node1))
|
||||
device->rd_fet_subs = node2;
|
||||
else if (device->rd_fet_source == node1)
|
||||
device->rd_fet_source = node2;
|
||||
|
|
|
|||
170
select/selOps.c
170
select/selOps.c
|
|
@ -1216,13 +1216,21 @@ SelectTransform(transform)
|
|||
SelectAndCopy2(EditRootDef);
|
||||
}
|
||||
|
||||
/* Client data used by SelectExpand */
|
||||
|
||||
typedef struct selExpData {
|
||||
int sed_mask; /* window mask */
|
||||
int sed_type; /* DB_EXPAND, etc. */
|
||||
Rect *sed_box; /* selection box if used, or NULL */
|
||||
} SelExpData;
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* SelectExpand --
|
||||
*
|
||||
* Expand all of the selected cells that are unexpanded, and
|
||||
* unexpand all of those that are expanded.
|
||||
* Expand or unexpand all of the selected cells according to
|
||||
* expandType.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
|
|
@ -1230,58 +1238,166 @@ SelectTransform(transform)
|
|||
* Side effects:
|
||||
* The contents of the selected cells will become visible or
|
||||
* invisible on the display in the indicated window(s).
|
||||
* Both the cell in the layout and the selection are updated
|
||||
* so that they are synchonized with respect to the state of
|
||||
* visibility.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
SelectExpand(mask)
|
||||
SelectExpand(mask, expandType, rootBox)
|
||||
int mask; /* Bits of this word indicate which
|
||||
* windows the selected cells will be
|
||||
* expanded in.
|
||||
*/
|
||||
int expandType; /* Operation to perform: Expand,
|
||||
* unexpand, or expand toggle.
|
||||
*/
|
||||
Rect *rootBox; /* Area of root box, if selecting by
|
||||
* cursor box area.
|
||||
*/
|
||||
{
|
||||
extern int selExpandFunc(); /* Forward reference. */
|
||||
/* Forward references */
|
||||
extern int selExpandFunc();
|
||||
|
||||
(void) SelEnumCells(FALSE, (bool *) NULL, (SearchContext *) NULL,
|
||||
selExpandFunc, INT2CD(mask));
|
||||
SelExpData sed;
|
||||
|
||||
sed.sed_type = expandType;
|
||||
sed.sed_box = rootBox;
|
||||
sed.sed_mask = mask;
|
||||
|
||||
if (rootBox != NULL)
|
||||
{
|
||||
SearchContext scx;
|
||||
|
||||
scx.scx_use = SelectUse;
|
||||
scx.scx_area = *rootBox;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
|
||||
SelEnumCells(FALSE, (bool *) NULL, &scx, selExpandFunc, &sed);
|
||||
return;
|
||||
}
|
||||
|
||||
SelEnumCells(FALSE, (bool *) NULL, (SearchContext *)NULL,
|
||||
selExpandFunc, &sed);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
selExpandFunc(selUse, use, transform, mask)
|
||||
selExpandFunc(selUse, use, transform, sed)
|
||||
CellUse *selUse; /* Use from selection. */
|
||||
CellUse *use; /* Use to expand (in actual layout). */
|
||||
Transform *transform; /* Not used. */
|
||||
int mask; /* Windows in which to expand. */
|
||||
SelExpData *sed; /* Information for expansion */
|
||||
{
|
||||
/* Don't change expansion status of root cell: screws up
|
||||
* DBWAreaChanged (need to always have at least top-level
|
||||
* cell be expanded).
|
||||
*/
|
||||
int expandType = sed->sed_type;
|
||||
int mask = sed->sed_mask;
|
||||
Rect *rootBox = sed->sed_box;
|
||||
|
||||
if (use->cu_parent == NULL)
|
||||
/* If a rootBox is provided, then we are here trying to sync the
|
||||
* cells in the selection to those in the edit cell. Need to
|
||||
* follow the policy of expandType: If DB_EXPAND_SURROUND, then
|
||||
* selUse must be inside the rootBox. If DB_EXPAND_OVERLAP, then
|
||||
* selUse must ovelap the rootBox.
|
||||
*/
|
||||
if (rootBox != NULL)
|
||||
{
|
||||
TxError("Can't unexpand root cell of window.\n");
|
||||
return 0;
|
||||
if ((expandType & DB_EXPAND_SURROUND_MASK) == DB_EXPAND_OVERLAP)
|
||||
{
|
||||
if (!GEO_OVERLAP(rootBox, &selUse->cu_bbox))
|
||||
return 0;
|
||||
}
|
||||
else /* (expandType & DB_EXPAND_SURROUND_MASK) == DB_EXPAND_SURROUND */
|
||||
{
|
||||
if (!GEO_SURROUND(rootBox, &selUse->cu_bbox))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Be sure to modify the expansion bit in the selection as well as
|
||||
* the one in the layout in order to keep them consistent.
|
||||
/* If a rootBox was given, then the expansion is being done in the
|
||||
* edit cell, and the selection is being updated to reflect any
|
||||
* changes there, so only handle the selection. Otherwise, we
|
||||
* have to sync the corresponding cells in the edit def here.
|
||||
*/
|
||||
|
||||
if (DBDescendSubcell(use, mask))
|
||||
if ((expandType & DB_EXPAND_MASK) == DB_EXPAND)
|
||||
{
|
||||
DBExpand(selUse, mask, FALSE);
|
||||
DBExpand(use, mask, FALSE);
|
||||
DBWAreaChanged(use->cu_parent, &use->cu_bbox, mask,
|
||||
(TileTypeBitMask *) NULL);
|
||||
/* Be sure to modify the expansion bit in the selection as well as
|
||||
* the one in the layout in order to keep them consistent.
|
||||
*/
|
||||
DBExpand(selUse, mask, DB_EXPAND);
|
||||
if (!rootBox)
|
||||
{
|
||||
DBExpand(use, mask, DB_EXPAND);
|
||||
if (use->cu_parent == NULL)
|
||||
DBWAreaChanged(use->cu_def, &use->cu_bbox, mask, &DBAllButSpaceBits);
|
||||
else
|
||||
DBWAreaChanged(use->cu_parent, &use->cu_bbox, mask, &DBAllButSpaceBits);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if ((expandType & DB_EXPAND_MASK) == DB_UNEXPAND)
|
||||
{
|
||||
DBExpand(selUse, mask, TRUE);
|
||||
DBExpand(use, mask, TRUE);
|
||||
DBWAreaChanged(use->cu_parent, &use->cu_bbox, mask, &DBAllButSpaceBits);
|
||||
/* Don't change expansion status of root cell: screws up
|
||||
* DBWAreaChanged (need to always have at least top-level
|
||||
* cell be expanded).
|
||||
*/
|
||||
|
||||
if ((use->cu_parent == NULL) && !rootBox)
|
||||
{
|
||||
TxError("Can't unexpand root cell of window.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (use->cu_parent != NULL)
|
||||
{
|
||||
/* Be sure to modify the expansion bit in the selection as well as
|
||||
* the one in the layout in order to keep them consistent.
|
||||
*/
|
||||
DBExpand(selUse, mask, DB_UNEXPAND);
|
||||
if (!rootBox)
|
||||
{
|
||||
DBExpand(use, mask, DB_UNEXPAND);
|
||||
DBWAreaChanged(use->cu_parent, &use->cu_bbox, mask,
|
||||
(TileTypeBitMask *) NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* (expandType & DB_EXPAND_MASK) == DB_EXPAND_TOGGLE */
|
||||
{
|
||||
/* Don't change expansion status of root cell: screws up
|
||||
* DBWAreaChanged (need to always have at least top-level
|
||||
* cell be expanded).
|
||||
*/
|
||||
|
||||
if (use->cu_parent == NULL)
|
||||
{
|
||||
if (!rootBox) TxError("Can't unexpand root cell of window.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Be sure to modify the expansion bit in the selection as well as
|
||||
* the one in the layout in order to keep them consistent.
|
||||
*/
|
||||
|
||||
if (DBDescendSubcell(selUse, mask))
|
||||
{
|
||||
DBExpand(selUse, mask, DB_UNEXPAND);
|
||||
if (!rootBox)
|
||||
{
|
||||
DBExpand(use, mask, DB_UNEXPAND);
|
||||
DBWAreaChanged(use->cu_parent, &use->cu_bbox, mask,
|
||||
(TileTypeBitMask *) NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBExpand(selUse, mask, DB_EXPAND);
|
||||
if (!rootBox)
|
||||
{
|
||||
DBExpand(use, mask, DB_EXPAND);
|
||||
DBWAreaChanged(use->cu_parent, &use->cu_bbox, mask, &DBAllButSpaceBits);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,6 +148,10 @@ proc magic::make_texthelper { mgrpath } {
|
|||
proc magic::analyze_labels {} {
|
||||
global typedflt typesticky typeport
|
||||
|
||||
# Ensure units of microns
|
||||
set curunits [units]
|
||||
units microns
|
||||
|
||||
# Pick up values from the first entry returned
|
||||
|
||||
set tval [lindex [setlabel text] 0]
|
||||
|
|
@ -157,6 +161,7 @@ proc magic::analyze_labels {} {
|
|||
set oval [lindex [setlabel offset] 0]
|
||||
set lval [lindex [setlabel layer] 0]
|
||||
set kval [lindex [setlabel sticky] 0]
|
||||
set sval [lindex [setlabel size] 0]
|
||||
set isport [lindex [port exists] 0]
|
||||
if {$isport} {
|
||||
set pval [lindex [port index] 0]
|
||||
|
|
@ -164,14 +169,6 @@ proc magic::analyze_labels {} {
|
|||
set pval -1
|
||||
}
|
||||
|
||||
# Rescale internal units to microns
|
||||
set sval [lindex [setlabel size] 0]
|
||||
set sscale [cif scale out]
|
||||
set tmp_pre $::tcl_precision
|
||||
set ::tcl_precision 3
|
||||
set sval [expr $sscale * $sval]
|
||||
set ::tcl_precision $tmp_pre
|
||||
|
||||
.texthelper.text.tent delete 0 end
|
||||
.texthelper.text.tent insert 0 $tval
|
||||
set jbtn [string map {NORTH N WEST W SOUTH S EAST E CENTER center} $jval]
|
||||
|
|
@ -206,6 +203,9 @@ proc magic::analyze_labels {} {
|
|||
pack .texthelper.layer.tent -side left -fill x -expand true
|
||||
pack .texthelper.layer.btn2 -side left
|
||||
}
|
||||
|
||||
# Revert units
|
||||
units {*}$curunits
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -220,6 +220,9 @@ proc magic::change_label {} {
|
|||
return
|
||||
}
|
||||
|
||||
set curunits [units]
|
||||
units microns
|
||||
|
||||
set ltext [.texthelper.text.tent get]
|
||||
set lfont [.texthelper.font.btn cget -text]
|
||||
set lsize [.texthelper.size.tent get]
|
||||
|
|
@ -247,13 +250,10 @@ proc magic::change_label {} {
|
|||
}
|
||||
}
|
||||
if {$lsize != ""} {
|
||||
setlabel size ${lsize}um
|
||||
setlabel size $lsize
|
||||
}
|
||||
if {$loff != ""} {
|
||||
set oldunits [units]
|
||||
units internal
|
||||
setlabel offset [join $loff]
|
||||
units $oldunits
|
||||
}
|
||||
if {$lrot != ""} {
|
||||
setlabel rotate $lrot
|
||||
|
|
@ -274,6 +274,8 @@ proc magic::change_label {} {
|
|||
port remove
|
||||
}
|
||||
}
|
||||
|
||||
units {*}$curunits
|
||||
}
|
||||
|
||||
proc magic::make_new_label {} {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,13 @@
|
|||
# Added spice-to-layout procedure
|
||||
# March 4, 2026
|
||||
# Changed to make use of new "units" command
|
||||
# March 26, 2026
|
||||
# Added behavior to handle ideal devices (resistor, capacitor,
|
||||
# inductor)
|
||||
# April 2, 2026
|
||||
# Changed the hash to MurmurHash3, as the existing hash
|
||||
# is prone to creating name collisions (rare, but not rare
|
||||
# enough).
|
||||
#--------------------------------------------------------------
|
||||
# Sets up the environment for a toolkit. The toolkit must
|
||||
# supply a namespace that is the "library name". For each
|
||||
|
|
@ -202,7 +209,7 @@ proc magic::generate_layout_add {subname subpins complist library} {
|
|||
select cell $inst
|
||||
delete
|
||||
}
|
||||
cellname delete $child
|
||||
cellname delete $child -noprompt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -281,8 +288,13 @@ proc magic::generate_layout_add {subname subpins complist library} {
|
|||
set paramlist {}
|
||||
|
||||
# NOTE: This routine deals with subcircuit calls and devices
|
||||
# with models. It needs to determine when a device is instantiated
|
||||
# without a model, and ignore such devices.
|
||||
# with models. There are two exceptions, for toolkits which
|
||||
# wish to implement a way to generate unmodeled capacitors,
|
||||
# resistors, or inductors based on value; for example, metal
|
||||
# interdigitated capacitors. For those exceptions, the device
|
||||
# value is recast as a parameter called "value", and the device
|
||||
# is given a model "capacitor", "resistor", or "inductor",
|
||||
# respectively.
|
||||
|
||||
# Parse SPICE line into pins, device name, and parameters. Make
|
||||
# sure parameters incorporate quoted expressions as {} or ''.
|
||||
|
|
@ -326,6 +338,23 @@ proc magic::generate_layout_add {subname subpins complist library} {
|
|||
set devtype [lindex $pinlist end]
|
||||
set pinlist [lrange $pinlist 0 end-1]
|
||||
|
||||
# Ideal device check: "devtype" will start with a digit.
|
||||
# The instname will begin with "c", "r", or "l".
|
||||
|
||||
if {[regexp {^([0-9\.]+.*)} $devtype pval]} {
|
||||
set comptype [string tolower [string range $instname 0 0]]
|
||||
if {$comptype == "c"} {
|
||||
lappend paramlist [list value $pval]
|
||||
set devtype capacitor
|
||||
} elseif {$comptype == "r"} {
|
||||
lappend paramlist [list value $pval]
|
||||
set devtype resistor
|
||||
} elseif {$comptype == "l"} {
|
||||
lappend paramlist [list value $pval]
|
||||
set devtype inductor
|
||||
}
|
||||
}
|
||||
|
||||
set mult 1
|
||||
foreach param $paramlist {
|
||||
set parmname [lindex $param 0]
|
||||
|
|
@ -337,6 +366,27 @@ proc magic::generate_layout_add {subname subpins complist library} {
|
|||
}
|
||||
}
|
||||
|
||||
# Check if devtype has routines by looking for ${devtype}_defaults.
|
||||
# If not found, do a case-insensitive check against all devices
|
||||
# before deciding that devtype is a subcircuit and not a device.
|
||||
# If found by case-insensitive check, then change the device name
|
||||
# to the one used in the library.
|
||||
|
||||
if {$library != ""} {
|
||||
set alldevices [namespace eval ::${library} {info procs}]
|
||||
} else {
|
||||
set alldevices [namespace eval ::${PDKNAMESPACE} {info procs}]
|
||||
}
|
||||
set devdefault [lsearch $alldevices ${devtype}_defaults]
|
||||
if {$devdefault == -1} {
|
||||
set devdefault [lsearch -nocase $alldevices ${devtype}_defaults]
|
||||
if {$devdefault != -1} {
|
||||
set devprocname [lindex $alldevices $devdefault]
|
||||
set devproclist [split $devprocname "_"]
|
||||
set devtype [lindex $devproclist 0]
|
||||
}
|
||||
}
|
||||
|
||||
# devtype is assumed to be in library. If not, it will attempt to
|
||||
# use 'getcell' on devtype. Note that this code depends on the
|
||||
# PDK setting varible PDKNAMESPACE.
|
||||
|
|
@ -500,7 +550,7 @@ proc magic::netlist_to_layout {netfile library} {
|
|||
set subname [lindex $ftokens 1]
|
||||
set subpins [lrange $ftokens 2 end]
|
||||
set insub true
|
||||
} elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \
|
||||
} elseif {[regexp -nocase {^[xmcrldq]([^ \t]+)[ \t](.*)$} $line \
|
||||
valid instname rest]} {
|
||||
lappend toplist $line
|
||||
} elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \
|
||||
|
|
@ -515,7 +565,7 @@ proc magic::netlist_to_layout {netfile library} {
|
|||
set subname ""
|
||||
set subpins ""
|
||||
set complist {}
|
||||
} elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \
|
||||
} elseif {[regexp -nocase {^[xmcrldq]([^ \t]+)[ \t](.*)$} $line \
|
||||
valid instname rest]} {
|
||||
lappend complist $line
|
||||
} elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \
|
||||
|
|
@ -798,11 +848,16 @@ proc magic::gencell_change {instname gencell_type library parameters} {
|
|||
set pdefaults [${library}::${gencell_type}_defaults]
|
||||
# Pull user-entered values from dialog
|
||||
set parameters [dict merge $pdefaults [magic::gencell_getparams]]
|
||||
set newinstname [.params.title.ient get]
|
||||
if {$newinstname == "(default)"} {set newinstname $instname}
|
||||
if {$newinstname == $instname} {set newinstname $instname}
|
||||
if {[instance list exists $newinstname] != ""} {set newinstname $instname}
|
||||
}
|
||||
|
||||
# Attempt to set the new instance name as specified in the dialog.
|
||||
# If the entry is "(default)" or if there is a name collision,
|
||||
# revert the name to the original name.
|
||||
|
||||
set newinstname [.params.title.ient get]
|
||||
if {$newinstname == "(default)"} {set newinstname $instname}
|
||||
if {[instance list exists $newinstname] != ""} {set newinstname $instname}
|
||||
|
||||
if {[dict exists $parameters gencell]} {
|
||||
# Setting special parameter "gencell" forces the gencell to change type
|
||||
set gencell_type [dict get $parameters gencell]
|
||||
|
|
@ -820,6 +875,20 @@ proc magic::gencell_change {instname gencell_type library parameters} {
|
|||
set gsuffix [magic::get_gencell_hash ${parameters}]
|
||||
set gname ${gencell_type}_${gsuffix}
|
||||
|
||||
# Handle instance name changing first. If no parameters changed, then
|
||||
# we're done.
|
||||
if {$newinstname != $instname} {
|
||||
identify $newinstname
|
||||
# The buttons "Apply" and "Okay" need to be changed for the new
|
||||
# instance name
|
||||
catch {.params.buttons.apply config -command \
|
||||
"magic::gencell_change $newinstname $gencell_type $library {}"}
|
||||
catch {.params.buttons.okay config -command \
|
||||
"magic::gencell_change $newinstname $gencell_type $library {} ;\
|
||||
destroy .params"}
|
||||
set instname $newinstname
|
||||
}
|
||||
|
||||
# Guard against instance having been deleted. Also, if parameters have not
|
||||
# changed as evidenced by the cell suffix not changing, then nothing further
|
||||
# needs to be done.
|
||||
|
|
@ -855,31 +924,9 @@ proc magic::gencell_change {instname gencell_type library parameters} {
|
|||
if {$abox != ""} {box values {*}$abox}
|
||||
set newinstname [getcell $gname $orient]
|
||||
select cell $newinstname
|
||||
set origname $newinstname
|
||||
expand
|
||||
|
||||
# If the old instance name was not formed from the old cell name,
|
||||
# then keep the old instance name.
|
||||
if {[string first $old_gname $instname] != 0} {
|
||||
set newinstname $instname
|
||||
}
|
||||
|
||||
if {[cellname list parents $old_gname] == []} {
|
||||
# If the original cell has no intances left, delete it. It can
|
||||
# be regenerated if and when necessary.
|
||||
cellname delete $old_gname
|
||||
}
|
||||
|
||||
} else {
|
||||
select cell $instname
|
||||
set orient [instance list orientation]
|
||||
set abox [instance list abutment]
|
||||
delete
|
||||
|
||||
# There is no cell of this name, so generate one and instantiate it.
|
||||
if {$abox != ""} {box values {*}$abox}
|
||||
set newinstname [magic::gencell_create $gencell_type $library $parameters $orient]
|
||||
select cell $newinstname
|
||||
|
||||
# If the old instance name was not formed from the old cell name,
|
||||
# then keep the old instance name.
|
||||
if {[string first $old_gname $instname] != 0} {
|
||||
|
|
@ -893,6 +940,47 @@ proc magic::gencell_change {instname gencell_type library parameters} {
|
|||
"magic::gencell_change $newinstname $gencell_type $library {} ;\
|
||||
destroy .params"}
|
||||
}
|
||||
|
||||
if {[cellname list parents $old_gname] == []} {
|
||||
# If the original cell has no intances left, delete it. It can
|
||||
# be regenerated if and when necessary.
|
||||
cellname delete $old_gname -noprompt
|
||||
select cell $origname
|
||||
}
|
||||
|
||||
} else {
|
||||
select cell $instname
|
||||
set orient [instance list orientation]
|
||||
set abox [instance list abutment]
|
||||
delete
|
||||
|
||||
# There is no cell of this name, so generate one and instantiate it.
|
||||
if {$abox != ""} {box values {*}$abox}
|
||||
set newinstname [magic::gencell_create $gencell_type $library $parameters $orient]
|
||||
select cell $newinstname
|
||||
set origname $newinstname
|
||||
|
||||
# If the old instance name was not formed from the old cell name,
|
||||
# then keep the old instance name.
|
||||
if {[string first $old_gname $instname] != 0} {
|
||||
set newinstname $instname
|
||||
} else {
|
||||
# The buttons "Apply" and "Okay" need to be changed for the new
|
||||
# instance name
|
||||
catch {.params.buttons.apply config -command \
|
||||
"magic::gencell_change $newinstname $gencell_type $library {}"}
|
||||
catch {.params.buttons.okay config -command \
|
||||
"magic::gencell_change $newinstname $gencell_type $library {} ;\
|
||||
destroy .params"}
|
||||
}
|
||||
|
||||
# If the old cell is not used anywhere, delete it
|
||||
if {[cellname list parents $old_gname] == []} {
|
||||
# If the original cell has no intances left, delete it. It can
|
||||
# be regenerated if and when necessary.
|
||||
cellname delete $old_gname -noprompt
|
||||
select cell $origname
|
||||
}
|
||||
}
|
||||
identify $newinstname
|
||||
eval "box values $savebox"
|
||||
|
|
@ -1023,38 +1111,47 @@ proc magic::get_gencell_name {gencell_type} {
|
|||
# gives a result that is repeatable for the same set of
|
||||
# parameter values with a very low probability of a collision.
|
||||
#
|
||||
# The hash function is similar to elfhash but reduced from 32
|
||||
# to 30 bits so that the result can form a 6-character value
|
||||
# in base32 with all characters being valid for a SPICE subcell
|
||||
# name (e.g., alphanumeric only and case-insensitive).
|
||||
# The hash function is murmur3 but reduced from 32 to 30 bits
|
||||
# so that the result can form a 6-character value in base36
|
||||
# with all characters being valid for a SPICE subcell name
|
||||
# (e.g., alphanumeric only and case-insensitive). This
|
||||
# reduces the space from ~4 billion unique suffixes to ~1
|
||||
# billion; however, even a complex mixed-signal chip design
|
||||
# is unlikely to have more than a few hundred unique parameter
|
||||
# sets for any given device.
|
||||
#
|
||||
# Code courtesy of ChatGPT, derived from my implementation.
|
||||
#----------------------------------------------------------------
|
||||
|
||||
proc magic::get_gencell_hash {parameters} {
|
||||
set hash 0
|
||||
# Apply hash
|
||||
dict for {key value} $parameters {
|
||||
foreach s [split $value {}] {
|
||||
set hash [expr {($hash << 4) + [scan $s %c]}]
|
||||
set high [expr {$hash & 0x03c0000000}]
|
||||
set hash [expr {$hash ^ ($high >> 30)}]
|
||||
set hash [expr {$hash & (~$high)}]
|
||||
}
|
||||
# Canonicalize: sort by key
|
||||
set keys [lsort [dict keys $parameters]]
|
||||
|
||||
# Build input string (values only, but delimited)
|
||||
set input ""
|
||||
foreach k $keys {
|
||||
set value [magic::normalize_value [dict get $parameters $k]]
|
||||
append input "${value};"
|
||||
}
|
||||
# Divide hash up into 5 bit values and convert to base32
|
||||
# using letters A-Z less I and O, and digits 2-9.
|
||||
|
||||
# Compute Murmur hash
|
||||
set hash [magic::murmur3_32 $input]
|
||||
|
||||
# Convert to 6-character base32
|
||||
set cvals ""
|
||||
for {set i 0} {$i < 6} {incr i} {
|
||||
set oval [expr {($hash >> ($i * 5)) & 0x1f}]
|
||||
set oval [expr {($hash >> ($i * 5)) & 0x1f}]
|
||||
|
||||
if {$oval < 8} {
|
||||
set bval [expr {$oval + 50}]
|
||||
} elseif {$oval < 16} {
|
||||
set bval [expr {$oval + 57}]
|
||||
} elseif {$oval < 21} {
|
||||
set bval [expr {$oval + 58}]
|
||||
} else {
|
||||
set bval [expr {$oval + 59}]
|
||||
}
|
||||
append cvals [binary format c* $bval]
|
||||
set bval [expr {$oval + 50}] ;# '2'-'9'
|
||||
} elseif {$oval < 16} {
|
||||
set bval [expr {$oval + 57}] ;# 'A'-'H'
|
||||
} elseif {$oval < 21} {
|
||||
set bval [expr {$oval + 58}] ;# 'J'-'N'
|
||||
} else {
|
||||
set bval [expr {$oval + 59}] ;# 'P'-'Z'
|
||||
}
|
||||
append cvals [binary format c* $bval]
|
||||
}
|
||||
return $cvals
|
||||
}
|
||||
|
|
@ -1178,17 +1275,7 @@ proc magic::add_entry {pname ptext parameters} {
|
|||
proc magic::add_check_callbacks {gencell_type library} {
|
||||
set wlist [winfo children .params.body.area.edits]
|
||||
foreach w $wlist {
|
||||
if {[regexp {\.params\.body\.area\.edits\.(.+)_ent} $w valid pname]} {
|
||||
# Add callback on enter or focus out
|
||||
bind $w <Return> \
|
||||
"magic::update_dialog {} $pname $gencell_type $library"
|
||||
bind $w <FocusOut> \
|
||||
"magic::update_dialog {} $pname $gencell_type $library"
|
||||
}
|
||||
if {[regexp {\.params\.body\.area\.edits\.(.+)_sel} $w valid pname]} {
|
||||
magic::add_dependency \{\} $gencell_type $library $pname
|
||||
}
|
||||
if {[regexp {\.params\.body\.area\.edits\.(.+)_chk} $w valid pname]} {
|
||||
if {[regexp {\.params\.body\.area\.edits\.(.+)_.+} $w valid pname]} {
|
||||
magic::add_dependency \{\} $gencell_type $library $pname
|
||||
}
|
||||
}
|
||||
|
|
@ -1207,6 +1294,16 @@ proc magic::add_check_callbacks {gencell_type library} {
|
|||
# dictionary.
|
||||
#
|
||||
# Also handle dependencies on checkboxes and selection lists
|
||||
#
|
||||
# If dependency callbacks exist, then chain them together.
|
||||
# A final default dependency will be added to all entries
|
||||
# to run the "check" procedure for the device. Dependencies
|
||||
# that are more targeted get run first.
|
||||
#
|
||||
# NOTE: The "check" procedure must be the first in the
|
||||
# list, as otherwise, any invalid entry that is corrected
|
||||
# by the check callback will have been used to evaluate
|
||||
# dependent values.
|
||||
#----------------------------------------------------------
|
||||
|
||||
proc magic::add_dependency {callback gencell_type library args} {
|
||||
|
|
@ -1221,21 +1318,28 @@ proc magic::add_dependency {callback gencell_type library args} {
|
|||
foreach pname $args {
|
||||
if {[lsearch $clist .params.body.area.edits.${pname}_ent] >= 0} {
|
||||
# Add callback on enter or focus out
|
||||
bind .params.body.area.edits.${pname}_ent <Return> \
|
||||
"magic::update_dialog $callback $pname $gencell_type $library"
|
||||
bind .params.body.area.edits.${pname}_ent <FocusOut> \
|
||||
"magic::update_dialog $callback $pname $gencell_type $library"
|
||||
set oldbind [bind .params.body.area.edits.${pname}_ent <Return>]
|
||||
set newbind "magic::update_dialog $callback $pname $gencell_type $library"
|
||||
if {$oldbind != {}} {set newbind "$oldbind ; $newbind"}
|
||||
bind .params.body.area.edits.${pname}_ent <Return> $newbind
|
||||
set oldbind [bind .params.body.area.edits.${pname}_ent <FocusOut>]
|
||||
set newbind "magic::update_dialog $callback $pname $gencell_type $library"
|
||||
if {$oldbind != {}} {set newbind "$oldbind ; $newbind"}
|
||||
bind .params.body.area.edits.${pname}_ent <FocusOut> $newbind
|
||||
} elseif {[lsearch $clist .params.body.area.edits.${pname}_chk] >= 0} {
|
||||
# Add callback on checkbox change state
|
||||
.params.body.area.edits.${pname}_chk configure -command \
|
||||
"magic::update_dialog $callback $pname $gencell_type $library"
|
||||
set oldcmd [.params.body.area.edits.${pname}_chk cget -command]
|
||||
set newcmd "magic::update_dialog $callback $pname $gencell_type $library"
|
||||
if {$oldcmd != {}} {set newcmd "$oldcmd ; $newcmd"}
|
||||
.params.body.area.edits.${pname}_chk configure -command $newcmd
|
||||
} elseif {[lsearch $clist .params.body.area.edits.${pname}_sel] >= 0} {
|
||||
set smenu .params.body.area.edits.${pname}_sel.menu
|
||||
set sitems [${smenu} index end]
|
||||
for {set idx 0} {$idx <= $sitems} {incr idx} {
|
||||
set curcommand [${smenu} entrycget $idx -command]
|
||||
${smenu} entryconfigure $idx -command "$curcommand ; \
|
||||
magic::update_dialog $callback $pname $gencell_type $library"
|
||||
set oldcmd [${smenu} entrycget $idx -command]
|
||||
set newcmd "magic::update_dialog $callback $pname $gencell_type $library"
|
||||
if {$oldcmd != {}} {set newcmd "$oldcmd ; $newcmd"}
|
||||
${smenu} entryconfigure $idx -command $newcmd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1256,13 +1360,13 @@ proc magic::update_dialog {callback pname gencell_type library} {
|
|||
set parameters [dict merge $pdefaults [magic::gencell_getparams]]
|
||||
}
|
||||
|
||||
if {$callback != {}} {
|
||||
set parameters [$callback $pname $parameters]
|
||||
}
|
||||
if {[catch {set parameters [${library}::${gencell_type}_check $parameters]} \
|
||||
checkerr]} {
|
||||
puts stderr $checkerr
|
||||
}
|
||||
if {$callback != {}} {
|
||||
set parameters [$callback $pname $parameters]
|
||||
}
|
||||
magic::gencell_setparams $parameters
|
||||
}
|
||||
|
||||
|
|
@ -1626,3 +1730,99 @@ proc magic::gencell_dialog {instname gencell_type library parameters} {
|
|||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Implementation of murmur3 hash, 32 bits
|
||||
# Code courtesy of ChatGPT.
|
||||
#-------------------------------------------------------------
|
||||
|
||||
proc magic::murmur3_32 {key {seed 0}} {
|
||||
set length [string length $key]
|
||||
|
||||
set c1 0xcc9e2d51
|
||||
set c2 0x1b873593
|
||||
|
||||
set h1 $seed
|
||||
|
||||
# Body (process 4 bytes at a time)
|
||||
set nblocks [expr {$length / 4}]
|
||||
for {set i 0} {$i < $nblocks} {incr i} {
|
||||
binary scan [string range $key [expr {$i*4}] [expr {$i*4+3}]] i k1
|
||||
|
||||
set k1 [expr {($k1 * $c1) & 0xffffffff}]
|
||||
set k1 [expr {(($k1 << 15) | (($k1 & 0xffffffff) >> 17)) & 0xffffffff}]
|
||||
set k1 [expr {($k1 * $c2) & 0xffffffff}]
|
||||
|
||||
set h1 [expr {$h1 ^ $k1}]
|
||||
set h1 [expr {(($h1 << 13) | (($h1 & 0xffffffff) >> 19)) & 0xffffffff}]
|
||||
set h1 [expr {(($h1 * 5) + 0xe6546b64) & 0xffffffff}]
|
||||
}
|
||||
|
||||
# Tail
|
||||
set k1 0
|
||||
set tail_index [expr {$nblocks * 4}]
|
||||
set tail [string range $key $tail_index end]
|
||||
set remaining [string length $tail]
|
||||
|
||||
if {$remaining >= 3} {
|
||||
binary scan [string index $tail 2] c b
|
||||
set k1 [expr {$k1 ^ (($b & 0xff) << 16)}]
|
||||
}
|
||||
if {$remaining >= 2} {
|
||||
binary scan [string index $tail 1] c b
|
||||
set k1 [expr {$k1 ^ (($b & 0xff) << 8)}]
|
||||
}
|
||||
if {$remaining >= 1} {
|
||||
binary scan [string index $tail 0] c b
|
||||
set k1 [expr {$k1 ^ ($b & 0xff)}]
|
||||
set k1 [expr {($k1 * $c1) & 0xffffffff}]
|
||||
set k1 [expr {(($k1 << 15) | (($k1 & 0xffffffff) >> 17)) & 0xffffffff}]
|
||||
set k1 [expr {($k1 * $c2) & 0xffffffff}]
|
||||
set h1 [expr {$h1 ^ $k1}]
|
||||
}
|
||||
|
||||
# Finalization (fmix)
|
||||
set h1 [expr {$h1 ^ $length}]
|
||||
set h1 [expr {$h1 ^ (($h1 & 0xffffffff) >> 16)}]
|
||||
set h1 [expr {($h1 * 0x85ebca6b) & 0xffffffff}]
|
||||
set h1 [expr {$h1 ^ (($h1 & 0xffffffff) >> 13)}]
|
||||
set h1 [expr {($h1 * 0xc2b2ae35) & 0xffffffff}]
|
||||
set h1 [expr {$h1 ^ (($h1 & 0xffffffff) >> 16)}]
|
||||
|
||||
return $h1
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Numerical normalization: Avoid having different suffixes
|
||||
# for cells with the same parameter values due to Tcl handling
|
||||
# numerical values as strings, which makes "2", "2.0", and "2e0"
|
||||
# all separate values. If hashed on the verbatim values, then
|
||||
# the same device with the same parameters can have many
|
||||
# different cell names, even though the layout is exactly the
|
||||
# same. Avoid this by detecting when a parameter value is
|
||||
# numeric and enforcing a consistent format (fixed precision,
|
||||
# four decimal places).
|
||||
#
|
||||
# Code courtesy of ChatGPT
|
||||
#-------------------------------------------------------------
|
||||
|
||||
proc magic::normalize_value {value} {
|
||||
# Detect if value is numeric
|
||||
if {[string is double -strict $value]} {
|
||||
set num [expr {double($value)}]
|
||||
|
||||
# Check if effectively integer
|
||||
if {abs($num - round($num)) < 1e-9} {
|
||||
return [format "%d" [expr {int(round($num))}]]
|
||||
}
|
||||
|
||||
# Otherwise, format to fixed precision (3 decimal places)
|
||||
set str [format "%.3f" $num]
|
||||
|
||||
# Strip trailing zeros
|
||||
regsub {\.?0+$} $str "" str
|
||||
|
||||
return $str
|
||||
}
|
||||
|
||||
# Non-numeric: return as-is
|
||||
return $value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -534,8 +534,11 @@ proc magic::enable_tools {} {
|
|||
# The user can change these bindings at will by using the
|
||||
# "macro" command when the tool is active.
|
||||
|
||||
# NOTE: Do not name a tool "netlist" because it will get
|
||||
# confused with the "netlist" window.
|
||||
|
||||
magic::macro copy wiring
|
||||
magic::macro copy netlist
|
||||
magic::macro copy nettool
|
||||
magic::macro copy pick
|
||||
|
||||
magic::tool wiring
|
||||
|
|
@ -549,7 +552,7 @@ proc magic::enable_tools {} {
|
|||
macro Button4 "wire incr width ; wire show"
|
||||
macro Button5 "wire decr width ; wire show"
|
||||
|
||||
magic::tool netlist
|
||||
magic::tool nettool
|
||||
macro Button1 "netlist select"
|
||||
macro Button2 "netlist join"
|
||||
macro Button3 "netlist terminal"
|
||||
|
|
@ -704,8 +707,8 @@ proc magic::tool {{type next}} {
|
|||
if {$type == "next"} {
|
||||
switch $Opts(tool) {
|
||||
box { set type wiring }
|
||||
wiring { set type netlist }
|
||||
netlist { set type pick }
|
||||
wiring { set type nettool }
|
||||
nettool { set type pick }
|
||||
pick { set type box }
|
||||
}
|
||||
}
|
||||
|
|
@ -761,9 +764,9 @@ proc magic::tool {{type next}} {
|
|||
set Opts(tool) wiring
|
||||
cursor 19 ;# sets the cursor
|
||||
}
|
||||
netlist {
|
||||
nettool {
|
||||
puts stdout {Switching to NETLIST tool.}
|
||||
set Opts(tool) netlist
|
||||
set Opts(tool) nettool
|
||||
cursor 18 ;# sets the cursor
|
||||
}
|
||||
pick {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
#ifndef _MAGIC__TEXTIO__TEXTIO_H
|
||||
#define _MAGIC__TEXTIO__TEXTIO_H
|
||||
|
||||
#include <stdarg.h> /* va_list */
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/dqueue.h" /* DQueue */
|
||||
|
||||
|
|
|
|||
|
|
@ -42,20 +42,6 @@ typedef struct {
|
|||
#define TX_PROMPT '>'
|
||||
#define TX_CMD_PROMPT ":"
|
||||
|
||||
/* all of the state associated with a tty terminal */
|
||||
#if !defined(SYSV) && !defined(CYGWIN) && !defined(__OpenBSD__) && !defined(EMSCRIPTEN)
|
||||
#if defined(HAVE_SYS_IOCTL_COMPAT_H) || defined(HAVE_SGTTY_H)
|
||||
#if defined(HAVE_SYS_IOCTL_COMPAT_H)
|
||||
#include <sys/ioctl_compat.h> /* replaced sgtty.h */
|
||||
#elif defined(HAVE_SGTTY_H)
|
||||
#include <sgtty.h>/* legacy - struct sgttyb{} defn */
|
||||
#endif
|
||||
typedef struct {
|
||||
struct sgttyb tx_i_sgtty;
|
||||
struct tchars tx_i_tchars;
|
||||
} txTermState;
|
||||
#endif /* HAVE_SYS_IOCTL_COMPAT_H || HAVE_SGTTY_H */
|
||||
#endif /* SYSV */
|
||||
|
||||
extern bool TxGetInputEvent(bool block, bool returnOnSigWinch);
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ static char rcsid[] __attribute__ ((unused)) ="$Header: /usr/cvsroot/magic-8.0/t
|
|||
#endif
|
||||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/magic.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
|
|
|
|||
125
textio/txInput.c
125
textio/txInput.c
|
|
@ -32,14 +32,13 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <dirent.h>
|
||||
|
||||
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/main.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "textio/txcommands.h"
|
||||
#include "textio/textioInt.h"
|
||||
#include "utils/magsgtty.h" /* txTermState */
|
||||
#include "utils/dqueue.h"
|
||||
#include "utils/macros.h"
|
||||
#include "utils/hash.h"
|
||||
|
|
@ -1225,36 +1224,21 @@ TxGetLine(
|
|||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#if defined(SYSV) || defined(CYGWIN)
|
||||
|
||||
void
|
||||
txGetTermState(
|
||||
struct termio *buf)
|
||||
{
|
||||
ioctl( fileno( stdin ), TCGETA, buf);
|
||||
}
|
||||
|
||||
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
|
||||
void
|
||||
txGetTermState(
|
||||
struct termios *buf)
|
||||
{
|
||||
(void) tcgetattr(fileno(stdin), buf);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void
|
||||
txGetTermState(
|
||||
txTermState *buf)
|
||||
{
|
||||
#if defined(HAVE_TERMIOS_H)
|
||||
(void) tcgetattr(fileno(stdin), &buf->termios);
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
ioctl(fileno(stdin), TCGETA, &buf->termio);
|
||||
#else /* sgtty */
|
||||
ASSERT(TxStdinIsatty, "txGetTermState");
|
||||
/* save the current terminal characteristics */
|
||||
(void) ioctl(fileno(stdin), TIOCGETP, (char *) &(buf->tx_i_sgtty) );
|
||||
(void) ioctl(fileno(stdin), TIOCGETC, (char *) &(buf->tx_i_tchars) );
|
||||
(void) ioctl(fileno(stdin), TIOCGETP, (char *) &buf->tx_i_sgtty);
|
||||
(void) ioctl(fileno(stdin), TIOCGETC, (char *) &buf->tx_i_tchars);
|
||||
#endif
|
||||
}
|
||||
#endif /* SYSV */
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -1273,24 +1257,17 @@ txGetTermState(
|
|||
|
||||
void
|
||||
txSetTermState(
|
||||
#if defined(SYSV) || defined(CYGWIN)
|
||||
struct termio *buf
|
||||
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
struct termios *buf
|
||||
#else
|
||||
txTermState *buf
|
||||
#endif /* SYSV */
|
||||
)
|
||||
txTermState *buf)
|
||||
{
|
||||
#if defined(SYSV) || defined(CYGWIN)
|
||||
ioctl( fileno(stdin), TCSETAF, buf );
|
||||
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
(void) tcsetattr( fileno(stdin), TCSANOW, buf );
|
||||
#else
|
||||
#if defined(HAVE_TERMIOS_H)
|
||||
(void) tcsetattr(fileno(stdin), TCSANOW, &buf->termios);
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
ioctl(fileno(stdin), TCSETAF, &buf->termio);
|
||||
#else /* sgtty */
|
||||
/* set the current terminal characteristics */
|
||||
(void) ioctl(fileno(stdin), TIOCSETN, (char *) &(buf->tx_i_sgtty) );
|
||||
(void) ioctl(fileno(stdin), TIOCSETC, (char *) &(buf->tx_i_tchars) );
|
||||
#endif /* SYSV */
|
||||
(void) ioctl(fileno(stdin), TIOCSETN, (char *) &buf->tx_i_sgtty);
|
||||
(void) ioctl(fileno(stdin), TIOCSETC, (char *) &buf->tx_i_tchars);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1313,37 +1290,27 @@ txSetTermState(
|
|||
|
||||
void
|
||||
txInitTermRec(
|
||||
#if defined(SYSV) || defined(CYGWIN)
|
||||
struct termio *buf
|
||||
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
struct termios *buf
|
||||
#else
|
||||
txTermState *buf
|
||||
#endif /* SYSV */
|
||||
)
|
||||
txTermState *buf)
|
||||
{
|
||||
#if defined(SYSV) || defined(CYGWIN) || defined(__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
buf->c_lflag = ISIG; /* raw: no echo and no processing, allow signals */
|
||||
buf->c_cc[ VMIN ] = 1;
|
||||
buf->c_cc[ VTIME ] = 0;
|
||||
#else
|
||||
#if defined(HAVE_TERMIOS_H)
|
||||
buf->termios.c_lflag = ISIG; /* raw: no echo and no processing, allow signals */
|
||||
buf->termios.c_cc[ VMIN ] = 1;
|
||||
buf->termios.c_cc[ VTIME ] = 0;
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
buf->termio.c_lflag = ISIG; /* raw: no echo and no processing, allow signals */
|
||||
buf->termio.c_cc[ VMIN ] = 1;
|
||||
buf->termio.c_cc[ VTIME ] = 0;
|
||||
#else /* sgtty */
|
||||
/* set things up for us, turn off echo, turn on cbreak, no EOF */
|
||||
buf->tx_i_sgtty.sg_flags |= CBREAK;
|
||||
buf->tx_i_sgtty.sg_flags &= ~ECHO;
|
||||
buf->tx_i_tchars.t_eofc = -1;
|
||||
|
||||
#endif /* SYSV */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if defined(SYSV) || defined(CYGWIN)
|
||||
struct termio closeTermState;
|
||||
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
struct termios closeTermState;
|
||||
#else
|
||||
static txTermState closeTermState;
|
||||
#endif /* SYSV */
|
||||
|
||||
static bool haveCloseState = FALSE;
|
||||
|
||||
|
|
@ -1366,21 +1333,21 @@ static bool haveCloseState = FALSE;
|
|||
void
|
||||
txSaveTerm(void)
|
||||
{
|
||||
#if defined(SYSV) || defined(CYGWIN)
|
||||
ioctl( fileno( stdin ), TCGETA, &closeTermState);
|
||||
txEraseChar = closeTermState.c_cc[VERASE];
|
||||
txKillChar = closeTermState.c_cc[VKILL];
|
||||
TxEOFChar = closeTermState.c_cc[VEOF];
|
||||
TxInterruptChar = closeTermState.c_cc[VINTR];
|
||||
#if defined(HAVE_TERMIOS_H)
|
||||
(void) tcgetattr(fileno(stdin), &closeTermState.termios);
|
||||
txEraseChar = closeTermState.termios.c_cc[VERASE];
|
||||
txKillChar = closeTermState.termios.c_cc[VKILL];
|
||||
TxEOFChar = closeTermState.termios.c_cc[VEOF];
|
||||
TxInterruptChar = closeTermState.termios.c_cc[VINTR];
|
||||
haveCloseState = TRUE;
|
||||
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
(void) tcgetattr( fileno( stdin ), &closeTermState);
|
||||
txEraseChar = closeTermState.c_cc[VERASE];
|
||||
txKillChar = closeTermState.c_cc[VKILL];
|
||||
TxEOFChar = closeTermState.c_cc[VEOF];
|
||||
TxInterruptChar = closeTermState.c_cc[VINTR];
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
ioctl(fileno(stdin), TCGETA, &closeTermState.termio);
|
||||
txEraseChar = closeTermState.termio.c_cc[VERASE];
|
||||
txKillChar = closeTermState.termio.c_cc[VKILL];
|
||||
TxEOFChar = closeTermState.termio.c_cc[VEOF];
|
||||
TxInterruptChar = closeTermState.termio.c_cc[VINTR];
|
||||
haveCloseState = TRUE;
|
||||
#else
|
||||
#else /* sgtty */
|
||||
struct ltchars lt;
|
||||
txGetTermState(&closeTermState);
|
||||
(void) ioctl(fileno(stdin), TIOCGLTC, (char *) <);
|
||||
|
|
@ -1393,7 +1360,7 @@ txSaveTerm(void)
|
|||
TxEOFChar = closeTermState.tx_i_tchars.t_eofc;
|
||||
TxInterruptChar = closeTermState.tx_i_tchars.t_intrc;
|
||||
haveCloseState = TRUE;
|
||||
#endif /* SYSV */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1414,13 +1381,7 @@ txSaveTerm(void)
|
|||
void
|
||||
TxSetTerminal(void)
|
||||
{
|
||||
#if defined(SYSV) || defined(CYGWIN)
|
||||
struct termio buf;
|
||||
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
|
||||
struct termios buf;
|
||||
#else
|
||||
txTermState buf;
|
||||
#endif /* SYSV */
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
/* If using Tk console, don't mess with the terminal settings; */
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/magic.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/magic.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
|
|
|
|||
|
|
@ -21,44 +21,54 @@
|
|||
#ifndef _MAGIC__UTILS__MAGSGTTY_H
|
||||
#define _MAGIC__UTILS__MAGSGTTY_H
|
||||
|
||||
/* maybe this can be #ifndef HAVE_TERMIO_H */
|
||||
#if !defined(SYSV) && !defined(CYGWIN)
|
||||
|
||||
# ifdef ALPHA
|
||||
# undef MAX
|
||||
# undef MIN
|
||||
# endif
|
||||
|
||||
/* unclear what platform requires this OpenBSD/FreeBSD ? */
|
||||
# ifndef COMPAT_43TTY
|
||||
# define COMPAT_43TTY
|
||||
# endif
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_TERMIOS_H)
|
||||
#include <termios.h>
|
||||
#elif defined(HAVE_SYS_IOCTL_COMPAT_H)
|
||||
/* unclear which platform(s) require <sys/ioctl_compat.h> and the structure
|
||||
* of this file is such that it will try to include it by default, better
|
||||
* to invert the #if and only select this on the known platforms that need
|
||||
* it so that <termios.h> goes by default, which exists on MacOSX, Linux, etc..
|
||||
* many possible solutions to make this work by default:
|
||||
* HAVE_SYS_IOCTL_COMPAT_H ? HAVE_TERMIOS_H ? !defined(linux) at top (MaxOSX is BSD type)
|
||||
*/
|
||||
#include <sys/ioctl_compat.h> /* replaced sgtty.h */
|
||||
#elif defined(HAVE_SGTTY_H)
|
||||
#include <sgtty.h> /* legacy - struct sgttyb{} defn */
|
||||
/* In modern times everything has POSIX */
|
||||
#include <termios.h>
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
/* Linux glibx 2.x - present
|
||||
* FreeBSD 14.3-RELEASE - present
|
||||
* Solaris 11.4 - present
|
||||
*/
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
/* Linux glibx 2.x - present (just includes termios.h & sys/ioctl.h)
|
||||
* Linux glibc 2.45+ - not present
|
||||
* FreeBSD 14.3-RELEASE - not present
|
||||
* Solaris 11.4 - present
|
||||
*/
|
||||
#include <termio.h>
|
||||
#else /* sgtty */
|
||||
#if defined(HAVE_SYS_IOCTL_COMPAT_H)
|
||||
/* Linux glibc2.x - not present
|
||||
* FreeBSD 14.3-RELEASE - not present
|
||||
* Solaris 11.4 - not present
|
||||
*/
|
||||
#include <sys/ioctl_compat.h> /* replaced sgtty.h */
|
||||
#elif defined(HAVE_SGTTY_H)
|
||||
/* Linux glibc2.x - present (includes sys/ioctl.h)
|
||||
* FreeBSD 14.3-RELEASE - not present
|
||||
* Solaris 11.4 - present
|
||||
*/
|
||||
#include <sgtty.h> /* legacy - struct sgttyb{} defn */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#if defined(HAVE_TERMIO_H)
|
||||
#include <termio.h>
|
||||
/* all of the state associated with a tty terminal */
|
||||
typedef struct {
|
||||
#if defined(HAVE_TERMIOS_H)
|
||||
struct termios termios;
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
struct termio termio;
|
||||
#else /* sgtty */
|
||||
struct sgttyb tx_i_sgtty;
|
||||
struct tchars tx_i_tchars;
|
||||
#endif
|
||||
} txTermState;
|
||||
|
||||
#endif /* !SYSV && !CYGWIN */
|
||||
|
||||
#endif /* _MAGIC__UTILS__MAGSGTTY_H */
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/main.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "utils/hash.h"
|
||||
#include "utils/macros.h"
|
||||
#include "textio/textio.h"
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/main.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/magsgtty.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "utils/signals.h"
|
||||
|
|
|
|||
|
|
@ -1056,6 +1056,7 @@ windDoMacro(w, cmd, interactive)
|
|||
bool do_help = FALSE;
|
||||
bool do_reverse = FALSE;
|
||||
char *searchterm = NULL;
|
||||
char *clientName = NULL;
|
||||
macrodef *cMacro;
|
||||
HashTable *clienttable;
|
||||
HashEntry *h;
|
||||
|
|
@ -1073,9 +1074,25 @@ windDoMacro(w, cmd, interactive)
|
|||
|
||||
argstart = 1;
|
||||
if (cmd->tx_argc == 1)
|
||||
wc = DBWclientID; /* Added by NP 11/15/04 */
|
||||
wc = DBWclientID; /* Default client */
|
||||
else if (cmd->tx_argc > 1)
|
||||
{
|
||||
wc = WindGetClient(cmd->tx_argv[1], TRUE);
|
||||
if (wc != NULL)
|
||||
{
|
||||
clientName = cmd->tx_argv[1];
|
||||
argstart++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check if argument is a known layout button handler */
|
||||
if (DBWButtonHandlerIndex(cmd->tx_argv[1]) != -1)
|
||||
{
|
||||
clientName = cmd->tx_argv[1];
|
||||
argstart++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (cmd->tx_argc > argstart)
|
||||
{
|
||||
|
|
@ -1116,6 +1133,15 @@ windDoMacro(w, cmd, interactive)
|
|||
wc = DBWclientID;
|
||||
}
|
||||
MacroCopy(wc, cmd->tx_argv[argstart]);
|
||||
|
||||
/* If tool name did not previously exist, then add
|
||||
* it to the list of known tool names, so that it
|
||||
* can be found later by the "macro" command.
|
||||
*/
|
||||
if (DBWButtonHandlerIndex(cmd->tx_argv[argstart]) == -1)
|
||||
DBWAddButtonHandler(cmd->tx_argv[argstart],
|
||||
(const cb_database_buttonhandler_t)NULL,
|
||||
0, (const char *)NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -1147,26 +1173,53 @@ windDoMacro(w, cmd, interactive)
|
|||
|
||||
if (MacroKey(cmd->tx_argv[argstart], &verbose) == 0)
|
||||
if (MacroKey(cmd->tx_argv[argstart + 1], &verbose) != 0)
|
||||
{
|
||||
wc = 0;
|
||||
argstart++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
argstart++;
|
||||
|
||||
/* If a clientName wasn't given, but wc is DBWclientID, then get
|
||||
* the clientName from the default button handler.
|
||||
*/
|
||||
|
||||
if ((clientName == NULL) && (wc == DBWclientID))
|
||||
clientName = DBWGetButtonHandler();
|
||||
|
||||
if (cmd->tx_argc == argstart)
|
||||
{
|
||||
if (wc == (WindClient)0)
|
||||
if (clientName == NULL)
|
||||
h = NULL;
|
||||
else
|
||||
h = HashLookOnly(&MacroClients, (char *)clientName);
|
||||
|
||||
if (h == NULL)
|
||||
{
|
||||
TxError("No such client.\n");
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_Obj *lobj;
|
||||
lobj = Tcl_NewListObj(0, NULL);
|
||||
#endif
|
||||
TxError("Cannot get macro list from current window.\n");
|
||||
#ifndef MAGIC_WRAPPER
|
||||
TxError("List of known macro clients:\n");
|
||||
#endif
|
||||
/* If clientName was not in MacroClients, then what is? */
|
||||
HashStartSearch(&hs);
|
||||
while ((h = HashNext(&MacroClients, &hs)) != NULL)
|
||||
{
|
||||
char *clientName = h->h_key.h_name;
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||
Tcl_NewStringObj(clientName, -1));
|
||||
#else
|
||||
TxError("%s ", clientName);
|
||||
#endif
|
||||
}
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_SetObjResult(magicinterp, lobj);
|
||||
#else
|
||||
TxError("\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
h = HashLookOnly(&MacroClients, (char *)wc);
|
||||
if (h == NULL)
|
||||
return;
|
||||
else
|
||||
{
|
||||
clienttable = (HashTable *)HashGetValue(h);
|
||||
|
|
|
|||
|
|
@ -954,7 +954,7 @@ windXviewCmd(w, cmd)
|
|||
|
||||
celluse = (CellUse *) (w->w_surfaceID);
|
||||
DBExpandAll(celluse, &(celluse->cu_bbox),
|
||||
((DBWclientRec *)w->w_clientData)->dbw_bitmask, FALSE,
|
||||
((DBWclientRec *)w->w_clientData)->dbw_bitmask, DB_UNEXPAND,
|
||||
ViewUnexpandFunc,
|
||||
(ClientData)(pointertype) (((DBWclientRec *)w->w_clientData)->dbw_bitmask));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue