Merge branch 'master' of https://github.com/RTimothyEdwards/magic into spice_hier

This commit is contained in:
Dan Moore 2020-11-07 15:46:53 -08:00
commit d38c088109
30 changed files with 1683 additions and 137 deletions

View File

@ -1 +1 @@
8.3.67
8.3.77

View File

@ -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,

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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]);
}

View File

@ -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)
{

View File

@ -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;
}
/*
* ----------------------------------------------------------------------------
*

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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))
{

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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)
{

View File

@ -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 ");

View File

@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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,

View File

@ -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

View File

@ -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"

View File

@ -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."

View File

@ -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 != ""} {

View File

@ -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