Merge branch 'master' of https://github.com/RTimothyEdwards/magic into spice_hier
This commit is contained in:
commit
d38c088109
926
cif/CIFgen.c
926
cif/CIFgen.c
|
|
@ -1024,6 +1024,27 @@ endbloat:
|
|||
STACKPUSH((ClientData) (tp), stack); \
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------
|
||||
*
|
||||
* cifProcessResetFunc --
|
||||
*
|
||||
* Unmark tiles
|
||||
*
|
||||
* Results: Return 0 to keep the search going.
|
||||
*
|
||||
*-------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifProcessResetFunc(tile, clientData)
|
||||
Tile *tile;
|
||||
ClientData clientData; /* unused */
|
||||
{
|
||||
tile->ti_client = (ClientData) CIF_UNPROCESSED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------
|
||||
*
|
||||
|
|
@ -1260,6 +1281,21 @@ cifBloatAllFunc(tile, bls)
|
|||
STACKPUSH(tp, BloatStack);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset marked tiles */
|
||||
|
||||
if (bloats->bl_plane < 0) /* Bloat types are CIF types */
|
||||
{
|
||||
temps = bls->temps;
|
||||
for (ttype = 0; ttype < TT_MAXTYPES; ttype++, temps++)
|
||||
if (bloats->bl_distance[ttype] > 0)
|
||||
(void) DBSrPaintArea((Tile *)NULL, *temps, &TiPlaneRect,
|
||||
&CIFSolidBits, cifProcessResetFunc, (ClientData)NULL);
|
||||
}
|
||||
else
|
||||
DBSrPaintArea((Tile *)NULL, def->cd_planes[bloats->bl_plane], &TiPlaneRect,
|
||||
&connect, cifProcessResetFunc, (ClientData)NULL);
|
||||
|
||||
return 0; /* Keep the search alive. . . */
|
||||
}
|
||||
|
||||
|
|
@ -2188,28 +2224,6 @@ cifSquaresStripFunc(tile, stripsData)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------
|
||||
*
|
||||
* cifSquaresResetFunc --
|
||||
*
|
||||
* Unmark tiles
|
||||
*
|
||||
* Results: Return 0 to keep the search going.
|
||||
*
|
||||
*-------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifSquaresResetFunc(tile, clientData)
|
||||
Tile *tile;
|
||||
ClientData clientData; /* unused */
|
||||
{
|
||||
tile->ti_client = (ClientData) CIF_UNPROCESSED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------
|
||||
*
|
||||
|
|
@ -2387,10 +2401,6 @@ cifRectBoundingBox(op, cellDef, plane)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear all the tiles that were processed */
|
||||
DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
|
||||
cifSquaresResetFunc, (ClientData)NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2725,7 +2735,7 @@ cifSquaresFillArea(op, cellDef, plane)
|
|||
|
||||
/* Clear all the tiles that were processed */
|
||||
DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
|
||||
cifSquaresResetFunc, (ClientData)NULL);
|
||||
cifProcessResetFunc, (ClientData)NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3088,7 +3098,7 @@ cifSlotsFillArea(op, cellDef, plane)
|
|||
|
||||
/* Clear all the tiles that were processed */
|
||||
DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &CIFSolidBits,
|
||||
cifSquaresResetFunc, (ClientData)NULL);
|
||||
cifProcessResetFunc, (ClientData)NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3775,6 +3785,831 @@ cifSrTiles(cifOp, area, cellDef, temps, func, cdArg)
|
|||
&CIFSolidBits, func, (ClientData) cdArg);
|
||||
}
|
||||
|
||||
/* Data structure to pass plane and minimum width to the callback function */
|
||||
typedef struct _bridgeLimStruct {
|
||||
Plane *plane;
|
||||
BridgeData *bridge;
|
||||
CellDef *def;
|
||||
Plane **temps;
|
||||
TileTypeBitMask co_paintMask;/* Zero or more paint layers to consider. */
|
||||
TileTypeBitMask co_cifMask; /* Zero or more other CIF layers. */
|
||||
} BridgeLimStruct;
|
||||
|
||||
static int xOverlap, yOverlap;
|
||||
|
||||
/* Bridge-lim Check data structure */
|
||||
typedef struct _bridgeLimCheckStruct {
|
||||
Tile *tile; /* Tile that triggered search (ignore this tile) */
|
||||
int direction; /* What outside corner to look for */
|
||||
Tile *violator; /* Return the violator tile in this space */
|
||||
TileType checktype; /* Type to check for, either TT_SPACE or CIF_SOLIDTYPE */
|
||||
long sqdistance; /* Square of the minimum distance */
|
||||
} BridgeLimCheckStruct;
|
||||
/*
|
||||
*-----------------------------------------------------------------------
|
||||
* Callback function for bridgeLimSrTiles used when a limiting layer tile
|
||||
* was found in the specified area. If calcOverlap is TRUE then the xOverlap
|
||||
* and yOverlap are updated and return 0 to continue searching. Otherwise
|
||||
* return 1 to stop the search.
|
||||
*-----------------------------------------------------------------------
|
||||
*/
|
||||
int
|
||||
bridgeLimFound(tile, calcOverlap)
|
||||
Tile *tile;
|
||||
bool calcOverlap;
|
||||
{
|
||||
if (calcOverlap)
|
||||
{
|
||||
if (RIGHT(tile) > xOverlap)
|
||||
xOverlap = RIGHT(tile);
|
||||
if (TOP(tile) > yOverlap)
|
||||
yOverlap = TOP(tile);
|
||||
return 0; // continue searching
|
||||
} else
|
||||
return 1; // tile found, stop the search
|
||||
}
|
||||
|
||||
/*
|
||||
*------------------------------------------------------------------------
|
||||
* Callback function used in bridge-lim operations to find if the specified
|
||||
* area contains tiles of the limiting layers.
|
||||
*------------------------------------------------------------------------
|
||||
*/
|
||||
int
|
||||
bridgeLimSrTiles(brlims, area, calcOverlap)
|
||||
BridgeLimStruct *brlims; /* Bridge-Lim structure. */
|
||||
Rect *area; /* Area of Magic paint to consider. */
|
||||
bool calcOverlap; /* TRUE to calculate the overlap of the limiting tiles in the specified area. */
|
||||
{
|
||||
TileTypeBitMask maskBits;
|
||||
TileType t;
|
||||
int i;
|
||||
Plane **temps = brlims->temps;
|
||||
xOverlap = area->r_xbot;
|
||||
yOverlap = area->r_ybot;
|
||||
|
||||
for (i = PL_DRC_CHECK; i < DBNumPlanes; i++)
|
||||
{
|
||||
maskBits = DBPlaneTypes[i];
|
||||
TTMaskAndMask(&maskBits, &brlims->co_paintMask);
|
||||
if (!TTMaskEqual(&maskBits, &DBZeroTypeBits))
|
||||
if (DBSrPaintArea((Tile *) NULL, brlims->def->cd_planes[i], area, &brlims->co_paintMask, bridgeLimFound, calcOverlap))
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (t = 0; t < TT_MAXTYPES; t++, temps++)
|
||||
if (TTMaskHasType(&brlims->co_cifMask, t))
|
||||
if (DBSrPaintArea((Tile *) NULL, *temps, area, &CIFSolidBits, bridgeLimFound, calcOverlap))
|
||||
return 0;
|
||||
|
||||
if (( xOverlap != area->r_xbot) || (yOverlap != area->r_ybot))
|
||||
return 0; //Constraint tile found
|
||||
else
|
||||
return 1; //Nothing found
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifBridgeLimFunc0 --
|
||||
*
|
||||
* Called for each relevant tile during bridge-lim operations. The
|
||||
* bridge-lim operation is similar to the bridge operation with the
|
||||
* difference that the material created to meet the minimum spacing/width
|
||||
* rules do not overlap the limiting layers.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0 to keep the search alive.
|
||||
*
|
||||
* Side effects:
|
||||
* May paint into cifNewPlane
|
||||
*
|
||||
* Algorithm (based on maximum horizontal stripes rule):
|
||||
* This function grows dimentions of tiles to meet a minimimum width rule (only
|
||||
* applies to vertical or horizontal directions). This is done in two steps:
|
||||
* 1. Adjust tile width to accomplish the minimimum width rule, limited by
|
||||
* the constraint layers.
|
||||
* 2. Search top and bottom tiles of same type, for each segment verify if
|
||||
* height meets the minimimum value, if not, adjust the segment height
|
||||
* but do not paint over limiting layer tiles.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
int
|
||||
cifBridgeLimFunc0(tile, brlims)
|
||||
Tile *tile;
|
||||
BridgeLimStruct *brlims;
|
||||
{
|
||||
Plane *plane = brlims->plane;
|
||||
Rect area, parea;
|
||||
int minDistance = brlims->bridge->br_width;
|
||||
int width, height, ybot0, tp2lim;
|
||||
Tile *tp, *tp2;
|
||||
|
||||
TiToRect(tile, &area);
|
||||
|
||||
/* Check whole tile for minimum width */
|
||||
width = area.r_xtop - area.r_xbot;
|
||||
if (width < minDistance)
|
||||
{
|
||||
area.r_xbot = area.r_xtop - minDistance;
|
||||
if (!bridgeLimSrTiles(brlims, &area, TRUE))
|
||||
{
|
||||
area.r_xbot = MIN(LEFT(tile), xOverlap);
|
||||
area.r_xtop = area.r_xbot + minDistance;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is another tile on top or bottom, and the height is */
|
||||
/* less than minimum, then extend height in the direction of */
|
||||
/* the bordering tile. Otherwise, if the height is less than */
|
||||
/* minimum, then grow considering the limiting layers. */
|
||||
|
||||
height = area.r_ytop - area.r_ybot;
|
||||
if (height < minDistance)
|
||||
{
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
||||
{
|
||||
tp2lim = MAX(LEFT(tp), area.r_xbot);
|
||||
for (tp2 = RT(tile); RIGHT(tp2) > tp2lim; tp2 = BL(tp2))
|
||||
if (LEFT(tp2) < RIGHT(tp))
|
||||
{
|
||||
parea.r_xbot = MAX(LEFT(tp2), tp2lim);
|
||||
parea.r_xtop = MIN(MIN(RIGHT(tp2), RIGHT(tp)), area.r_xtop);
|
||||
if (TiGetBottomType(tp2) == TiGetTopType(tile))
|
||||
parea.r_ytop = TOP(tp2);
|
||||
else
|
||||
parea.r_ytop = area.r_ytop;
|
||||
if (TiGetTopType(tp) == TiGetBottomType(tile))
|
||||
ybot0 = BOTTOM(tp);
|
||||
else
|
||||
ybot0 = area.r_ybot;
|
||||
height = parea.r_ytop - ybot0;
|
||||
if (height < minDistance)
|
||||
{
|
||||
parea.r_ybot = parea.r_ytop - minDistance;
|
||||
if (!bridgeLimSrTiles(brlims, &parea, TRUE))
|
||||
{
|
||||
parea.r_ybot = MIN(ybot0 , yOverlap);
|
||||
parea.r_ytop = parea.r_ybot + minDistance;
|
||||
}
|
||||
DBPaintPlane(cifPlane, &parea, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------
|
||||
* Callback function for cifBridgeLimFunc1 and cifBridgeLimFunc2 to find if
|
||||
* there are violator cells in the search area. If a violator cell is
|
||||
* found, then put the tile pointer in the BridgeCheckStruct and return
|
||||
* value 1 to stop the search. Otherwise return 0 to keep going.
|
||||
*-----------------------------------------------------------------------
|
||||
*/
|
||||
int
|
||||
bridgeLimCheckFunc(tile, brlimcs)
|
||||
Tile *tile;
|
||||
BridgeLimCheckStruct *brlimcs;
|
||||
{
|
||||
int dir = brlimcs->direction;
|
||||
Tile *self = brlimcs->tile;
|
||||
Tile *tp1, *tp2;
|
||||
TileType checktype = brlimcs->checktype;
|
||||
long sqdistance = brlimcs->sqdistance;
|
||||
int dx, dy;
|
||||
long sqcheck;
|
||||
|
||||
if (self == tile) return 0; /* Ignore the triggering tile */
|
||||
|
||||
switch (dir) {
|
||||
case BRIDGE_NW:
|
||||
/* Ignore tile if split, and SE corner is clipped */
|
||||
if (TiGetRightType(tile) == checktype || TiGetBottomType(tile) == checktype)
|
||||
break;
|
||||
for (tp1 = RT(tile); LEFT(tp1) > LEFT(tile); tp1 = BL(tp1));
|
||||
for (tp2 = BL(tile); TOP(tp2) < TOP(tile); tp2 = RT(tp2));
|
||||
if ((TiGetBottomType(tp1) == checktype) &&
|
||||
(TiGetRightType(tp2) == checktype))
|
||||
{
|
||||
dx = LEFT(tile) - RIGHT(self);
|
||||
dy = BOTTOM(self) - TOP(tile);
|
||||
if ((dx > 0) && (dy > 0))
|
||||
{
|
||||
sqcheck = (long)dx*dx + (long)dy*dy;
|
||||
if (sqcheck >= sqdistance)
|
||||
return 0;
|
||||
}
|
||||
brlimcs->violator = tile;
|
||||
return 1; /* Violator found */
|
||||
}
|
||||
break;
|
||||
case BRIDGE_NE:
|
||||
/* Ignore tile if split, and SW corner is clipped */
|
||||
if (TiGetLeftType(tile) == checktype || TiGetBottomType(tile) == checktype)
|
||||
break;
|
||||
tp1 = RT(tile);
|
||||
tp2 = TR(tile);
|
||||
if ((TiGetBottomType(tp1) == checktype) &&
|
||||
(TiGetLeftType(tp2) == checktype))
|
||||
{
|
||||
dx = LEFT(self) - RIGHT(tile);
|
||||
dy = BOTTOM(self) - TOP(tile);
|
||||
if ((dx > 0) && (dy > 0))
|
||||
{
|
||||
sqcheck = (long)dx*dx + (long)dy*dy;
|
||||
if (sqcheck >= sqdistance)
|
||||
return 0;
|
||||
}
|
||||
brlimcs->violator = tile;
|
||||
return 1; /* Violator found */
|
||||
}
|
||||
break;
|
||||
case BRIDGE_SW:
|
||||
/* Ignore tile if split, and NE corner is clipped */
|
||||
if (TiGetRightType(tile) == checktype || TiGetTopType(tile) == checktype)
|
||||
break;
|
||||
tp1 = LB(tile);
|
||||
tp2 = BL(tile);
|
||||
if ((TiGetTopType(tp1) == checktype) &&
|
||||
(TiGetRightType(tp2) == checktype))
|
||||
{
|
||||
dx = LEFT(tile) - RIGHT(self);
|
||||
dy = BOTTOM(tile) - TOP(self);
|
||||
if ((dx > 0) && (dy > 0))
|
||||
{
|
||||
sqcheck = (long)dx*dx + (long)dy*dy;
|
||||
if (sqcheck >= sqdistance)
|
||||
return 0;
|
||||
}
|
||||
brlimcs->violator = tile;
|
||||
return 1; /* Violator found */
|
||||
}
|
||||
break;
|
||||
case BRIDGE_SE:
|
||||
/* Ignore tile if split, and NW corner is clipped */
|
||||
if (TiGetLeftType(tile) == checktype || TiGetTopType(tile) == checktype)
|
||||
break;
|
||||
for (tp1 = LB(tile); RIGHT(tp1) < RIGHT(tile); tp1 = TR(tp1));
|
||||
for (tp2 = TR(tile); BOTTOM(tp2) > BOTTOM(tile); tp2 = LB(tp2));
|
||||
if ((TiGetTopType(tp1) == checktype) &&
|
||||
(TiGetLeftType(tp2) == checktype))
|
||||
{
|
||||
dx = LEFT(self) - RIGHT(tile);
|
||||
dy = BOTTOM(tile) - TOP(self);
|
||||
if ((dx > 0) && (dy > 0))
|
||||
{
|
||||
sqcheck = (long)dx*dx + (long)dy*dy;
|
||||
if (sqcheck >= sqdistance)
|
||||
return 0;
|
||||
}
|
||||
brlimcs->violator = tile;
|
||||
return 1; /* Violator found */
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0; /* Nothing found here, so keep going */
|
||||
}
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------
|
||||
* Callback function used in bridge-lim operations to do not paint areas
|
||||
* where new bridge overlaps the limiting layer tiles.
|
||||
*-----------------------------------------------------------------------
|
||||
*/
|
||||
int
|
||||
bridgeErase(brlims, area)
|
||||
BridgeLimStruct *brlims; /* Bridge-lim structure. */
|
||||
Rect *area; /* Area of Magic paint to consider. */
|
||||
{
|
||||
TileTypeBitMask maskBits;
|
||||
TileType t;
|
||||
int i;
|
||||
Plane **temps = brlims->temps;
|
||||
|
||||
for (i = PL_DRC_CHECK; i < DBNumPlanes; i++)
|
||||
{
|
||||
maskBits = DBPlaneTypes[i];
|
||||
TTMaskAndMask(&maskBits, &brlims->co_paintMask);
|
||||
if (!TTMaskEqual(&maskBits, &DBZeroTypeBits))
|
||||
if (DBSrPaintArea((Tile *) NULL, brlims->def->cd_planes[i], area, &brlims->co_paintMask, cifPaintFunc, CIFEraseTable))
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (t = 0; t < TT_MAXTYPES; t++, temps++)
|
||||
if (TTMaskHasType(&brlims->co_cifMask, t))
|
||||
if (DBSrPaintArea((Tile *) NULL, *temps, area, &CIFSolidBits, cifPaintFunc, CIFEraseTable))
|
||||
return 0;
|
||||
|
||||
return 1; //Nothing found
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifBridgeLimFunc1 --
|
||||
*
|
||||
* Called for each relevant tile during bridge-lim operations. The
|
||||
* bridge-lim operation is similar to the bridge operation with the
|
||||
* difference that the material created to meet the minimum spacing/width
|
||||
* rules do not overlap the limiting layers.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0 to keep the search alive.
|
||||
*
|
||||
* Side effects:
|
||||
* May paint into cifNewPlane
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
int
|
||||
cifBridgeLimFunc1(tile, brlims)
|
||||
Tile *tile;
|
||||
BridgeLimStruct *brlims;
|
||||
{
|
||||
Plane *plane = brlims->plane;
|
||||
Rect area;
|
||||
Tile *tp1, *tp2, *tpx;
|
||||
int width = brlims->bridge->br_width;
|
||||
int spacing = growDistance;
|
||||
BridgeLimCheckStruct brlimcs;
|
||||
brlimcs.sqdistance = (long) spacing * spacing;
|
||||
|
||||
/* If tile is marked, then it has been handled, so ignore it */
|
||||
if (tile->ti_client != (ClientData)CIF_UNPROCESSED) return 0;
|
||||
|
||||
/* Find each tile outside corner (up to four) */
|
||||
|
||||
/* Check for NE outside corner */
|
||||
tp1 = TR(tile); /* Tile on right side at the top of this tile */
|
||||
tp2 = RT(tile); /* Tile on top side at the right of this tile */
|
||||
if ((TiGetLeftType(tp1) == TT_SPACE) &&
|
||||
(TiGetBottomType(tp2) == TT_SPACE))
|
||||
{
|
||||
/* Set search box */
|
||||
area.r_xbot = RIGHT(tile);
|
||||
area.r_xtop = RIGHT(tile) + spacing;
|
||||
area.r_ybot = TOP(tile);
|
||||
area.r_ytop = TOP(tile) + spacing;
|
||||
|
||||
/* Find violator tiles */
|
||||
brlimcs.tile = tile;
|
||||
brlimcs.direction = BRIDGE_SW;
|
||||
brlimcs.checktype = TT_SPACE;
|
||||
if (DBSrPaintArea((Tile *) NULL, plane, &area,
|
||||
&CIFSolidBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
|
||||
{
|
||||
tpx = brlimcs.violator;
|
||||
area.r_xtop = MAX(RIGHT(tile), LEFT(tpx) + width);
|
||||
area.r_ytop = MAX(TOP(tile), BOTTOM(tpx));
|
||||
area.r_xbot = MIN(LEFT(tpx), RIGHT(tile));
|
||||
area.r_ybot = MIN(BOTTOM(tpx), TOP(tile) - width);
|
||||
if (bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
/* First option of bridge can be implemented (there are not limiting tiles in the area)*/
|
||||
area.r_ytop = TOP(tile);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
area.r_xbot = LEFT(tpx);
|
||||
area.r_ytop = MAX(TOP(tile), BOTTOM(tpx));
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
area.r_xtop = MAX(RIGHT(tile), LEFT(tpx));
|
||||
area.r_ytop = MAX(TOP(tile), BOTTOM(tpx) + width);
|
||||
area.r_xbot = MIN(LEFT(tpx), RIGHT(tile) - width);
|
||||
area.r_ybot = MIN(BOTTOM(tpx), TOP(tile));
|
||||
if (bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
/* Second option of bridge can be implemented (there are not limiting tiles in the area)*/
|
||||
area.r_ybot = BOTTOM(tpx);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
area.r_xtop = RIGHT(tile);
|
||||
area.r_ybot = MIN(BOTTOM(tpx), TOP(tile));
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Last option (Limiting tiles are present on both sides, those areas must be excluded from the bridge)*/
|
||||
area.r_xtop = MAX(RIGHT(tile), LEFT(tpx) + width);
|
||||
area.r_ytop = MAX(TOP(tile), BOTTOM(tpx) + width);
|
||||
area.r_xbot = MIN(LEFT(tpx), RIGHT(tile) - width);
|
||||
area.r_ybot = MIN(BOTTOM(tpx), TOP(tile) - width);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
bridgeErase(brlims, &area);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for SW outside corner */
|
||||
tp1 = BL(tile); /* Tile on left side at the bottom of this tile */
|
||||
tp2 = LB(tile); /* Tile on bottom side at the left of this tile */
|
||||
if ((TiGetRightType(tp1) == TT_SPACE) &&
|
||||
(TiGetTopType(tp2) == TT_SPACE))
|
||||
{
|
||||
/* Set search box */
|
||||
area.r_xbot = LEFT(tile) - spacing;
|
||||
area.r_xtop = LEFT(tile);
|
||||
area.r_ybot = BOTTOM(tile) - spacing;
|
||||
area.r_ytop = BOTTOM(tile);
|
||||
|
||||
/* Find violator tiles */
|
||||
brlimcs.tile = tile;
|
||||
brlimcs.direction = BRIDGE_NE;
|
||||
brlimcs.checktype = TT_SPACE;
|
||||
if (DBSrPaintArea((Tile *) NULL, plane, &area,
|
||||
&CIFSolidBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
|
||||
{
|
||||
tpx = brlimcs.violator;
|
||||
area.r_xtop = MAX(RIGHT(tpx), LEFT(tile) + width);
|
||||
area.r_ytop = MAX(TOP(tpx), BOTTOM(tile));
|
||||
area.r_xbot = MIN(LEFT(tile), RIGHT(tpx));
|
||||
area.r_ybot = MIN(BOTTOM(tile), TOP(tpx) - width);
|
||||
if (bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
/* First option of bridge can be implemented (there are not limiting tiles in the area)*/
|
||||
area.r_ytop = TOP(tpx);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
area.r_xbot = LEFT(tile);
|
||||
area.r_ytop = MAX(TOP(tpx), BOTTOM(tile));
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
area.r_xtop = MAX(RIGHT(tpx), LEFT(tile));
|
||||
area.r_ytop = MAX(TOP(tpx), BOTTOM(tile) + width);
|
||||
area.r_xbot = MIN(LEFT(tile), RIGHT(tpx) - width);
|
||||
area.r_ybot = MIN(BOTTOM(tile), TOP(tpx));
|
||||
if (bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
/* Second option of bridge can be implemented (there are not limiting tiles in the area)*/
|
||||
area.r_ybot = BOTTOM(tile);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
area.r_xtop = RIGHT(tpx);
|
||||
area.r_ybot = MIN(BOTTOM(tile), TOP(tpx));
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Last option (Limiting tiles are present on both sides, those areas must be excluded from the bridge)*/
|
||||
area.r_xtop = MAX(RIGHT(tpx), LEFT(tile) + width);
|
||||
area.r_ytop = MAX(TOP(tpx), BOTTOM(tile) + width);
|
||||
area.r_xbot = MIN(LEFT(tile), RIGHT(tpx) - width);
|
||||
area.r_ybot = MIN(BOTTOM(tile), TOP(tpx) - width);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
bridgeErase(brlims, &area);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for SE outside corner */
|
||||
for (tp1 = TR(tile); BOTTOM(tp1) > BOTTOM(tile); tp1 = LB(tp1));
|
||||
for (tp2 = LB(tile); RIGHT(tp1) < RIGHT(tile); tp2 = TR(tp2));
|
||||
if ((TiGetLeftType(tp1) == TT_SPACE) &&
|
||||
(TiGetTopType(tp2) == TT_SPACE))
|
||||
{
|
||||
/* Set search box */
|
||||
area.r_xbot = RIGHT(tile);
|
||||
area.r_xtop = RIGHT(tile) + spacing;
|
||||
area.r_ybot = BOTTOM(tile) - spacing;
|
||||
area.r_ytop = BOTTOM(tile);
|
||||
|
||||
/* Find violator tiles */
|
||||
brlimcs.tile = tile;
|
||||
brlimcs.direction = BRIDGE_NW;
|
||||
brlimcs.checktype = TT_SPACE;
|
||||
if (DBSrPaintArea((Tile *) NULL, plane, &area,
|
||||
&CIFSolidBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
|
||||
{
|
||||
tpx = brlimcs.violator;
|
||||
area.r_xtop = MAX(RIGHT(tile), LEFT(tpx));
|
||||
area.r_ybot = MIN(BOTTOM(tile), TOP(tpx) - width);
|
||||
area.r_xbot = MIN(LEFT(tpx), RIGHT(tile) - width);
|
||||
area.r_ytop = MAX(TOP(tpx), BOTTOM(tile));
|
||||
if (bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
/* First option of bridge can be implemented (there are not limiting tiles in the area)*/
|
||||
area.r_xtop = RIGHT(tile);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
area.r_xtop = MAX(RIGHT(tile), LEFT(tpx));
|
||||
area.r_ytop = TOP(tpx);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
area.r_xtop = MAX(RIGHT(tile), LEFT(tpx) + width);
|
||||
area.r_ybot = MIN(BOTTOM(tile), TOP(tpx));
|
||||
area.r_xbot = MIN(LEFT(tpx), RIGHT(tile));
|
||||
area.r_ytop = MAX(TOP(tpx), BOTTOM(tile) + width);
|
||||
if (bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
/* Second option of bridge can be implemented (there are not limiting tiles in the area)*/
|
||||
area.r_xbot = LEFT(tpx);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
area.r_xbot = MIN(LEFT(tpx), RIGHT(tile));
|
||||
area.r_ybot = BOTTOM(tile);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Last option (Limiting tiles are present on both sides, those areas must be excluded from the bridge)*/
|
||||
area.r_xtop = MAX(RIGHT(tile), LEFT(tpx) + width);
|
||||
area.r_ybot = MIN(BOTTOM(tile), TOP(tpx) - width);
|
||||
area.r_xbot = MIN(LEFT(tpx), RIGHT(tile) - width);
|
||||
area.r_ytop = MAX(TOP(tpx), BOTTOM(tile) + width);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
bridgeErase(brlims, &area);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for NW outside corner */
|
||||
for (tp1 = BL(tile); TOP(tp1) < TOP(tile); tp1 = RT(tp1));
|
||||
for (tp2 = RT(tile); LEFT(tp1) > LEFT(tile); tp2 = BL(tp1));
|
||||
if ((TiGetRightType(tp1) == TT_SPACE) &&
|
||||
(TiGetBottomType(tp2) == TT_SPACE))
|
||||
{
|
||||
/* Set search box */
|
||||
area.r_xbot = LEFT(tile) - spacing;
|
||||
area.r_xtop = LEFT(tile);
|
||||
area.r_ybot = TOP(tile);
|
||||
area.r_ytop = TOP(tile) + spacing;
|
||||
|
||||
/* Find violator tiles */
|
||||
brlimcs.tile = tile;
|
||||
brlimcs.direction = BRIDGE_SE;
|
||||
brlimcs.checktype = TT_SPACE;
|
||||
if (DBSrPaintArea((Tile *) NULL, plane, &area,
|
||||
&CIFSolidBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
|
||||
{
|
||||
tpx = brlimcs.violator;
|
||||
area.r_xtop = MAX(RIGHT(tpx), LEFT(tile));
|
||||
area.r_ybot = MIN(BOTTOM(tpx), TOP(tile) - width);
|
||||
area.r_xbot = MIN(LEFT(tile), RIGHT(tpx) - width);
|
||||
area.r_ytop = MAX(TOP(tile), BOTTOM(tpx));
|
||||
if (bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
/* First option of bridge can be implemented (there are not limiting tiles in the area)*/
|
||||
area.r_xtop = RIGHT(tpx);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
area.r_xtop = MAX(RIGHT(tpx), LEFT(tile));
|
||||
area.r_ytop = TOP(tile);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
area.r_xtop = MAX(RIGHT(tpx), LEFT(tile) + width);
|
||||
area.r_ybot = MIN(BOTTOM(tpx), TOP(tile));
|
||||
area.r_xbot = MIN(LEFT(tile), RIGHT(tpx));
|
||||
area.r_ytop = MAX(TOP(tile), BOTTOM(tpx) + width);
|
||||
if (bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
/* Second option of bridge can be implemented (there are not limiting tiles in the area)*/
|
||||
area.r_xbot = LEFT(tile);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
area.r_xbot = MIN(LEFT(tile), RIGHT(tpx));
|
||||
area.r_ybot = BOTTOM(tpx);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Last option (Limiting tiles are present on both sides, those areas must be excluded from the bridge)*/
|
||||
area.r_xtop = MAX(RIGHT(tpx), LEFT(tile) + width);
|
||||
area.r_ybot = MIN(BOTTOM(tpx), TOP(tile) - width);
|
||||
area.r_xbot = MIN(LEFT(tile), RIGHT(tpx) - width);
|
||||
area.r_ytop = MAX(TOP(tile), BOTTOM(tpx) + width);
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
bridgeErase(brlims, &area);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* cifBridgeLimFunc2 --
|
||||
*
|
||||
* Called for each relevant tile during bridge-lim operations. The
|
||||
* bridge-lim operation is similar to the bridge operation with the
|
||||
* difference that the material created to meet the minimum spacing/width
|
||||
* rules do not overlap the limiting layers.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0 to keep the search alive.
|
||||
*
|
||||
* Side effects:
|
||||
* May paint into cifNewPlane
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
int
|
||||
cifBridgeLimFunc2(tile, brlims)
|
||||
Tile *tile;
|
||||
BridgeLimStruct *brlims;
|
||||
{
|
||||
Plane *plane = brlims->plane;
|
||||
Rect area;
|
||||
Tile *tp1, *tp2, *tpx;
|
||||
int width = brlims->bridge->br_width;
|
||||
int thirdOption;
|
||||
int spacing = growDistance;
|
||||
BridgeLimCheckStruct brlimcs;
|
||||
brlimcs.sqdistance = (long) width * width;
|
||||
|
||||
/* If tile is marked, then it has been handled, so ignore it */
|
||||
if (tile->ti_client != (ClientData)CIF_UNPROCESSED) return 0;
|
||||
|
||||
/* Find each tile outside corner (up to four) */
|
||||
|
||||
/* Check for NE outside corner */
|
||||
tp1 = TR(tile); /* Tile on right side at the top of this tile */
|
||||
tp2 = RT(tile); /* Tile on top side at the right of this tile */
|
||||
if ((TiGetLeftType(tp1) == CIF_SOLIDTYPE) &&
|
||||
(TiGetBottomType(tp2) == CIF_SOLIDTYPE))
|
||||
{
|
||||
/* Set search box */
|
||||
area.r_xbot = RIGHT(tile);
|
||||
area.r_xtop = RIGHT(tile) + width;
|
||||
area.r_ybot = TOP(tile);
|
||||
area.r_ytop = TOP(tile) + width;
|
||||
|
||||
/* Find violator tiles */
|
||||
brlimcs.tile = tile;
|
||||
brlimcs.direction = BRIDGE_SW;
|
||||
brlimcs.checktype = CIF_SOLIDTYPE;
|
||||
if (DBSrPaintArea((Tile *) NULL, plane, &area,
|
||||
&DBSpaceBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
|
||||
{
|
||||
tpx = brlimcs.violator;
|
||||
area.r_xtop = RIGHT(tile);
|
||||
area.r_ytop = TOP(tile);
|
||||
area.r_xbot = LEFT(tpx) - width;
|
||||
area.r_ybot = BOTTOM(tpx) - width;
|
||||
|
||||
thirdOption = 0;
|
||||
if (!bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
area.r_xtop = RIGHT(tile) + width;
|
||||
area.r_ytop = TOP(tile) + width;
|
||||
area.r_xbot = LEFT(tpx);
|
||||
area.r_ybot = BOTTOM(tpx);
|
||||
if (!bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
area.r_xbot = LEFT(tpx) - width;
|
||||
area.r_ybot = BOTTOM(tpx) - width;
|
||||
thirdOption = 1;
|
||||
}
|
||||
}
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
if (thirdOption)
|
||||
bridgeErase(brlims, &area);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for SW outside corner */
|
||||
tp1 = BL(tile); /* Tile on left side at the bottom of this tile */
|
||||
tp2 = LB(tile); /* Tile on bottom side at the left of this tile */
|
||||
if ((TiGetRightType(tp1) == CIF_SOLIDTYPE) &&
|
||||
(TiGetTopType(tp2) == CIF_SOLIDTYPE))
|
||||
{
|
||||
/* Set search box */
|
||||
area.r_xbot = LEFT(tile) - width;
|
||||
area.r_xtop = LEFT(tile);
|
||||
area.r_ybot = BOTTOM(tile) - width;
|
||||
area.r_ytop = BOTTOM(tile);
|
||||
|
||||
/* Find violator tiles */
|
||||
brlimcs.tile = tile;
|
||||
brlimcs.direction = BRIDGE_NE;
|
||||
brlimcs.checktype = CIF_SOLIDTYPE;
|
||||
if (DBSrPaintArea((Tile *) NULL, plane, &area,
|
||||
&DBSpaceBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
|
||||
{
|
||||
tpx = brlimcs.violator;
|
||||
area.r_xtop = RIGHT(tpx);
|
||||
area.r_ytop = TOP(tpx);
|
||||
area.r_xbot = LEFT(tile) - width;
|
||||
area.r_ybot = BOTTOM(tile) - width;
|
||||
|
||||
thirdOption = 0;
|
||||
if (!bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
area.r_xtop = RIGHT(tpx) + width;
|
||||
area.r_ytop = TOP(tpx) + width;
|
||||
area.r_xbot = LEFT(tile);
|
||||
area.r_ybot = BOTTOM(tile);
|
||||
if (!bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
area.r_xbot = LEFT(tile) - width;
|
||||
area.r_ybot = BOTTOM(tile) - width;
|
||||
thirdOption = 1;
|
||||
}
|
||||
}
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
if (thirdOption)
|
||||
bridgeErase(brlims, &area);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for SE outside corner */
|
||||
for (tp1 = TR(tile); BOTTOM(tp1) > BOTTOM(tile); tp1 = LB(tp1));
|
||||
for (tp2 = LB(tile); RIGHT(tp2) < RIGHT(tile); tp2 = TR(tp2));
|
||||
if ((TiGetLeftType(tp1) == CIF_SOLIDTYPE) &&
|
||||
(TiGetTopType(tp2) == CIF_SOLIDTYPE))
|
||||
{
|
||||
/* Set search box */
|
||||
area.r_xbot = RIGHT(tile);
|
||||
area.r_xtop = RIGHT(tile) + width;
|
||||
area.r_ybot = BOTTOM(tile) - width;
|
||||
area.r_ytop = BOTTOM(tile);
|
||||
|
||||
/* Find violator tiles */
|
||||
brlimcs.tile = tile;
|
||||
brlimcs.direction = BRIDGE_NW;
|
||||
brlimcs.checktype = CIF_SOLIDTYPE;
|
||||
if (DBSrPaintArea((Tile *) NULL, plane, &area,
|
||||
&DBSpaceBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
|
||||
{
|
||||
tpx = brlimcs.violator;
|
||||
area.r_xtop = RIGHT(tile) + width;
|
||||
area.r_ytop = TOP(tpx);
|
||||
area.r_xbot = LEFT(tpx);
|
||||
area.r_ybot = BOTTOM(tile) - width;
|
||||
|
||||
thirdOption = 0;
|
||||
if (!bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
area.r_xtop = RIGHT(tile);
|
||||
area.r_ytop = TOP(tpx) + width;
|
||||
area.r_xbot = LEFT(tpx) - width;
|
||||
area.r_ybot = BOTTOM(tile);
|
||||
if (!bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
area.r_xtop = RIGHT(tile) + width;
|
||||
area.r_ybot = BOTTOM(tile) - width;
|
||||
thirdOption = 1;
|
||||
}
|
||||
}
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
if (thirdOption)
|
||||
bridgeErase(brlims, &area);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for NW outside corner */
|
||||
for (tp1 = BL(tile); TOP(tp1) < TOP(tile); tp1 = RT(tp1));
|
||||
for (tp2 = RT(tile); LEFT(tp2) > LEFT(tile); tp2 = BL(tp2));
|
||||
if ((TiGetRightType(tp1) == CIF_SOLIDTYPE) &&
|
||||
(TiGetBottomType(tp2) == CIF_SOLIDTYPE))
|
||||
{
|
||||
/* Set search box */
|
||||
area.r_xbot = LEFT(tile) - width;
|
||||
area.r_xtop = LEFT(tile);
|
||||
area.r_ybot = TOP(tile);
|
||||
area.r_ytop = TOP(tile) + width;
|
||||
|
||||
/* Find violator tiles */
|
||||
brlimcs.tile = tile;
|
||||
brlimcs.direction = BRIDGE_SE;
|
||||
brlimcs.checktype = CIF_SOLIDTYPE;
|
||||
if (DBSrPaintArea((Tile *) NULL, plane, &area,
|
||||
&DBSpaceBits, bridgeLimCheckFunc, (ClientData)&brlimcs) == 1)
|
||||
{
|
||||
tpx = brlimcs.violator;
|
||||
area.r_xtop = RIGHT(tpx) + width;
|
||||
area.r_ytop = TOP(tile);
|
||||
area.r_xbot = LEFT(tile);
|
||||
area.r_ybot = BOTTOM(tpx) - width;
|
||||
|
||||
thirdOption = 0;
|
||||
if (!bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
area.r_xtop = RIGHT(tpx);
|
||||
area.r_ytop = TOP(tile) + width;
|
||||
area.r_xbot = LEFT(tile) - width;
|
||||
area.r_ybot = BOTTOM(tpx);
|
||||
if (!bridgeLimSrTiles(brlims, &area, FALSE))
|
||||
{
|
||||
area.r_xtop = RIGHT(tpx) + width;
|
||||
area.r_ybot = BOTTOM(tpx) - width;
|
||||
thirdOption = 1;
|
||||
}
|
||||
}
|
||||
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
|
||||
if (thirdOption)
|
||||
bridgeErase(brlims, &area);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -3828,6 +4663,7 @@ CIFGenLayer(op, area, cellDef, origDef, temps, clientdata)
|
|||
char *netname;
|
||||
BloatStruct bls;
|
||||
BridgeStruct brs;
|
||||
BridgeLimStruct brlims;
|
||||
BridgeData *bridge;
|
||||
int (*cifGrowFuncPtr)() = (CIFCurStyle->cs_flags & CWF_GROW_EUCLIDEAN) ?
|
||||
cifGrowEuclideanFunc : cifGrowFunc;
|
||||
|
|
@ -4022,11 +4858,11 @@ CIFGenLayer(op, area, cellDef, origDef, temps, clientdata)
|
|||
cifPlane = nextPlane;
|
||||
cifScale = 1;
|
||||
/* First copy the existing paint into the target plane */
|
||||
(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
|
||||
&CIFSolidBits, cifPaintFunc, (ClientData)CIFPaintTable);
|
||||
DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
|
||||
&CIFSolidBits, cifPaintFunc, (ClientData)CIFPaintTable);
|
||||
DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
|
||||
&DBSpaceBits, cifCloseFunc, (ClientData)&curPlane);
|
||||
|
||||
(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
|
||||
&DBSpaceBits, cifCloseFunc, (ClientData)&curPlane);
|
||||
temp = curPlane;
|
||||
curPlane = nextPlane;
|
||||
nextPlane = temp;
|
||||
|
|
@ -4052,6 +4888,32 @@ CIFGenLayer(op, area, cellDef, origDef, temps, clientdata)
|
|||
nextPlane = temp;
|
||||
break;
|
||||
|
||||
case CIFOP_BRIDGELIM:
|
||||
growDistance = op->co_distance;
|
||||
DBClearPaintPlane(nextPlane);
|
||||
cifPlane = nextPlane;
|
||||
cifScale = 1;
|
||||
|
||||
brlims.bridge = (BridgeData *)op->co_client;
|
||||
brlims.def = cellDef;
|
||||
brlims.temps = temps;
|
||||
brlims.co_paintMask = op->co_paintMask;
|
||||
brlims.co_cifMask = op->co_cifMask;
|
||||
|
||||
(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
|
||||
&CIFSolidBits, cifBridgeLimFunc0, (ClientData)&brlims);
|
||||
temp = curPlane;
|
||||
curPlane = nextPlane;
|
||||
brlims.plane = curPlane;
|
||||
|
||||
(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
|
||||
&CIFSolidBits, cifBridgeLimFunc1, (ClientData)&brlims);
|
||||
(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
|
||||
&DBSpaceBits, cifBridgeLimFunc2, (ClientData)&brlims);
|
||||
curPlane = nextPlane;
|
||||
nextPlane = temp;
|
||||
break;
|
||||
|
||||
case CIFOP_BLOAT:
|
||||
cifPlane = curPlane;
|
||||
cifSrTiles(op, area, cellDef, temps,
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ typedef struct cifop
|
|||
* current cell. This replaces the "fault" method.
|
||||
* CIFOP_CLOSE - Added 11/25/19---close up areas smaller than indicated
|
||||
* CIFOP_BRIDGE - Added 6/11/20---Bridge across catecorner gaps
|
||||
* CIFOP_BRIDGELIM - Added 27/07/20---Bridge across catecorner gaps, but with limiting layers
|
||||
*/
|
||||
|
||||
#define CIFOP_AND 1
|
||||
|
|
@ -164,6 +165,8 @@ typedef struct cifop
|
|||
#define CIFOP_COPYUP 19
|
||||
#define CIFOP_CLOSE 20
|
||||
#define CIFOP_BRIDGE 21
|
||||
#define CIFOP_BRIDGELIM 22
|
||||
|
||||
|
||||
/* Added by Tim 10/21/2004 */
|
||||
/* The following structure is used to pass information on how to draw
|
||||
|
|
|
|||
|
|
@ -1058,6 +1058,8 @@ CIFTechLine(sectionName, argc, argv)
|
|||
newOp->co_opcode = CIFOP_CLOSE;
|
||||
else if (strcmp(argv[0], "bridge") == 0)
|
||||
newOp->co_opcode = CIFOP_BRIDGE;
|
||||
else if (strcmp(argv[0], "bridge-lim") == 0)
|
||||
newOp->co_opcode = CIFOP_BRIDGELIM;
|
||||
else
|
||||
{
|
||||
TechError("Unknown statement \"%s\".\n", argv[0]);
|
||||
|
|
@ -1107,6 +1109,26 @@ CIFTechLine(sectionName, argc, argv)
|
|||
newOp->co_client = (ClientData)bridge;
|
||||
break;
|
||||
|
||||
case CIFOP_BRIDGELIM:
|
||||
if (argc != 4) goto wrongNumArgs;
|
||||
newOp->co_distance = atoi(argv[1]);
|
||||
if (newOp->co_distance <= 0)
|
||||
{
|
||||
TechError("Bridge distance must be greater than zero.\n");
|
||||
goto errorReturn;
|
||||
}
|
||||
bridge = (BridgeData *)mallocMagic(sizeof(BridgeData));
|
||||
bridge->br_width = atoi(argv[2]);
|
||||
if (bridge->br_width <= 0)
|
||||
{
|
||||
TechError("Bridge width must be greater than zero.\n");
|
||||
freeMagic(bridge);
|
||||
goto errorReturn;
|
||||
}
|
||||
cifParseLayers(argv[3], CIFCurStyle, &newOp->co_paintMask, &newOp->co_cifMask,FALSE);
|
||||
newOp->co_client = (ClientData)bridge;
|
||||
break;
|
||||
|
||||
case CIFOP_BLOATALL:
|
||||
if (argc != 3) goto wrongNumArgs;
|
||||
cifParseLayers(argv[1], CIFCurStyle, &newOp->co_paintMask,
|
||||
|
|
@ -1572,6 +1594,7 @@ cifComputeRadii(layer, des)
|
|||
break;
|
||||
|
||||
case CIFOP_BRIDGE: break;
|
||||
case CIFOP_BRIDGELIM: break;
|
||||
case CIFOP_SQUARES: break;
|
||||
case CIFOP_SQUARES_G: break;
|
||||
}
|
||||
|
|
@ -1831,6 +1854,7 @@ CIFTechFinal()
|
|||
case CIFOP_MAXRECT:
|
||||
case CIFOP_NET:
|
||||
break;
|
||||
case CIFOP_BRIDGELIM:
|
||||
case CIFOP_BRIDGE:
|
||||
bridge = (BridgeData *)op->co_client;
|
||||
c = FindGCF(style->cs_scaleFactor,
|
||||
|
|
@ -1928,6 +1952,7 @@ CIFTechFinal()
|
|||
case CIFOP_ANDNOT:
|
||||
case CIFOP_SHRINK:
|
||||
case CIFOP_CLOSE:
|
||||
case CIFOP_BRIDGELIM:
|
||||
case CIFOP_BRIDGE:
|
||||
needThisLayer = TRUE;
|
||||
break;
|
||||
|
|
@ -2359,6 +2384,7 @@ CIFTechOutputScale(n, d)
|
|||
case CIFOP_MAXRECT:
|
||||
case CIFOP_NET:
|
||||
break;
|
||||
case CIFOP_BRIDGELIM:
|
||||
case CIFOP_BRIDGE:
|
||||
bridge = (BridgeData *)op->co_client;
|
||||
bridge->br_width *= d;
|
||||
|
|
@ -2463,6 +2489,7 @@ CIFTechOutputScale(n, d)
|
|||
if (bloats->bl_distance[j] != 0)
|
||||
bloats->bl_distance[j] /= lexpand;
|
||||
break;
|
||||
case CIFOP_BRIDGELIM:
|
||||
case CIFOP_BRIDGE:
|
||||
bridge = (BridgeData *)op->co_client;
|
||||
bridge->br_width /= lexpand;
|
||||
|
|
|
|||
|
|
@ -624,7 +624,8 @@ outputCalma:
|
|||
* or
|
||||
* cellname property [name] [property_key [property_value]]
|
||||
* or
|
||||
* instance orientation [name] [-def]
|
||||
* instance orientation [name] [-def] [orient]
|
||||
* instance abutment [name]
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
|
|
@ -648,7 +649,7 @@ CmdCellname(w, cmd)
|
|||
bool dodef = FALSE;
|
||||
int option;
|
||||
int locargc = cmd->tx_argc;
|
||||
char *cellname = NULL;
|
||||
char *cellname = NULL, *orient = NULL;
|
||||
void (*func)();
|
||||
CellDef *newDef, *cellDef;
|
||||
|
||||
|
|
@ -671,6 +672,7 @@ CmdCellname(w, cmd)
|
|||
"lock lock the named cell (prevent changes to cell use)",
|
||||
"unlock unlock the named cell (allow changes to cell use)",
|
||||
"property list or set cell definition properties",
|
||||
"abutment list instance abutment coordinates",
|
||||
"orientation list or set instance orientation",
|
||||
"rename rename the indicated cell",
|
||||
"writeable make the cell definition read-only or read-write",
|
||||
|
|
@ -681,7 +683,7 @@ CmdCellname(w, cmd)
|
|||
IDX_INSTANCE, IDX_CHILDINST, IDX_CELLDEF, IDX_ALLCELLS,
|
||||
IDX_TOPCELLS, IDX_IN_WINDOW, IDX_CREATE,
|
||||
IDX_DELETE, IDX_FILEPATH, IDX_FLAGS, IDX_LOCK, IDX_UNLOCK,
|
||||
IDX_PROPERTY, IDX_ORIENTATION, IDX_RENAME,
|
||||
IDX_PROPERTY, IDX_ABUTMENT, IDX_ORIENTATION, IDX_RENAME,
|
||||
IDX_READWRITE, IDX_MODIFIED } optionType;
|
||||
|
||||
if (strstr(cmd->tx_argv[0], "in"))
|
||||
|
|
@ -720,7 +722,7 @@ CmdCellname(w, cmd)
|
|||
|
||||
if ((locargc > 3) && (option != IDX_RENAME) && (option != IDX_DELETE) &&
|
||||
(option != IDX_READWRITE) && (option != IDX_PROPERTY) &&
|
||||
(option != IDX_FILEPATH))
|
||||
(option != IDX_FILEPATH) && (option != IDX_ORIENTATION))
|
||||
goto badusage;
|
||||
|
||||
if ((locargc > 4) && (option != IDX_PROPERTY))
|
||||
|
|
@ -751,6 +753,10 @@ CmdCellname(w, cmd)
|
|||
TxError("Cell definitions do not have orientations."
|
||||
" Use \"instance\"?\n");
|
||||
return;
|
||||
case IDX_ABUTMENT:
|
||||
TxError("Use \"property get FIXED_BBOX\" to get the cell "
|
||||
"abutment box.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1029,7 +1035,16 @@ CmdCellname(w, cmd)
|
|||
}
|
||||
break;
|
||||
case IDX_ORIENTATION:
|
||||
DBOrientUse(cellname, dodef);
|
||||
orient = (locargc == 4) ? cmd->tx_argv[3 + ((dolist) ? 1 : 0)] : NULL;
|
||||
if ((cellname != NULL) && (orient != NULL))
|
||||
{
|
||||
TxError("Cannot set orientation by name. Use selection.\n");
|
||||
break;
|
||||
}
|
||||
DBOrientUse(cellname, dodef, orient);
|
||||
break;
|
||||
case IDX_ABUTMENT:
|
||||
DBAbutmentUse(cellname, dolist);
|
||||
break;
|
||||
case IDX_LOCK:
|
||||
DBLockUse(cellname, TRUE);
|
||||
|
|
@ -1647,7 +1662,7 @@ CmdCif(w, cmd)
|
|||
* the interpreter to uniquely identify it.
|
||||
*
|
||||
* The "-origin" option has been added to allow rotating stuff
|
||||
* relative to the origin, insteadd of the lower-left corner.
|
||||
* relative to the origin, instead of the lower-left corner.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -3897,9 +3912,9 @@ cmdDumpParseArgs(cmdName, w, cmd, dummy, scx)
|
|||
hasChild = hasRoot = hasTrans = FALSE;
|
||||
while (ac > 0)
|
||||
{
|
||||
static char *kwdNames[] = { "child", "parent", "90", "180", "270",
|
||||
"v", "90v", "180v", "270v",
|
||||
"h", "90h", "180h", "270h", 0 };
|
||||
static char *kwdNames[] = { "child", "parent", "0", "90", "180", "270",
|
||||
"v", "0v", "90v", "180v", "270v",
|
||||
"h", "0h", "90h", "180h", "270h", 0 };
|
||||
static char *refPointNames[] = { "ll", "lr", "ul", "ur", 0 };
|
||||
Label *lab;
|
||||
int n,p;
|
||||
|
|
@ -4043,8 +4058,8 @@ cmdDumpParseArgs(cmdName, w, cmd, dummy, scx)
|
|||
}
|
||||
hasRoot = TRUE;
|
||||
break;
|
||||
case 2: /* 90 */
|
||||
tx_cell = &Geo90Transform;
|
||||
case 2: /* 0 */
|
||||
tx_cell = &GeoIdentityTransform;
|
||||
transform_cell:
|
||||
if (ac < 2 )
|
||||
{
|
||||
|
|
@ -4127,34 +4142,39 @@ default_action:
|
|||
}
|
||||
hasTrans = TRUE;
|
||||
break;
|
||||
case 3: /* 180 */
|
||||
case 3: /* 90 */
|
||||
tx_cell = &Geo90Transform;
|
||||
goto transform_cell;
|
||||
case 4: /* 180 */
|
||||
tx_cell = &Geo180Transform;
|
||||
goto transform_cell;
|
||||
case 4: /* 270 */
|
||||
case 5: /* 270 */
|
||||
tx_cell = &Geo270Transform;
|
||||
goto transform_cell;
|
||||
case 5: /* v */
|
||||
case 6: /* v */
|
||||
case 7: /* 0v */
|
||||
tx_cell = &GeoUpsideDownTransform;
|
||||
goto transform_cell;
|
||||
case 6: /* 90v */
|
||||
case 8: /* 90v */
|
||||
tx_cell = &GeoRef45Transform;
|
||||
goto transform_cell;
|
||||
case 7: /* 180v */
|
||||
case 9: /* 180v */
|
||||
tx_cell = &GeoSidewaysTransform;
|
||||
goto transform_cell;
|
||||
case 8: /* 270v */
|
||||
case 10: /* 270v */
|
||||
tx_cell = &GeoRef135Transform;
|
||||
goto transform_cell;
|
||||
case 9: /* h */
|
||||
case 11: /* h */
|
||||
case 12: /* 0h */
|
||||
tx_cell = &GeoSidewaysTransform;
|
||||
goto transform_cell;
|
||||
case 10: /* 90h */
|
||||
case 13: /* 90h */
|
||||
tx_cell = &GeoRef135Transform;
|
||||
goto transform_cell;
|
||||
case 11: /* 180h */
|
||||
case 14: /* 180h */
|
||||
tx_cell = &GeoUpsideDownTransform;
|
||||
goto transform_cell;
|
||||
case 12: /* 270h */
|
||||
case 15: /* 270h */
|
||||
tx_cell = &GeoRef45Transform;
|
||||
goto transform_cell;
|
||||
}
|
||||
|
|
|
|||
155
commands/CmdLQ.c
155
commands/CmdLQ.c
|
|
@ -2276,3 +2276,158 @@ CmdNetlist(w, cmd)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CmdOrient --
|
||||
*
|
||||
* Implement the "orient" command. Set the orientation of the selection and
|
||||
* according to the orientation string, which can be in Magic's format
|
||||
* (using number of degrees, and "h" for horizontal flip or "v" for vertical
|
||||
* flip) or DEF format ("N", "S", "FN", etc.). The cursor box is rotated to
|
||||
* match.
|
||||
*
|
||||
* Usage:
|
||||
* orient [orientation] [-origin]
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Modifies the edit cell.
|
||||
*
|
||||
* Notes:
|
||||
* The "-origin" option sets the orientation relative to the origin,
|
||||
* instead of the lower-left corner.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
CmdOrient(w, cmd)
|
||||
MagWindow *w;
|
||||
TxCommand *cmd;
|
||||
{
|
||||
Transform trans, t2;
|
||||
int orientidx, locargc;
|
||||
char *orientstr;
|
||||
Rect rootBox, bbox;
|
||||
CellDef *rootDef;
|
||||
bool noAdjust = FALSE;
|
||||
|
||||
static char *orientNames[] = { "0", "90", "180", "270",
|
||||
"v", "0v", "90v", "180v", "270v",
|
||||
"h", "0h", "90h", "180h", "270h",
|
||||
"N", "E", "S", "W",
|
||||
"FN", "FE", "FS", "FW",
|
||||
0 };
|
||||
|
||||
typedef enum { IDX_ORIENT_0, IDX_ORIENT_90, IDX_ORIENT_180, IDX_ORIENT_270,
|
||||
IDX_ORIENT_V, IDX_ORIENT_0V, IDX_ORIENT_90V, IDX_ORIENT_180V,
|
||||
IDX_ORIENT_270V, IDX_ORIENT_H, IDX_ORIENT_0H, IDX_ORIENT_90H,
|
||||
IDX_ORIENT_180H, IDX_ORIENT_270H, IDX_ORIENT_N, IDX_ORIENT_E,
|
||||
IDX_ORIENT_S, IDX_ORIENT_W, IDX_ORIENT_FN, IDX_ORIENT_FE,
|
||||
IDX_ORIENT_FS, IDX_ORIENT_FW } orientType;
|
||||
|
||||
locargc = cmd->tx_argc;
|
||||
if (!strncmp(cmd->tx_argv[locargc - 1], "-orig", 5))
|
||||
{
|
||||
noAdjust = TRUE;
|
||||
locargc--;
|
||||
}
|
||||
|
||||
if (!ToolGetEditBox((Rect *)NULL)) return;
|
||||
|
||||
if (locargc == 2)
|
||||
orientstr = cmd->tx_argv[1];
|
||||
else
|
||||
goto badusage;
|
||||
|
||||
orientidx = Lookup(orientstr, orientNames);
|
||||
|
||||
switch (orientidx)
|
||||
{
|
||||
case IDX_ORIENT_0:
|
||||
case IDX_ORIENT_N:
|
||||
/* ORIENT_NORTH */
|
||||
t2 = GeoIdentityTransform;
|
||||
break;
|
||||
case IDX_ORIENT_S:
|
||||
case IDX_ORIENT_180:
|
||||
/* ORIENT_SOUTH */
|
||||
t2 = Geo180Transform;
|
||||
break;
|
||||
case IDX_ORIENT_E:
|
||||
case IDX_ORIENT_90:
|
||||
/* ORIENT_EAST */
|
||||
t2 = Geo90Transform;
|
||||
break;
|
||||
case IDX_ORIENT_W:
|
||||
case IDX_ORIENT_270:
|
||||
/* ORIENT_WEST */
|
||||
t2 = Geo270Transform;
|
||||
break;
|
||||
case IDX_ORIENT_FN:
|
||||
case IDX_ORIENT_H:
|
||||
case IDX_ORIENT_0H:
|
||||
/* ORIENT_FLIPPED_NORTH */
|
||||
t2 = GeoSidewaysTransform;
|
||||
break;
|
||||
case IDX_ORIENT_FS:
|
||||
case IDX_ORIENT_180H:
|
||||
case IDX_ORIENT_V:
|
||||
case IDX_ORIENT_0V:
|
||||
/* ORIENT_FLIPPED_SOUTH */
|
||||
t2 = GeoUpsideDownTransform;
|
||||
break;
|
||||
case IDX_ORIENT_FE:
|
||||
case IDX_ORIENT_90H:
|
||||
case IDX_ORIENT_270V:
|
||||
/* ORIENT_FLIPPED_EAST */
|
||||
t2 = GeoRef135Transform;
|
||||
break;
|
||||
case IDX_ORIENT_FW:
|
||||
case IDX_ORIENT_270H:
|
||||
case IDX_ORIENT_90V:
|
||||
/* ORIENT_FLIPPED_WEST */
|
||||
t2 = GeoRef45Transform;
|
||||
break;
|
||||
default:
|
||||
goto badusage;
|
||||
}
|
||||
|
||||
/* To orient the selection, first orient it relative to the origin
|
||||
* then move it so its lower-left corner is at the same place
|
||||
* that it used to be. If the "-origin" option was selected, then
|
||||
* only orient relative to the origin.
|
||||
*/
|
||||
|
||||
GeoTransRect(&t2, &SelectDef->cd_bbox, &bbox);
|
||||
if (noAdjust)
|
||||
trans = t2;
|
||||
else
|
||||
{
|
||||
GeoTranslateTrans(&t2, SelectDef->cd_bbox.r_xbot - bbox.r_xbot,
|
||||
SelectDef->cd_bbox.r_ybot - bbox.r_ybot, &trans);
|
||||
}
|
||||
|
||||
SelectTransform(&trans);
|
||||
|
||||
/* Rotate the box, if it exists and is in the same window as the
|
||||
* selection.
|
||||
*/
|
||||
|
||||
if (ToolGetBox(&rootDef, &rootBox) && (rootDef == SelectRootDef))
|
||||
{
|
||||
Rect newBox;
|
||||
|
||||
GeoTransRect(&trans, &rootBox, &newBox);
|
||||
DBWSetBox(rootDef, &newBox);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
badusage:
|
||||
TxError("Usage: %s [orientation]\n", cmd->tx_argv[0]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -734,8 +734,9 @@ again:
|
|||
}
|
||||
|
||||
/* Remove any ".mag" file extension from the name */
|
||||
if (!strcmp(returnname + strlen(returnname) - 4, ".mag"))
|
||||
*(returnname + strlen(returnname) - 4) = '\0';
|
||||
if (strlen(returnname) > 4)
|
||||
if (!strcmp(returnname + strlen(returnname) - 4, ".mag"))
|
||||
*(returnname + strlen(returnname) - 4) = '\0';
|
||||
|
||||
if (strcmp(returnname, def->cd_name) != 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1204,19 +1204,20 @@ DBLockUse(UseName, bval)
|
|||
*
|
||||
* DBOrientUse --
|
||||
*
|
||||
* This routine sets or reports a cell instance's orientation
|
||||
* This routine reports a cell instance's orientation.
|
||||
* UseName is the name of a specific CellUse. If NULL, then the
|
||||
* operation applies to all selected cell uses. "orient" is a
|
||||
* string in the form used by "getcell" (e.g., "180", "270v",
|
||||
* etc.), unless "dodef" is true, in which case the output is
|
||||
* given in the form used by DEF ("N", "FN", etc.).
|
||||
* reported.
|
||||
* operation applies to all selected cell uses.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* cu_transform changed for indicated cell use.
|
||||
* In the Tcl/Tk implementation, the result is set in the interpreter.
|
||||
*
|
||||
* Notes:
|
||||
* This routine only reports orientation. Setting orientation must
|
||||
* be done through the selection interface (i.e., commands "sideways",
|
||||
* "upsidedown", "clockwise" ("rotate"), or "orient" (added 10/30/2020)).
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -1294,6 +1295,7 @@ dbOrientUseFunc(selUse, use, transform, data)
|
|||
ClientData data;
|
||||
{
|
||||
bool *dodef = (bool *)data;
|
||||
int orient;
|
||||
|
||||
if (EditCellUse && !DBIsChild(use, EditCellUse))
|
||||
{
|
||||
|
|
@ -1302,9 +1304,16 @@ dbOrientUseFunc(selUse, use, transform, data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
orient = -1;
|
||||
|
||||
if (selUse != NULL)
|
||||
orient = GeoTransOrient(&selUse->cu_transform);
|
||||
else if (use != NULL)
|
||||
orient = GeoTransOrient(&use->cu_transform);
|
||||
|
||||
if (orient != -1)
|
||||
{
|
||||
switch (GeoTransOrient(&selUse->cu_transform)) {
|
||||
switch (orient) {
|
||||
#ifdef MAGIC_WRAPPER
|
||||
case ORIENT_NORTH:
|
||||
Tcl_AppendElement(magicinterp, (*dodef) ? "N" : "0");
|
||||
|
|
@ -1362,6 +1371,140 @@ dbOrientUseFunc(selUse, use, transform, data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* DBAbutmentUse --
|
||||
*
|
||||
* This routine reports the cell instance's abutment box in the
|
||||
* coordinate system of the parent (edit) cell.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
DBAbutmentUse(UseName, dolist)
|
||||
char *UseName;
|
||||
bool dolist;
|
||||
{
|
||||
int found;
|
||||
HashSearch hs;
|
||||
HashEntry *entry;
|
||||
CellDef *celldef;
|
||||
CellUse *celluse;
|
||||
|
||||
int dbAbutmentUseFunc();
|
||||
|
||||
/*
|
||||
*
|
||||
* Check to see if a cell name was specified. If not, then search
|
||||
* for selected cells.
|
||||
*
|
||||
*/
|
||||
|
||||
if (UseName == NULL)
|
||||
{
|
||||
SelEnumCells(TRUE, (int *)NULL, (SearchContext *)NULL,
|
||||
dbAbutmentUseFunc, (ClientData)&dolist);
|
||||
}
|
||||
else
|
||||
{
|
||||
SearchContext scx;
|
||||
|
||||
bzero(&scx, sizeof(SearchContext));
|
||||
found = 0;
|
||||
|
||||
HashStartSearch(&hs);
|
||||
while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
|
||||
{
|
||||
celldef = (CellDef *) HashGetValue(entry);
|
||||
if (celldef != (CellDef *) NULL)
|
||||
{
|
||||
celluse = celldef->cd_parents; /* only need one */
|
||||
if (celluse != (CellUse *)NULL) {
|
||||
DBTreeFindUse(UseName, celluse, &scx);
|
||||
if (scx.scx_use != NULL) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (scx.scx_use == NULL)
|
||||
TxError("Cell %s is not currently loaded.\n", UseName);
|
||||
else
|
||||
dbAbutmentUseFunc(NULL, scx.scx_use, NULL, (ClientData)&dolist);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dbAbutmentUseFunc()
|
||||
*/
|
||||
|
||||
int
|
||||
dbAbutmentUseFunc(selUse, use, transform, data)
|
||||
CellUse *selUse; /* Use from selection cell */
|
||||
CellUse *use; /* Use from layout corresponding to selection */
|
||||
Transform *transform;
|
||||
ClientData data;
|
||||
{
|
||||
Rect bbox, refbox;
|
||||
Transform *trans;
|
||||
char *propvalue;
|
||||
bool found;
|
||||
bool *dolist = (bool *)data;
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_Obj *pobj;
|
||||
#endif
|
||||
|
||||
if (EditCellUse && !DBIsChild(use, EditCellUse))
|
||||
{
|
||||
TxError("Cell %s (%s) isn't a child of the edit cell.\n",
|
||||
use->cu_id, use->cu_def->cd_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (use == NULL)
|
||||
{
|
||||
TxError("No instance in selection!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
trans = &use->cu_transform;
|
||||
propvalue = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
|
||||
if (!found)
|
||||
bbox = use->cu_def->cd_bbox;
|
||||
else
|
||||
{
|
||||
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
||||
&bbox.r_xtop, &bbox.r_ytop) != 4)
|
||||
bbox = use->cu_def->cd_bbox;
|
||||
}
|
||||
GeoTransRect(trans, &bbox, &refbox);
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
if (*dolist)
|
||||
{
|
||||
pobj = Tcl_NewListObj(0, NULL);
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_xbot));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_ybot));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_xtop));
|
||||
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_ytop));
|
||||
Tcl_SetObjResult(magicinterp, pobj);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
TxPrintf("Abutment box: %d %d %d %d\n", refbox.r_xbot, refbox.r_ybot,
|
||||
refbox.r_xtop, refbox.r_ytop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
|
|||
|
|
@ -2774,7 +2774,7 @@ DBCellWrite(cellDef, fileName)
|
|||
/* The cd_file should not have the .mag suffix, but make sure */
|
||||
/* it doesn't before adding one. */
|
||||
|
||||
if (strcmp(fileName + strlen(fileName) - 4, DBSuffix))
|
||||
if ((strlen(fileName) < 4) || (strcmp(fileName + strlen(fileName) - 4, DBSuffix)))
|
||||
{
|
||||
realname = (char *) mallocMagic(strlen(fileName) + strlen(DBSuffix) + 1);
|
||||
(void) sprintf(realname, "%s%s", fileName, DBSuffix);
|
||||
|
|
|
|||
|
|
@ -426,9 +426,9 @@ DBEraseLabelsByContent(def, rect, type, text)
|
|||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* DBEraseLabelsByFunction --
|
||||
* DBRemoveLabel --
|
||||
*
|
||||
* Erase any labels found on the label list for which the function returns
|
||||
* Erase a labels by reference.
|
||||
* TRUE.
|
||||
*
|
||||
* Results:
|
||||
|
|
@ -443,19 +443,9 @@ DBEraseLabelsByContent(def, rect, type, text)
|
|||
*/
|
||||
|
||||
void
|
||||
DBEraseLabelsByFunction(def, func)
|
||||
DBRemoveLabel(def, refLab)
|
||||
CellDef *def; /* Where to look for label to delete. */
|
||||
bool (*func)(); /* Function to call for each label. If it
|
||||
* returns TRUE, we delete the label.
|
||||
*
|
||||
* Function should be of the form:
|
||||
*
|
||||
* bool func(lab)
|
||||
* Label *lab;
|
||||
* {
|
||||
* return XXX;
|
||||
* }
|
||||
*/
|
||||
Label *refLab;
|
||||
{
|
||||
Label *lab, *labPrev;
|
||||
|
||||
|
|
@ -464,7 +454,7 @@ DBEraseLabelsByFunction(def, func)
|
|||
labPrev = lab, lab = lab->lab_next)
|
||||
{
|
||||
nextCheck:
|
||||
if (!(*func)(lab)) continue;
|
||||
if (lab != refLab) continue;
|
||||
DBUndoEraseLabel(def, lab);
|
||||
DBWLabelChanged(def, lab, DBW_ALLWINDOWS);
|
||||
if (labPrev == NULL)
|
||||
|
|
|
|||
|
|
@ -451,6 +451,9 @@ DBTechPrintTypes(mask, dolist)
|
|||
for (p = dbTypeNameLists.sn_next; p != &dbTypeNameLists;
|
||||
p = p->sn_next)
|
||||
{
|
||||
/* Ignore aliases */
|
||||
if (p->sn_alias) continue;
|
||||
|
||||
if (((TileType)(spointertype) p->sn_value) == i)
|
||||
{
|
||||
if (dolist)
|
||||
|
|
|
|||
|
|
@ -760,7 +760,7 @@ dbTechNameAdd(name, cdata, ptable, alias)
|
|||
*cp = '\0';
|
||||
if (*(cp = onename))
|
||||
{
|
||||
if ((current = dbTechNameAddOne(cp, cdata, FALSE, ptable)) == NULL)
|
||||
if ((current = dbTechNameAddOne(cp, cdata, FALSE, alias, ptable)) == NULL)
|
||||
return (NULL);
|
||||
if (first == NULL)
|
||||
first = current->sn_name;
|
||||
|
|
@ -793,10 +793,11 @@ dbTechNameAdd(name, cdata, ptable, alias)
|
|||
*/
|
||||
|
||||
NameList *
|
||||
dbTechNameAddOne(name, cdata, isPrimary, ptable)
|
||||
dbTechNameAddOne(name, cdata, isPrimary, isAlias, ptable)
|
||||
char *name; /* Name to be added */
|
||||
ClientData cdata; /* Client value associated with this name */
|
||||
bool isPrimary; /* TRUE if this is the primary abbreviation */
|
||||
bool isAlias; /* TRUE if this name is an alias */
|
||||
NameList *ptable; /* Table of names to which we're adding this */
|
||||
{
|
||||
int cmp;
|
||||
|
|
@ -817,6 +818,7 @@ dbTechNameAddOne(name, cdata, isPrimary, ptable)
|
|||
new->sn_name = StrDup((char **) NULL, name);
|
||||
new->sn_value = cdata;
|
||||
new->sn_primary = isPrimary;
|
||||
new->sn_alias = isAlias;
|
||||
|
||||
/* Link this entry in to the list before 'tbl' */
|
||||
new->sn_next = tbl;
|
||||
|
|
|
|||
|
|
@ -639,7 +639,14 @@ dbTechAddPaintErase(type, sectionName, argc, argv)
|
|||
|
||||
pMask &= ~rMask;
|
||||
|
||||
for (tres = 0; tres < DBNumTypes; tres++)
|
||||
/* 10/30/2020: Changed from DBNumTypes to DBNumUserLayers, */
|
||||
/* because DBTechNoisyNameMask() was modified to add stacking */
|
||||
/* contact types, and it is not correct for tMask to have more */
|
||||
/* than one type in the mask that share the same plane. */
|
||||
/* NOTE: Paint rules for stacked contacts probably have to be */
|
||||
/* handled too, but in a separate way. */
|
||||
|
||||
for (tres = 0; tres < DBNumUserLayers; tres++)
|
||||
{
|
||||
if (TTMaskHasType(&tMask, tres))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -729,7 +729,7 @@ extern void DBFontLabelSetBBox();
|
|||
extern bool DBEraseLabel();
|
||||
extern void DBEraseLabelAll();
|
||||
extern void DBEraseLabelsByContent();
|
||||
extern void DBEraseLabelsByFunction();
|
||||
extern void DBRemoveLabel();
|
||||
extern void DBReOrientLabel();
|
||||
extern void DBAdjustLabels();
|
||||
|
||||
|
|
@ -778,6 +778,7 @@ extern CellUse *DBCellFindDup();
|
|||
extern void DBLockUse();
|
||||
extern void DBUnlockUse();
|
||||
extern void DBOrientUse();
|
||||
extern void DBAbutmentUse();
|
||||
|
||||
/* Cell selection */
|
||||
extern CellUse *DBSelectCell();
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ typedef struct namelist
|
|||
char *sn_name; /* Text of name */
|
||||
ClientData sn_value; /* Value (TileType or plane number) */
|
||||
bool sn_primary; /* If TRUE, this is the primary name */
|
||||
bool sn_alias; /* If TRUE, this is an alias name */
|
||||
} NameList;
|
||||
|
||||
typedef struct
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ extern void CmdEdit(), CmdElement(), CmdErase(), CmdExpand(), CmdExtract();
|
|||
extern void CmdFeedback(), CmdFill(), CmdFindBox(), CmdFindLabel(), CmdFlush();
|
||||
extern void CmdGetcell(), CmdGrid(), CmdIdentify();
|
||||
extern void CmdLabel(), CmdLoad();
|
||||
extern void CmdMove(), CmdNetlist(), CmdPaint(), CmdPath(), CmdPlow();
|
||||
extern void CmdPolygon(), CmdPort(), CmdProperty();
|
||||
extern void CmdMove(), CmdNetlist(), CmdOrient(), CmdPaint(), CmdPath();
|
||||
extern void CmdPlow(), CmdPolygon(), CmdPort(), CmdProperty();
|
||||
extern void CmdSave(), CmdScaleGrid(), CmdSee();
|
||||
extern void CmdSelect(), CmdSetLabel(), CmdSideways();
|
||||
extern void CmdShell(), CmdSnap();
|
||||
|
|
@ -378,6 +378,9 @@ DBWInitCommands()
|
|||
for information on options",
|
||||
CmdNetlist, FALSE);
|
||||
|
||||
WindAddCommand(DBWclientID,
|
||||
"orient [orientation] orient selection and box",
|
||||
CmdOrient, FALSE);
|
||||
WindAddCommand(DBWclientID,
|
||||
"paint layers|cursor paint mask information",
|
||||
CmdPaint, FALSE);
|
||||
|
|
|
|||
13
drc/DRCcif.c
13
drc/DRCcif.c
|
|
@ -157,6 +157,13 @@ drcCifWarning()
|
|||
* Side effects:
|
||||
* Updates the DRC technology variables.
|
||||
*
|
||||
* Notes: "centidistance" is by default in centimicrons, but it is really in
|
||||
* whatever units are declared in the cifoutput section; so if cifoutput
|
||||
* declares nanometers, then units are in nanometers. This may be in
|
||||
* different units from the non-CIF part of the DRC section. The escape
|
||||
* sequence substitution in the "Why" text will make sure that the correct
|
||||
* physical dimensions are presented to the end user.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -194,7 +201,7 @@ drcCifWidth(argc, argv)
|
|||
}
|
||||
|
||||
scalefactor = drcCifStyle->cs_scaleFactor;
|
||||
centidistance *= drcCifStyle->cs_expander; // BSI
|
||||
// centidistance *= drcCifStyle->cs_expander; // BSI
|
||||
|
||||
dpnext = drcCifRules[thislayer][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
|
|
@ -287,7 +294,7 @@ drcCifSpacing(argc, argv)
|
|||
}
|
||||
|
||||
scalefactor = drcCifStyle->cs_scaleFactor;
|
||||
centidistance *= drcCifStyle->cs_expander; // BSI
|
||||
// centidistance *= drcCifStyle->cs_expander; // BSI
|
||||
dpnext = drcCifRules[layer[0]][DRC_CIF_SOLID];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) sizeof (DRCCookie));
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
||||
|
|
@ -1167,7 +1174,7 @@ drcCifMaxwidth(argc, argv)
|
|||
}
|
||||
|
||||
scalefactor = drcCifStyle->cs_scaleFactor;
|
||||
centidistance *= drcCifStyle->cs_expander; // BSI
|
||||
// centidistance *= drcCifStyle->cs_expander; // BSI
|
||||
dpnext = drcCifRules[thislayer][DRC_CIF_SPACE];
|
||||
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
||||
drcCifAssign(dpnew, centidistance, dpnext, &CIFSolidBits, &CIFSolidBits,
|
||||
|
|
|
|||
|
|
@ -107,10 +107,22 @@ drcFindOtherCells(use, area)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* For each tile found in drcCopyErrorsFunc(), translate the */
|
||||
/* tile position into the coordinate system of the parent cell */
|
||||
/* (represented by the drcTemp plane in ClientData) and */
|
||||
/* copy (paint) into it. */
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* drcSubCopyErrors ---
|
||||
*
|
||||
* For each tile found in drcCopyErrorsFunc(), translate the tile position
|
||||
* into the coordinate system of the parent cell (represented by the drcTemp
|
||||
* plane in ClientData) and apply the function passed in the filter, which is
|
||||
* whatever function handles DRC errors inside an error tile (which is
|
||||
* different for "drc why" commands than for "drc check".
|
||||
*
|
||||
* Returns:
|
||||
* 0 to keep the search going.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
drcSubCopyErrors(tile, cxp)
|
||||
|
|
@ -121,9 +133,6 @@ drcSubCopyErrors(tile, cxp)
|
|||
Rect destArea;
|
||||
struct drcClientData *arg = (struct drcClientData *)cxp->tc_filter->tf_arg;
|
||||
|
||||
// DBTreeSrTiles() checks its own tiles, which we want to ignore.
|
||||
if (arg->dCD_celldef == cxp->tc_scx->scx_use->cu_def) return 0;
|
||||
|
||||
TiToRect(tile, &area);
|
||||
GeoClip(&area, &cxp->tc_scx->scx_area);
|
||||
GeoTransRect(&cxp->tc_scx->scx_trans, &area, &destArea);
|
||||
|
|
@ -135,6 +144,40 @@ drcSubCopyErrors(tile, cxp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* drcSubCopyFunc ---
|
||||
*
|
||||
* This routine is applied for each subcell of a parent def. It calls
|
||||
* DBNoTreeSrTiles() with the above routine drcSubCopyErrors(), which
|
||||
* copies all TT_ERROR_P tiles from the child cell up into the parent.
|
||||
* This is used only within areas found to be non-interacting with the
|
||||
* parent, such that any error found in the child cell is guaranteed to
|
||||
* be a real error, and not one that might be resolved by additional
|
||||
* material found in the parent or a sibling cell.
|
||||
*
|
||||
* Returns:
|
||||
* Whatever DBNoTreeSrTiles() returns.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
drcSubCopyFunc(scx, cdarg)
|
||||
SearchContext *scx;
|
||||
ClientData cdarg;
|
||||
{
|
||||
TileTypeBitMask drcMask;
|
||||
|
||||
/* Create a mask with only TT_ERROR_P in it */
|
||||
TTMaskZero(&drcMask);
|
||||
TTMaskSetType(&drcMask, TT_ERROR_P);
|
||||
|
||||
/* Use DBNoTreeSrTiles() because we want to search only one level down */
|
||||
return DBNoTreeSrTiles(scx, &drcMask, 0, drcSubCopyErrors, cdarg);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -607,17 +650,12 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
void (*savedPaintPlane)();
|
||||
struct drcClientData arg;
|
||||
SearchContext scx;
|
||||
TileTypeBitMask drcMask;
|
||||
|
||||
drcSubFunc = func;
|
||||
drcSubClientData = cdarg;
|
||||
oldTiles = DRCstatTiles;
|
||||
count = 0;
|
||||
|
||||
/* Create a mask with only TT_ERROR_P in it */
|
||||
TTMaskZero(&drcMask);
|
||||
TTMaskSetType(&drcMask, TT_ERROR_P);
|
||||
|
||||
/* Divide the area to be checked up into squares. Process each
|
||||
* square separately.
|
||||
*/
|
||||
|
|
@ -670,7 +708,7 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
|
||||
/* Copy errors up from all non-interacting children */
|
||||
scx.scx_area = subArea;
|
||||
DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg);
|
||||
DBCellSrArea(&scx, drcSubCopyFunc, &arg);
|
||||
|
||||
DRCErrorType = errorSaveType;
|
||||
continue;
|
||||
|
|
@ -706,7 +744,7 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
|
||||
/* Copy errors up from all non-interacting children */
|
||||
scx.scx_area = subArea;
|
||||
DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg);
|
||||
DBCellSrArea(&scx, drcSubCopyFunc, &arg);
|
||||
}
|
||||
/* check below */
|
||||
if (intArea.r_ybot > eraseClip.r_ybot)
|
||||
|
|
@ -717,7 +755,7 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
|
||||
/* Copy errors up from all non-interacting children */
|
||||
scx.scx_area = subArea;
|
||||
DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg);
|
||||
DBCellSrArea(&scx, drcSubCopyFunc, &arg);
|
||||
}
|
||||
subArea.r_ytop = intArea.r_ytop;
|
||||
subArea.r_ybot = intArea.r_ybot;
|
||||
|
|
@ -730,7 +768,7 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
|
||||
/* Copy errors up from all non-interacting children */
|
||||
scx.scx_area = subArea;
|
||||
DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg);
|
||||
DBCellSrArea(&scx, drcSubCopyFunc, &arg);
|
||||
}
|
||||
/* check left */
|
||||
if (intArea.r_xbot > eraseClip.r_xbot)
|
||||
|
|
@ -741,7 +779,7 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
|
|||
DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
|
||||
/* Copy errors up from all non-interacting children */
|
||||
scx.scx_area = subArea;
|
||||
DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg);
|
||||
DBCellSrArea(&scx, drcSubCopyFunc, &arg);
|
||||
}
|
||||
DRCErrorType = errorSaveType;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,10 +92,11 @@ FILE *esLabF = NULL;
|
|||
static unsigned short esFormat = MIT ;
|
||||
|
||||
struct {
|
||||
short resClassSource ; /* the resistance class of the source of the dev */
|
||||
short resClassDrain ; /* the resistance class of the drain of the dev */
|
||||
short resClassSub ; /* the resistance class of the substrate of the dev */
|
||||
char *defSubs ; /* the default substrate node */
|
||||
short resClassSource ; /* The resistance class of the source of the dev */
|
||||
short resClassDrain ; /* The resistance class of the drain of the dev */
|
||||
short resClassSub ; /* The resistance class of the substrate of the dev */
|
||||
TileType devType ; /* Magic tile type of the device */
|
||||
char *defSubs ; /* The default substrate node */
|
||||
} fetInfo[MAXDEVTYPES];
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -266,6 +267,7 @@ CmdExtToSim(w, cmd)
|
|||
short s_rclass, d_rclass, sub_rclass;
|
||||
char *devname;
|
||||
char *subname;
|
||||
TileType devtype;
|
||||
int idx;
|
||||
|
||||
static EFCapValue LocCapThreshold = 2;
|
||||
|
|
@ -576,6 +578,7 @@ runexttosim:
|
|||
fetInfo[i].resClassDrain = NO_RESCLASS;
|
||||
fetInfo[i].resClassSub = NO_RESCLASS;
|
||||
fetInfo[i].defSubs = NULL;
|
||||
fetInfo[i].devType = TT_SPACE;
|
||||
}
|
||||
|
||||
/* Get fetInfo information from the current extraction style */
|
||||
|
|
@ -583,7 +586,8 @@ runexttosim:
|
|||
/* command) */
|
||||
|
||||
idx = 0;
|
||||
while (ExtGetDevInfo(idx++, &devname, &s_rclass, &d_rclass, &sub_rclass, &subname))
|
||||
while (ExtGetDevInfo(idx++, &devname, &devtype, &s_rclass, &d_rclass,
|
||||
&sub_rclass, &subname))
|
||||
{
|
||||
if (idx == MAXDEVTYPES)
|
||||
{
|
||||
|
|
@ -598,6 +602,7 @@ runexttosim:
|
|||
fetInfo[i].resClassDrain = d_rclass;
|
||||
fetInfo[i].resClassSub = sub_rclass;
|
||||
fetInfo[i].defSubs = subname;
|
||||
fetInfo[i].devType = devtype;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -676,6 +681,7 @@ main(argc, argv)
|
|||
fetInfo[i].resClassDrain = NO_RESCLASS;
|
||||
fetInfo[i].resClassSub = NO_RESCLASS;
|
||||
fetInfo[i].defSubs = NULL;
|
||||
fetInfo[i].devType = TT_SPACE;
|
||||
}
|
||||
i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "nfet");
|
||||
fetInfo[i].resClassSource = fetInfo[i].resClassDrain = 0 ;
|
||||
|
|
@ -895,6 +901,7 @@ simmainArgs(pargc, pargv)
|
|||
fetInfo[ndx].resClassDrain = rClass;
|
||||
fetInfo[ndx].resClassSub = rClassSub;
|
||||
fetInfo[ndx].defSubs = (char *) mallocMagic((unsigned) (strlen(subsNode)+1));
|
||||
fetInfo[ndx].devType = TT_SPACE;
|
||||
strcpy(fetInfo[ndx].defSubs,subsNode);
|
||||
TxError("Info: fet %s(%d) sdRclass=%d subRclass=%d dSub=%s\n",
|
||||
cp, ndx, fetInfo[ndx].resClassSD, fetInfo[ndx].resClassSub,
|
||||
|
|
@ -1047,6 +1054,41 @@ simdevVisit(dev, hc, scale, trans)
|
|||
case DEV_CAPREV:
|
||||
fprintf(esSimF, "c"); /* sim format extension */
|
||||
break;
|
||||
case DEV_FET:
|
||||
case DEV_MOSFET:
|
||||
case DEV_ASYMMETRIC:
|
||||
case DEV_MSUBCKT:
|
||||
/* The sim file format only understands "n" and "p" for FETs. */
|
||||
/* The extraction method says nothing about which is which. */
|
||||
/* The EFDevTypes[] should ideally start with "n" or "p". If */
|
||||
/* it doesn't, then dev->dev_type should. If neither does, */
|
||||
/* then use EFDevTypes[] but flag an error. */
|
||||
|
||||
if (EFDevTypes[dev->dev_type][0] == 'n' ||
|
||||
EFDevTypes[dev->dev_type][0] == 'p')
|
||||
{
|
||||
fprintf(esSimF, "%c", EFDevTypes[dev->dev_type][0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
TileType ttype = fetInfo[dev->dev_type].devType;
|
||||
|
||||
if (DBTypeLongNameTbl[ttype][0] == 'n' ||
|
||||
DBTypeLongNameTbl[ttype][0] == 'p')
|
||||
{
|
||||
fprintf(esSimF, "%c", DBTypeLongNameTbl[ttype][0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
TxError("Error: MOSFET device type \"%s\" does not start with "
|
||||
"\"n\" or \"p\" as required for the .sim format\n",
|
||||
EFDevTypes[dev->dev_type]);
|
||||
|
||||
/* Default to "n" */
|
||||
fprintf(esSimF, "n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(esSimF, "%c", EFDevTypes[dev->dev_type][0]);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -242,6 +242,7 @@ CmdExtToSpice(w, cmd)
|
|||
short s_rclass, d_rclass, sub_rclass;
|
||||
char *devname;
|
||||
char *subname;
|
||||
TileType devtype;
|
||||
int idx, idx2;
|
||||
globalList *glist = NULL;
|
||||
|
||||
|
|
@ -739,7 +740,8 @@ runexttospice:
|
|||
/* command) */
|
||||
|
||||
idx = 0;
|
||||
while (ExtGetDevInfo(idx++, &devname, &s_rclass, &d_rclass, &sub_rclass, &subname))
|
||||
while (ExtGetDevInfo(idx++, &devname, &devtype, &s_rclass, &d_rclass,
|
||||
&sub_rclass, &subname))
|
||||
{
|
||||
if (idx == MAXDEVTYPES)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1484,6 +1484,9 @@ extOutputParameters(def, transList, outFile)
|
|||
|
||||
for (devptr = ExtCurStyle->exts_device[t]; devptr; devptr = devptr->exts_next)
|
||||
{
|
||||
/* Do not output parameters for ignored devices */
|
||||
if (!strcmp(devptr->exts_deviceName, "Ignore")) continue;
|
||||
|
||||
plist = devptr->exts_deviceParams;
|
||||
if (plist != (ParamList *)NULL)
|
||||
{
|
||||
|
|
@ -1726,9 +1729,15 @@ extOutputDevices(def, transList, outFile)
|
|||
tmask = &devptr->exts_deviceSDTypes[termcount];
|
||||
if (TTMaskIsZero(tmask)) {
|
||||
if (termcount < nsd) {
|
||||
ExtDevice *devcheck;
|
||||
/* See if there is another matching device record with */
|
||||
/* a different number of terminals, and try again. */
|
||||
devptr = extDevFindMatch(devptr, t);
|
||||
devcheck = extDevFindMatch(devptr, t);
|
||||
if (devcheck != NULL) devptr = devcheck;
|
||||
|
||||
/* Not finding another device record just means that */
|
||||
/* terminals are tied together on the same net, such as */
|
||||
/* with a MOS cap. Accept this fact and move on. */
|
||||
}
|
||||
break; /* End of SD terminals */
|
||||
}
|
||||
|
|
@ -1851,6 +1860,14 @@ extOutputDevices(def, transList, outFile)
|
|||
#endif
|
||||
extTransRec.tr_devrec = devptr;
|
||||
|
||||
/* Model type "Ignore" in the techfile indicates a device */
|
||||
/* to be ignored (i.e., a specific combination of layers */
|
||||
/* does not form an extractable device, or overlaps another */
|
||||
/* device type that should take precedence). */
|
||||
|
||||
if (!strcmp(devptr->exts_deviceName, "Ignore"))
|
||||
continue;
|
||||
|
||||
/* Original-style FET record backward compatibility */
|
||||
if (devptr->exts_deviceClass != DEV_FET)
|
||||
fprintf(outFile, "device ");
|
||||
|
|
|
|||
|
|
@ -427,9 +427,9 @@ extHardGenerateLabel(scx, reg, arg)
|
|||
len = strlen(gen) + prefixlen;
|
||||
newlab = (Label *) mallocMagic((unsigned) (sizeof (Label) + len - 3));
|
||||
r.r_ll = reg->treg_tile->ti_ll;
|
||||
GEOCLIP(&r,&scx->scx_area);
|
||||
r.r_ur.p_x = r.r_ll.p_x+1;
|
||||
r.r_ur.p_y = r.r_ll.p_y+1;
|
||||
GEOCLIP(&r,&scx->scx_area);
|
||||
GeoTransRect(&scx->scx_trans, &r, &newlab->lab_rect);
|
||||
newlab->lab_type = TiGetType(reg->treg_tile);
|
||||
|
||||
|
|
|
|||
|
|
@ -218,13 +218,14 @@ ExtLabelRegions(def, connTo, nodeList, clipArea)
|
|||
for (quad = 0; quad < 4; quad++)
|
||||
{
|
||||
/*
|
||||
* Visit each of the four quadrants surrounding
|
||||
* the lower-left corner of the label, searching
|
||||
* for a tile whose type matches that of the label
|
||||
* or connects to it.
|
||||
* Visit each of the four quadrants surrounding the center
|
||||
* point of the label, searching for a tile whose type matches
|
||||
* that of the label or connects to it.
|
||||
*/
|
||||
p.p_x = lab->lab_rect.r_xbot + offsets[quad].p_x;
|
||||
p.p_y = lab->lab_rect.r_ybot + offsets[quad].p_y;
|
||||
p.p_x = ((lab->lab_rect.r_xbot + lab->lab_rect.r_xtop) >> 1)
|
||||
+ offsets[quad].p_x;
|
||||
p.p_y = ((lab->lab_rect.r_ybot + lab->lab_rect.r_ytop) >> 1)
|
||||
+ offsets[quad].p_y;
|
||||
tp = def->cd_planes[pNum]->pl_hint;
|
||||
GOTOPOINT(tp, &p);
|
||||
def->cd_planes[pNum]->pl_hint = tp;
|
||||
|
|
|
|||
|
|
@ -304,9 +304,11 @@ ExtCompareStyle(stylename)
|
|||
*/
|
||||
|
||||
bool
|
||||
ExtGetDevInfo(idx, devnameptr, s_rclassptr, d_rclassptr, sub_rclassptr, subnameptr)
|
||||
ExtGetDevInfo(idx, devnameptr, devtypeptr, s_rclassptr, d_rclassptr,
|
||||
sub_rclassptr, subnameptr)
|
||||
int idx;
|
||||
char **devnameptr;
|
||||
char **devnameptr; /* Name of extracted device model */
|
||||
TileType *devtypeptr; /* Magic tile type of device */
|
||||
short *s_rclassptr; /* Source (1st terminal) type only */
|
||||
short *d_rclassptr; /* Drain (2nd terminal) type only */
|
||||
short *sub_rclassptr;
|
||||
|
|
@ -354,6 +356,7 @@ ExtGetDevInfo(idx, devnameptr, s_rclassptr, d_rclassptr, sub_rclassptr, subnamep
|
|||
|
||||
*devnameptr = locdname;
|
||||
*subnameptr = devptr->exts_deviceSubstrateName;
|
||||
*devtypeptr = t;
|
||||
|
||||
tmask = &devptr->exts_deviceSDTypes[0];
|
||||
*s_rclassptr = (short)(-1); /* NO_RESCLASS */
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ makeUnique:
|
|||
|
||||
lab = ll2->ll_label;
|
||||
saveLab = *lab;
|
||||
DBEraseLabelsByContent(def, &lab->lab_rect, lab->lab_type, lab->lab_text);
|
||||
DBRemoveLabel(def, lab);
|
||||
(void) DBPutFontLabel(def, &saveLab.lab_rect,
|
||||
saveLab.lab_font, saveLab.lab_size, saveLab.lab_rotate,
|
||||
&saveLab.lab_offset, saveLab.lab_just, name2,
|
||||
|
|
|
|||
10
lef/lefCmd.c
10
lef/lefCmd.c
|
|
@ -112,15 +112,15 @@ CmdLef(w, cmd)
|
|||
static char *cmdLefOption[] =
|
||||
{
|
||||
"read [filename] read a LEF file filename[.lef]\n"
|
||||
" read [filename] -import read a LEF file; import cells from .mag files\n",
|
||||
" read [filename] -annotate read a LEF file for cell annotation only.",
|
||||
" read [filename] -import read a LEF file; import cells from .mag files\n"
|
||||
" read [filename] -annotate read a LEF file for cell annotation only."
|
||||
"write [filename] [-tech] write LEF for current cell\n"
|
||||
" write [filename] -hide hide all details other than ports\n",
|
||||
" write [filename] -hide hide all details other than ports\n"
|
||||
" write [filename] -hide <d> hide details in area set back distance <d>",
|
||||
"writeall write all cells including the top-level cell\n"
|
||||
" writeall -notop write all children of the top-level cell\n"
|
||||
" writeall -all recurse on all subcells of the top-level cell\n",
|
||||
" writeall -hide hide all details other than ports\n",
|
||||
" writeall -all recurse on all subcells of the top-level cell\n"
|
||||
" writeall -hide hide all details other than ports\n"
|
||||
" writeall -hide [dist] hide details in area set back distance dist",
|
||||
"help print this help information",
|
||||
NULL
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ if {$::tk_version >= 8.5} {
|
|||
|
||||
set Opts(cellmgr) 0
|
||||
|
||||
magic::tag select "magic::mgrselect %R"
|
||||
magic::tag select "magic::mgrselect %r"
|
||||
magic::tag load "catch {magic::clearstack}; magic::cellmanager"
|
||||
magic::tag getcell "magic::cellmanager"
|
||||
|
||||
|
|
|
|||
|
|
@ -220,10 +220,14 @@ proc readspice {netfile} {
|
|||
set pinname [lindex $infopair 0]
|
||||
set pindir [lindex $infopair 1]
|
||||
if {![catch {set pin [dict get $pindict $pinname]}]} {
|
||||
case $pindir {
|
||||
B {port $pin class inout}
|
||||
I {port $pin class input}
|
||||
O {port $pin class output}
|
||||
# Only set pin class if the pin class is currently default
|
||||
set pinclass [port $pin class]
|
||||
if {$pinclass == "default"} {
|
||||
case $pindir {
|
||||
B {port $pin class inout}
|
||||
I {port $pin class input}
|
||||
O {port $pin class output}
|
||||
}
|
||||
}
|
||||
} elseif {$pinname != ""} {
|
||||
puts stderr ".PININFO error: Pin $pinname not found."
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
# Revision 0
|
||||
# December 15, 2016
|
||||
# Revision 1
|
||||
# October 29, 2020
|
||||
# Revision 2 (names are hashed from properties)
|
||||
#--------------------------------------------------------------
|
||||
# Sets up the environment for a toolkit. The toolkit must
|
||||
# supply a namespace that is the "library name". For each
|
||||
|
|
@ -237,6 +239,36 @@ proc magic::gencell {gencell_name {instname {}} args} {
|
|||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# gencell_makecell
|
||||
#
|
||||
# This is a variation of magic::gencell and is used to generate
|
||||
# a cell and return the cell name without creating or placing
|
||||
# an instance.
|
||||
#-------------------------------------------------------------
|
||||
|
||||
proc magic::gencell_makecell {gencell_fullname args} {
|
||||
|
||||
set argpar [dict create {*}$args]
|
||||
set gencell_basename [namespace tail $gencell_fullname]
|
||||
set library [namespace qualifiers $gencell_fullname]
|
||||
set parameters [magic::gencell_defaults $gencell_basename $library $argpar]
|
||||
set gsuffix [magic::get_gencell_hash ${parameters}]
|
||||
set gname ${gencell_basename}_${gsuffix}
|
||||
suspendall
|
||||
cellname create $gname
|
||||
pushstack $gname
|
||||
if {[catch {${library}::${gencell_basename}_draw $parameters} drawerr]} {
|
||||
puts stderr $drawerr
|
||||
}
|
||||
property library $library
|
||||
property gencell $gencell_basename
|
||||
property parameters $parameters
|
||||
popstack
|
||||
resumeall
|
||||
return $gname
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# gencell_getparams
|
||||
#
|
||||
|
|
@ -271,6 +303,9 @@ proc magic::gencell_setparams {parameters} {
|
|||
if {[catch {set state [wm state .params]}]} {return}
|
||||
set slist [grid slaves .params.edits]
|
||||
foreach s $slist {
|
||||
# ignore .params.edits.gencell_sel, as that does not exist in the
|
||||
# parameters dictionary
|
||||
if {$s == ".params.edits.gencell_sel"} {continue}
|
||||
if {[regexp {^.params.edits.(.*)_ent$} $s valid pname] != 0} {
|
||||
set value [dict get $parameters $pname]
|
||||
set magic::${pname}_val $value
|
||||
|
|
@ -293,7 +328,16 @@ proc magic::gencell_setparams {parameters} {
|
|||
#-------------------------------------------------------------
|
||||
# gencell_change
|
||||
#
|
||||
# Redraw a gencell with new parameters.
|
||||
# Recreate a gencell with new parameters. Note that because
|
||||
# each cellname is uniquely identified by the (hashed) set
|
||||
# of parameters, changing parameters effectively means
|
||||
# creating a new cell. If the original cell has parents
|
||||
# other than the parent of the instance being changed, then
|
||||
# it is retained; otherwise, it is deleted. The instance
|
||||
# being edited gets replaced by an instance of the new cell.
|
||||
# If the instance name was the cellname + suffix, then the
|
||||
# instance name is regenerated. Otherwise, the instance
|
||||
# name is retained.
|
||||
#-------------------------------------------------------------
|
||||
|
||||
proc magic::gencell_change {instname gencell_type library parameters} {
|
||||
|
|
@ -324,6 +368,128 @@ proc magic::gencell_change {instname gencell_type library parameters} {
|
|||
set parameters [dict remove $parameters gencell]
|
||||
}
|
||||
|
||||
set old_gname [instance list celldef $instname]
|
||||
set gsuffix [magic::get_gencell_hash ${parameters}]
|
||||
set gname ${gencell_type}_${gsuffix}
|
||||
|
||||
# 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.
|
||||
if {$gname == "" || $gname == $old_gname} {
|
||||
resumeall
|
||||
return
|
||||
}
|
||||
|
||||
set snaptype [snap list]
|
||||
snap internal
|
||||
set savebox [box values]
|
||||
|
||||
catch {setpoint 0 0 $Opts(focus)}
|
||||
if [dict exists $parameters nocell] {
|
||||
select cell $instname
|
||||
set abox [instance list abutment]
|
||||
delete
|
||||
if {$abox != ""} {box values {*}$abox}
|
||||
if {[catch {set newinst [${library}::${gencell_type}_draw $parameters]} \
|
||||
drawerr]} {
|
||||
puts stderr $drawerr
|
||||
}
|
||||
select cell $newinst
|
||||
} elseif {[cellname list exists $gname] != 0} {
|
||||
# If there is already a cell of this type then it is only required to
|
||||
# remove the instance and replace it with an instance of the cell
|
||||
select cell $instname
|
||||
# check rotate/flip before replacing and replace with same
|
||||
set orient [instance list orientation]
|
||||
set abox [instance list abutment]
|
||||
delete
|
||||
|
||||
if {$abox != ""} {box values {*}$abox}
|
||||
set newinstname [getcell $gname $orient]
|
||||
select cell $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} {
|
||||
set newinstname $instname
|
||||
}
|
||||
}
|
||||
identify $newinstname
|
||||
eval "box values $savebox"
|
||||
snap $snaptype
|
||||
|
||||
# Update window
|
||||
if {$gname != $old_gname} {
|
||||
catch {.params.title.glab configure -text "$gname"}
|
||||
}
|
||||
if {$instname != $newinstname} {
|
||||
catch {.params.title.ient delete 0 end}
|
||||
catch {.params.title.ient insert 0 "$newinstname"}
|
||||
}
|
||||
|
||||
resumeall
|
||||
redraw
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# gencell_change_orig
|
||||
#
|
||||
# Original version: Redraw a gencell with new parameters,
|
||||
# without changing the cell itself.
|
||||
#-------------------------------------------------------------
|
||||
|
||||
proc magic::gencell_change_orig {instname gencell_type library parameters} {
|
||||
global Opts
|
||||
suspendall
|
||||
|
||||
set newinstname $instname
|
||||
if {$parameters == {}} {
|
||||
# Get device defaults
|
||||
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}
|
||||
}
|
||||
if {[dict exists $parameters gencell]} {
|
||||
# Setting special parameter "gencell" forces the gencell to change type
|
||||
set gencell_type [dict get $parameters gencell]
|
||||
}
|
||||
if {[catch {set parameters [${library}::${gencell_type}_check $parameters]} \
|
||||
checkerr]} {
|
||||
puts stderr $checkerr
|
||||
}
|
||||
magic::gencell_setparams $parameters
|
||||
if {[dict exists $parameters gencell]} {
|
||||
set parameters [dict remove $parameters gencell]
|
||||
}
|
||||
|
||||
set gname [instance list celldef $instname]
|
||||
|
||||
# Guard against instance having been deleted
|
||||
|
|
@ -391,6 +557,51 @@ proc magic::get_gencell_name {gencell_type} {
|
|||
return ${gencell_type}_$postfix
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# get_gencell_hash
|
||||
#
|
||||
# A better approach to the above. Take the parameter
|
||||
# dictionary, and run all the values through a hash function
|
||||
# to generate a 30-bit value, then convert to base32. This
|
||||
# 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).
|
||||
#----------------------------------------------------------------
|
||||
|
||||
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)}]
|
||||
}
|
||||
}
|
||||
# Divide hash up into 5 bit values and convert to base32
|
||||
# using letters A-Z less I and O, and digits 2-9.
|
||||
set cvals ""
|
||||
for {set i 0} {$i < 6} {incr i} {
|
||||
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]
|
||||
}
|
||||
return $cvals
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# gencell_create
|
||||
#
|
||||
|
|
@ -402,7 +613,7 @@ proc magic::get_gencell_name {gencell_type} {
|
|||
# the drawing routine is going to do to the stack!
|
||||
#-------------------------------------------------------------
|
||||
|
||||
proc magic::gencell_create {gencell_type library parameters} {
|
||||
proc magic::gencell_create {gencell_type library parameters {orient 0}} {
|
||||
global Opts
|
||||
suspendall
|
||||
|
||||
|
|
@ -451,7 +662,8 @@ proc magic::gencell_create {gencell_type library parameters} {
|
|||
set gname [instance list celldef $instname]
|
||||
eval "box values $savebox"
|
||||
} else {
|
||||
set gname [magic::get_gencell_name ${gencell_type}]
|
||||
set gsuffix [magic::get_gencell_hash ${parameters}]
|
||||
set gname ${gencell_type}_${gsuffix}
|
||||
cellname create $gname
|
||||
pushstack $gname
|
||||
if {[catch {${library}::${gencell_type}_draw $parameters} drawerr]} {
|
||||
|
|
@ -462,7 +674,7 @@ proc magic::gencell_create {gencell_type library parameters} {
|
|||
property parameters $parameters
|
||||
popstack
|
||||
eval "box values $savebox"
|
||||
set instname [getcell $gname]
|
||||
set instname [getcell $gname $orient]
|
||||
expand
|
||||
}
|
||||
if {$newinstname != ""} {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ proc magic::suspendall {} {
|
|||
global Winopts
|
||||
if {[info commands winfo] != ""} {
|
||||
foreach window [magic::windownames layout] {
|
||||
if {$window == 0} {continue}
|
||||
set framename [winfo toplevel $window]
|
||||
if {$framename == "."} {
|
||||
set framename $window
|
||||
|
|
@ -30,6 +31,7 @@ proc magic::resumeall {} {
|
|||
global Winopts
|
||||
if {[info commands winfo] != ""} {
|
||||
foreach window [magic::windownames layout] {
|
||||
if {$window == 0} {continue}
|
||||
set framename [winfo toplevel $window]
|
||||
if {$framename == "."} {
|
||||
set framename $window
|
||||
|
|
|
|||
Loading…
Reference in New Issue