Compare commits

...

17 Commits

Author SHA1 Message Date
Torleif Skår fc7aac1ca1
Merge d825f6cafe into 246c0ea7a4 2025-10-31 17:26:02 +01:00
R. Timothy Edwards 246c0ea7a4 Extended the "maxwidth" DRC rule to take an optional set of layers
that exclude the maxwidth rule from taking effect.  This is
especially useful for implementing a maxwidth rule on top metal
that does not apply to pads, using the passivation cut layer to
prevent the maxwidth rule from being applied.
2025-10-30 16:39:54 -04:00
R. Timothy Edwards 47778971ee And one more fix to the method, for which I added a variation of
DBNMSrPaintPlane() where if "tile" is non-NULL then "plane" can be
NULL;  the hint tile does not get set but the routine can be called
without knowing the plane other than that the tile is in it somewhere.
2025-10-30 13:18:12 -04:00
R. Timothy Edwards cccd79ab0d One correction to the last commit---The additional check is not
limited to the DRC_REVERSE case but must be done in both the
forward and reverse cases.
2025-10-30 12:37:00 -04:00
R. Timothy Edwards 51b9846120 Made a correction to the DRC error checking on a non-Manhattan
edge.  This was catching geometry unrelated to the error when doing
a spacing check between geometry on different planes.  In the
reverse-edge case, magic needed to run an additional search over
the area on the other side of the original edge that triggered
the rule to effectively clip that corner of the triangle from the
search area.
2025-10-30 12:07:29 -04:00
R. Timothy Edwards 1afd48e840 Corrected an error in which an invalid client name passed to the
"macro" command will crash magic.  This will happen if, for
example, magic is compiled without OpenGL support, in which case
the "wind3d" client does not exist, and parsing the default
macros from the system .magicrc file will cause an immediate
crash.
2025-10-29 09:32:03 -04:00
R. Timothy Edwards 99a5a28a3e Added a drc check to the gencell change procedure, as it appears
that otherwise DRC is not re-checked after a gencell update.  It
is not clear to me why checks are not done otherwise.
2025-10-28 15:10:03 -04:00
R. Timothy Edwards 0ac4d3a465 Found a way to work around the problem of having subcell DRC
errors show up as "See error definition in subcell", which has
been the case since I modified the code to prevent showing DRC
errors in subcells that have been resolved by the hierarchy
above them.  DRC errors are now intelligently searched
downward in the heirarchy when enumerated for "drc why".
Also changed the DRC check tile definition to offset such that
there is a tile centered on the origin, instead of the origin
being between four tiles.  Since most layouts are subcells and
most subcells are small relative to the DRC check tile area,
and most subcells are placed near the origin, then most subcells
will appear in only one tile, which speeds up the DRC process
somewhat.
2025-10-23 17:11:44 -04:00
R. Timothy Edwards 42aa06f8f5 Corrected what seems to be a long-standing error in which
DRCCheckThis() is called in order of top to bottom of the hierarchy
when called from drcCheckFunc() although it was changed to order
DRCPendingRoot from bottom to top.  drcCheckFunc() then does it
backwards.  Fixing this appears to have resolved some weird errors
with DRC errors not showing up when doing "drc check" (initially)
and DRC errors disappearing when making changes to a generated
cell.  Appears to be okay now.
2025-10-22 17:27:00 -04:00
R. Timothy Edwards 4d2912a406 Corrected the return value of spcWriteValue() (recently added)
from "bool" to "void" (does not return a value).
2025-10-21 09:15:05 -04:00
R. Timothy Edwards b668b02a1f Corrected a problem in which "cellname delete" never cleared the
cell name from the cell name hash table.  So when "cellname rename"
was changed recently to prevent changing the name of a cell that
already exists, the suggested recipe for R-C extraction no longer
works:  "load x; flatten y; load y; cellname delete x; cellname
rename y x".  Solved by adding a HashRemove() function to the
cell deletion routine.  Thanks to Egor Lukyachenko for reporting
the issue (Github issue tracker #467).
2025-10-20 11:03:03 -04:00
R. Timothy Edwards 6b8f5d1d67 Modified the toolkit behavior so that a default callback to update
the dialog (and run limit checks) is installed by default on
checkboxes and selection menus, as it is already done for entry
boxes.  Otherwise it is possible to make a selection (like changing
a device type) that invalidates the existing values, but if Apply
is hit immediately afterward, then no checks will be run and the
values may be used as-is even if invalid.  This does not prohibit
the use of "add_dependency" to change the callback behavior.
2025-10-16 17:08:15 -04:00
R. Timothy Edwards c977e4cf76 Corrected an error introduced yesterday by a hasty fix, which
ended up breaking the "extresist" function by failing to parse
the comment line of a .sim file.  This is now fixed.
2025-10-15 10:00:02 -04:00
R. Timothy Edwards 9327e319da Corrected ext2sim to handle the new "dsubcircuit" device type,
added in a recent commit.  The extension was handled by
"ext2spice" but "ext2sim" was missed.  Without it, "extresist"
will fail for any circuit containing a device defined in the
tech file extract section with "dsubcircuit".
2025-10-15 08:31:58 -04:00
R. Timothy Edwards 0e84616af8 Corrected an error that allows a cell to be renamed with the name
of an existing cell, which does not appear to be a fatal problem,
but must be causing a memory leak.  Also:  Corrected an error in
extresist when reading .sim files, in code that is slated to be
overhauled, so this is just a patch to avoid a crash condition.
2025-10-14 10:36:07 -04:00
Torleif Skår d825f6cafe textio/txInput.c: Refactor header includes
Rather than being dependent on OS-level defines,
refactor to use feature-level defines.
2025-07-31 20:13:45 +02:00
Torleif Skår 388572c1ff utils/magsgtty.h: Refactor header includes 2025-07-31 20:10:22 +02:00
17 changed files with 379 additions and 151 deletions

View File

@ -1 +1 @@
8.3.561
8.3.571

View File

@ -117,6 +117,14 @@ DBCellRename(cellname, newname, doforce)
return FALSE;
}
/* Cannot rename a cell with the name of an existing cell */
entry = HashLookOnly(&dbCellDefTable, newname);
if (entry != NULL)
{
TxError("Cannot rename; cell \"%s\" already exists!\n", newname);
return FALSE;
}
/* Disallow renaming if the cell has the READONLY flag set, */
/* because the cellname must match the name in the GDS */
/* file referenced. */
@ -1936,6 +1944,7 @@ DBCellDeleteDef(cellDef)
entry = HashFind(&dbCellDefTable, cellDef->cd_name);
ASSERT(HashGetValue(entry) == (ClientData) cellDef, "DBCellDeleteDef");
HashSetValue(entry, (ClientData) NULL);
HashRemove(&dbCellDefTable, cellDef->cd_name);
if (cellDef->cd_props)
DBPropClearAll(cellDef);

View File

@ -92,7 +92,7 @@ DBSrPaintNMArea(hintTile, plane, ttype, rect, mask, func, arg)
* provide a hint tile in case hintTile == NULL.
* The hint tile in the plane is updated to be
* the last tile visited in the area
* enumeration.
* enumeration, if plane is non-NULL.
*/
TileType ttype; /* Information about the non-manhattan area to
* search; zero if area is manhattan.
@ -129,7 +129,7 @@ DBSrPaintNMArea(hintTile, plane, ttype, rect, mask, func, arg)
{
/* Each iteration enumerates another tile */
nm_enum:
PlaneSetHint(plane, tp);
if (plane != (Plane *)NULL) PlaneSetHint(plane, tp);
if (SigInterruptPending)
return (1);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 893 B

After

Width:  |  Height:  |  Size: 991 B

View File

@ -36,6 +36,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/signals.h"
#include "utils/maxrect.h"
#include "utils/malloc.h"
#include "textio/textio.h"
int dbDRCDebug = 0;
@ -284,12 +285,53 @@ areaCheck(tile, arg)
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* areaNMReject ---
*
* Trivial callback function used by areaNMCheck to see if a tile
* found in the error area of a reverse non-manhattan check exists
* only on the other side of the original check boundary. If it
* is found in this search, return 1 to immediately stop the search.
*
* Results:
* Returns 1 if the tile indicated in the ClientData argument was
* found in the check area, otherwise return 0 to keep looking.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
areaNMReject(tile, arg)
Tile *tile;
ClientData *arg;
{
Tile *checktile = (Tile *)arg;
if (tile == checktile)
return 1;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* areaNMCheck ---
*
* Check for errors in triangular area of a tile
* Check for errors in triangular area of a tile.
*
* Results:
* Return 0 always to keep the search going.
*
* Side effects:
* If the tile is not rejected due to being outside of the various
* clip areas, then call the function specified in the drcClientData
* argument.
*
* ----------------------------------------------------------------------------
*/
@ -320,6 +362,24 @@ areaNMCheck(tile, arg)
if ((rect.r_xbot >= rect.r_xtop) || (rect.r_ybot >= rect.r_ytop))
return 0;
if (arg->dCD_entries & TT_DIAGONAL)
{
TileTypeBitMask mask;
int dinfo = arg->dCD_entries;
/* In the DRC_REVERSE case, the area being searched extends
* behind the edge that triggered the DRC check, but any
* tile that is outside that edge should be ignored. This
* requires a separate check.
*/
TTMaskSetOnlyType(&mask, TiGetLeftType(tile));
TTMaskSetType(&mask, TiGetRightType(tile));
if (DBSrPaintNMArea((Tile *)tile, (Plane *)NULL, dinfo, arg->dCD_rlist,
&mask, areaNMReject, (ClientData)tile) == 0)
return 0;
}
(*(arg->dCD_function))(arg->dCD_celldef, &rect, arg->dCD_cptr,
arg->dCD_clientData);
(*(arg->dCD_errors))++;
@ -556,6 +616,20 @@ drcTile (tile, arg)
dinfo |= TT_SIDE;
}
/* The area to check is bounded between the diagonals of
* tile and errRect (which is the tile area, offset).
* Pass errRect and dinfo to areaNMCheck using the
* ClientData structure arg->dCD_rlist and arg->dCD_entries,
* which are not used by areaNMCheck.
*/
arg->dCD_rlist = (Rect *)mallocMagic(sizeof(Rect));
*(arg->dCD_rlist) = errRect;
arg->dCD_entries = dinfo;
if (dinfo & TT_SIDE)
arg->dCD_entries &= ~TT_SIDE;
else
arg->dCD_entries |= TT_SIDE;
/* errRect is the tile area offset by (deltax, deltay) */
errRect.r_xbot += deltax;
errRect.r_ybot += deltay;
@ -565,6 +639,10 @@ drcTile (tile, arg)
DBSrPaintNMArea((Tile *) NULL,
arg->dCD_celldef->cd_planes[cptr->drcc_plane], dinfo,
&errRect, &tmpMask, areaNMCheck, (ClientData) arg);
arg->dCD_entries = 0;
freeMagic(arg->dCD_rlist);
arg->dCD_rlist = (Rect *)NULL;
}
DRCstatEdges++;
}
@ -1135,7 +1213,7 @@ drcTile (tile, arg)
lr = &mrd->rlist[i];
GeoClip(lr, arg->dCD_clip);
if (!GEO_RECTNULL(lr))
{
{
(*(arg->dCD_function)) (arg->dCD_celldef,
lr, cptr, arg->dCD_clientData);
(*(arg->dCD_errors))++;

View File

@ -203,13 +203,12 @@ DRCCheckThis (celldef, operation, area)
/* Insert celldef into list of Defs waiting to be checked, unless */
/* it is already there. */
#if (0)
/* The switch to copying up DRC errors from non-interacting */
/* child cells means that the child cells must be processed */
/* first. So this routine changes from prepending the cell */
/* to the list to appending it. */
#if (0)
pback = &DRCPendingRoot;
p = DRCPendingRoot;
@ -230,8 +229,8 @@ DRCCheckThis (celldef, operation, area)
}
p->dpc_next = DRCPendingRoot;
DRCPendingRoot = p;
#endif
/* Append new cell to check to the pending list */
if (DRCPendingRoot == NULL)
{

View File

@ -449,6 +449,31 @@ drcCheckRectSize(starttile, arg, cptr)
}
}
/*
*-------------------------------------------------------------------------
*
* MaxRectsExclude ---
*
* Trivial callback function which detects if a type is found
* overlapping a Maxrects area.
*
* Results:
* Always return 1 to immediately halt the search.
*
* Side effects:
* None.
*
*-------------------------------------------------------------------------
*/
int
MaxRectsExclude(
Tile *tile,
ClientData clientdata)
{
return 1;
}
/*
*-------------------------------------------------------------------------
*
@ -563,10 +588,31 @@ drcCanonicalMaxwidth(starttile, dir, arg, cptr)
mrd->maxdist = edgelimit;
TTMaskCom2(&wrongtypes, &cptr->drcc_mask);
boundorig = *boundrect;
DBSrPaintArea(starttile, arg->dCD_celldef->cd_planes[cptr->drcc_plane],
DBSrPaintArea(starttile, arg->dCD_celldef->cd_planes[cptr->drcc_edgeplane],
&boundorig, &wrongtypes, FindMaxRects, mrd);
if (mrd->entries == 0)
return NULL;
else if (cptr->drcc_plane != cptr->drcc_edgeplane)
{
/* If the "exclude" option is used, then the maxrect rule will be
* ignored for any metal area partially or totally covered by any
* type in cptr->drcc_corner on plane cptr->drcc_plane (!=
* cptr->drcc_edgeplane).
*/
for (s = 0; s < mrd->entries; s++)
{
Rect *r = &(mrd->rlist[s]);
if (DBSrPaintArea((Tile *)NULL,
arg->dCD_celldef->cd_planes[cptr->drcc_plane],
r, &cptr->drcc_corner, MaxRectsExclude, NULL) != 0)
{
/* Take this area out of consideration */
r->r_xtop = r->r_xbot;
r->r_ytop = r->r_ybot;
}
}
return (MaxRectsData *)mrd;
}
else
return (MaxRectsData *)mrd;
}

View File

@ -277,20 +277,50 @@ drcPrintError (celldef, rect, cptr, scx)
{
HashEntry *h;
int i;
Rect *area, r;
Rect *area;
int drcsave = DRCErrorCount;
/* Forward declaration */
void drcWhyFunc(SearchContext *scx, ClientData cdarg);
ASSERT (cptr != (DRCCookie *) NULL, "drcPrintError");
area = &scx->scx_area;
if ((area != NULL) && (!GEO_OVERLAP(area, rect))) return;
i = DRCErrorList[cptr->drcc_tag];
if (i == 0)
TxPrintf("%s\n", drcSubstitute(cptr));
if (i >= 0)
if (cptr->drcc_tag == DRC_IN_SUBCELL_TAG)
{
DRCErrorCount += 1;
DRCErrorList[cptr->drcc_tag] = i + 1;
SearchContext newscx;
/* Recurse into subcells to find the error being flagged */
/* recursive call is drcWhyFunc, clientdata is FALSE */
newscx.scx_area = *rect;
newscx.scx_use = scx->scx_use;
newscx.scx_x = scx->scx_use->cu_xlo;
newscx.scx_y = scx->scx_use->cu_ylo;
newscx.scx_trans = scx->scx_trans;
DBTreeSrCells(&newscx, 0, drcWhyFunc, (ClientData)FALSE);
}
/* Hack to avoid printing "no errors found" when recursing on
* drcWhyFunc() above. In some cases like run-length rules,
* changing the search area can make the error disappear. If
* that happens, "See error definition in subcell" will be
* printed. The underlying error needs to be fixed, but this
* method provides the information the user needs to find the
* error.
*/
if (drcsave == DRCErrorCount)
{
i = DRCErrorList[cptr->drcc_tag];
if (i == 0)
TxPrintf("%s\n", drcSubstitute(cptr));
if (i >= 0)
{
DRCErrorCount += 1;
DRCErrorList[cptr->drcc_tag] = i + 1;
}
}
}
@ -309,24 +339,47 @@ drcListError (celldef, rect, cptr, scx)
HashEntry *h;
int i;
Rect *area;
int drcsave = DRCErrorCount;
/* Forward declaration */
void drcWhyFunc(SearchContext *scx, ClientData cdarg);
ASSERT (cptr != (DRCCookie *) NULL, "drcListError");
area = &scx->scx_area;
if ((area != NULL) && (!GEO_OVERLAP(area, rect))) return;
i = DRCErrorList[cptr->drcc_tag];
if (i == 0)
if (cptr->drcc_tag == DRC_IN_SUBCELL_TAG)
{
Tcl_Obj *lobj;
lobj = Tcl_GetObjResult(magicinterp);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(drcSubstitute(cptr), -1));
Tcl_SetObjResult(magicinterp, lobj);
SearchContext newscx;
/* Recurse into subcells to find the error being flagged */
/* recursive call is drcWhyFunc, clientdata is TRUE */
newscx.scx_area = *rect;
newscx.scx_use = scx->scx_use;
newscx.scx_x = scx->scx_use->cu_xlo;
newscx.scx_y = scx->scx_use->cu_ylo;
newscx.scx_trans = scx->scx_trans;
DBTreeSrCells(&newscx, 0, drcWhyFunc, (ClientData)TRUE);
}
if (i >= 0)
if (drcsave == DRCErrorCount)
{
DRCErrorCount += 1;
DRCErrorList[cptr->drcc_tag] = i + 1;
i = DRCErrorList[cptr->drcc_tag];
if (i == 0)
{
Tcl_Obj *lobj;
lobj = Tcl_GetObjResult(magicinterp);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(drcSubstitute(cptr), -1));
Tcl_SetObjResult(magicinterp, lobj);
}
if (i >= 0)
{
DRCErrorCount += 1;
DRCErrorList[cptr->drcc_tag] = i + 1;
}
}
}
@ -343,6 +396,10 @@ drcListallError (celldef, rect, cptr, scx)
Tcl_Obj *lobj, *pobj;
HashEntry *h;
Rect *area, r;
int drcsave = DRCErrorCount;
/* Forward declaration */
int drcWhyAllFunc(SearchContext *scx, ClientData cdarg);
ASSERT (cptr != (DRCCookie *) NULL, "drcListallError");
@ -350,21 +407,40 @@ drcListallError (celldef, rect, cptr, scx)
GeoTransRect(&scx->scx_trans, rect, &r);
area = &scx->scx_area;
if ((area != NULL) && (!GEO_OVERLAP(area, rect))) return;
DRCErrorCount += 1;
h = HashFind(&DRCErrorTable, drcSubstitute(cptr));
lobj = (Tcl_Obj *) HashGetValue(h);
if (lobj == NULL)
lobj = Tcl_NewListObj(0, NULL);
pobj = Tcl_NewListObj(0, NULL);
if (cptr->drcc_tag == DRC_IN_SUBCELL_TAG)
{
SearchContext newscx;
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_xbot));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_ybot));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_xtop));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_ytop));
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
/* Recurse into subcells to find the error being flagged */
/* recursive call is drcWhyAllFunc, clientdata is NULL */
newscx.scx_area = *rect;
newscx.scx_use = scx->scx_use;
newscx.scx_x = scx->scx_use->cu_xlo;
newscx.scx_y = scx->scx_use->cu_ylo;
newscx.scx_trans = scx->scx_trans;
HashSetValue(h, lobj);
DBTreeSrCells(&newscx, 0, drcWhyAllFunc, (ClientData)NULL);
}
if (drcsave == DRCErrorCount)
{
DRCErrorCount += 1;
h = HashFind(&DRCErrorTable, drcSubstitute(cptr));
lobj = (Tcl_Obj *) HashGetValue(h);
if (lobj == NULL)
lobj = Tcl_NewListObj(0, NULL);
pobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_xbot));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_ybot));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_xtop));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_ytop));
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
HashSetValue(h, lobj);
}
}
#else
@ -737,11 +813,12 @@ drcCheckFunc(scx, cdarg)
DBStdPaintTbl(TT_CHECKPAINT, PL_DRC_CHECK),
(PaintUndoInfo *) NULL);
DRCCheckThis(def, TT_CHECKPAINT, (Rect *) NULL);
/* Search children */
/* Search children and apply recursively */
(void) DBCellSrArea(scx, drcCheckFunc, (ClientData) NULL);
/* Then do self */
DRCCheckThis(def, TT_CHECKPAINT, (Rect *) NULL);
/* As a special performance hack, if the complete cell area is
* handled here, don't bother to look at any more array elements.
*/

View File

@ -734,9 +734,9 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
* square separately.
*/
x = (area->r_xbot/DRCStepSize) * DRCStepSize;
x = (area->r_xbot/DRCStepSize) * DRCStepSize - (DRCStepSize / 2);
if (x > area->r_xbot) x -= DRCStepSize;
y = (area->r_ybot/DRCStepSize) * DRCStepSize;
y = (area->r_ybot/DRCStepSize) * DRCStepSize - (DRCStepSize / 2);
if (y > area->r_ybot) y -= DRCStepSize;
for (square.r_xbot = x; square.r_xbot < area->r_xtop;
square.r_xbot += DRCStepSize)

View File

@ -1061,7 +1061,7 @@ DRCTechAddRule(sectionName, argc, argv)
"layers area horizon why"},
{"off_grid", 4, 4, drcOffGrid,
"layers pitch why"},
{"maxwidth", 4, 5, drcMaxwidth,
{"maxwidth", 4, 6, drcMaxwidth,
"layers maxwidth bends why"},
{"cifstyle", 2, 2, drcCifSetStyle,
"cif_style"},
@ -1582,7 +1582,7 @@ drcOffGrid(argc, argv)
* Process a maxwidth rule.
* This is of the form:
*
* maxwidth layers distance [bends] why
* maxwidth layers distance [bends] [exclude_layers] why
*
* This routine was updated 3/6/05 to match the "canonical" definition of
* a maxwidth region, which is any rectangle containing <layers> that is
@ -1591,6 +1591,11 @@ drcOffGrid(argc, argv)
* (see below) for backwards-compatibility. Otherwise ("bend_ok" or
* nothing), the new routine is used.
*
* exclude_layers is optional and indicates a type or types (which if more
* than one must all be on the same plane) that prevent "maxwidth" from
* being checked. A common use case is using "glass" (passivation cut) to
* exclude top metal on a pad from being checked for maximum metal width.
*
* maxwidth metal1 389 "metal1 width > 35um must be slotted"
* maxwidth pmc 4 bend_illegal "poly contact area must be no wider than 4"
* maxwidth trench 4 bend_ok "trench width must be exactly 4"
@ -1629,11 +1634,11 @@ drcMaxwidth(argc, argv)
int distance = atoi(argv[2]);
char *bends = argv[3];
int why;
TileTypeBitMask set, setC;
TileTypeBitMask set, setC, setE;
DRCCookie *dp, *dpnew;
TileType i, j;
PlaneMask pmask, ptest, pset;
int plane;
PlaneMask pmask, pmask2, ptest, pset;
int plane, plane2;
int bend;
ptest = DBTechNoisyNameMask(layers, &set);
@ -1667,8 +1672,34 @@ drcMaxwidth(argc, argv)
TechError("unknown bend option %s\n",bends);
return (0);
}
why = drcWhyCreate(argv[4]);
if (argc == 6)
why = drcWhyCreate(argv[5]);
else
why = drcWhyCreate(argv[4]);
}
if (argc == 6)
{
ptest = DBTechNoisyNameMask(argv[4], &setE);
pmask2 = CoincidentPlanes(&setE, ptest);
if (pmask2 == 0)
{
TechError("All layers for \"maxwidth\" exclude types must "
"be on same plane.\n");
return (0);
}
else
{
for (plane2 = PL_TECHDEPBASE; plane2 < DBNumPlanes; plane2++)
if (PlaneMaskHasPlane(pmask2, plane2))
break;
if (plane2 == plane)
TechError("Warning: Exclude types for \"maxwidth\" are on the "
"same plane and so cannot be checked.\n");
}
}
else
plane2 = -1;
for (i = 0; i < DBNumTypes; i++)
{
@ -1689,8 +1720,12 @@ drcMaxwidth(argc, argv)
/* find bucket preceding the new one we wish to insert */
dp = drcFindBucket(i, j, distance);
dpnew = (DRCCookie *) mallocMagic(sizeof (DRCCookie));
drcAssign(dpnew, distance, dp->drcc_next, &set, &set, why,
if (plane2 == -1)
drcAssign(dpnew, distance, dp->drcc_next, &set, &set, why,
distance, DRC_MAXWIDTH | bend, plane, plane);
else
drcAssign(dpnew, distance, dp->drcc_next, &set, &setE, why,
distance, DRC_MAXWIDTH | bend, plane2, plane);
dp->drcc_next = dpnew;
}

View File

@ -1116,6 +1116,7 @@ simdevVisit(
break;
case DEV_MSUBCKT:
case DEV_CSUBCKT:
case DEV_DSUBCKT:
case DEV_RSUBCKT:
case DEV_SUBCKT:
/* Use the 'x' type in .sim format. This is implemented in the */

View File

@ -2041,7 +2041,7 @@ topVisit(
* ----------------------------------------------------------------------------
*/
bool
void
spcWriteValue(
Dev *dev, /* Dev being output */
HierName *hierName) /* Hierarchical path down to this dev */

View File

@ -198,9 +198,10 @@ ResReadSim(simfile, fetproc, capproc, resproc, attrproc, mergeproc, subproc)
result = 1;
break;
}
if (fettype == -1)
if ((fettype != MINFINITY) && (fettype < 0))
{
TxError("Error in Reading device line of sim file.\n");
TxError("Error in Reading device line of sim file: ");
TxError("Ambiguous or unknown device.\n");
result = 1;
}
else if (fettype == DBNumTypes)

View File

@ -893,6 +893,7 @@ proc magic::gencell_change {instname gencell_type library parameters} {
}
resumeall
drc check ;# force a DRC update if DRC is on.
redraw
}
@ -1153,7 +1154,10 @@ proc magic::add_entry {pname ptext parameters} {
#----------------------------------------------------------
# Default entry callback, without any dependencies. Each
# parameter changed
# parameter changed causes an update to the dialog. Also
# add default callbacks on checkboxes and choice menus,
# using a null function which does not get executed, but
# the dialog gets updated afterward.
#----------------------------------------------------------
proc magic::add_check_callbacks {gencell_type library} {
@ -1166,6 +1170,12 @@ proc magic::add_check_callbacks {gencell_type library} {
bind $w <FocusOut> \
"magic::update_dialog {} $pname $gencell_type $library"
}
if {[regexp {\.params\.body\.area\.edits\.(.+)_sel} $w valid pname]} {
magic::add_dependency \{\} $gencell_type $library $pname
}
if {[regexp {\.params\.body\.area\.edits\.(.+)_chk} $w valid pname]} {
magic::add_dependency \{\} $gencell_type $library $pname
}
}
}

View File

@ -1225,36 +1225,29 @@ TxGetLine(
* ----------------------------------------------------------------------------
*/
#if defined(SYSV) || defined(CYGWIN)
void
txGetTermState(
struct termio *buf)
{
ioctl( fileno( stdin ), TCGETA, buf);
}
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
void
txGetTermState(
struct termios *buf)
{
(void) tcgetattr(fileno(stdin), buf);
}
#if defined(HAVE_TERMIOS_H)
struct termios *buf
#elif defined(HAVE_TERMIO_H)
struct termio *buf
#else
void
txGetTermState(
txTermState *buf)
txTermState *buf
#endif
)
{
#if defined(HAVE_TERMIOS_H) /* POSIX */
(void) tcgetattr(fileno(stdin), buf);
#elif defined(HAVE_TERMIO_H) /* SYSV */
ioctl( fileno( stdin ), TCGETA, buf);
#else /* fallback to sgtty-style */
ASSERT(TxStdinIsatty, "txGetTermState");
/* save the current terminal characteristics */
(void) ioctl(fileno(stdin), TIOCGETP, (char *) &(buf->tx_i_sgtty) );
(void) ioctl(fileno(stdin), TIOCGETC, (char *) &(buf->tx_i_tchars) );
#endif
}
#endif /* SYSV */
/*
@ -1273,24 +1266,24 @@ txGetTermState(
void
txSetTermState(
#if defined(SYSV) || defined(CYGWIN)
struct termio *buf
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
#if defined(HAVE_TERMIOS_H)
struct termios *buf
#elif defined(HAVE_TERMIO_H)
struct termio *buf
#else
txTermState *buf
#endif /* SYSV */
)
#endif
)
{
#if defined(SYSV) || defined(CYGWIN)
ioctl( fileno(stdin), TCSETAF, buf );
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
#if defined(HAVE_TERMIOS_H) /* POSIX */
(void) tcsetattr( fileno(stdin), TCSANOW, buf );
#else
#elif defined(HAVE_TERMIO_H) /* SYSV */
ioctl( fileno(stdin), TCSETAF, buf );
#else /* fallback to sgtty-style */
/* set the current terminal characteristics */
(void) ioctl(fileno(stdin), TIOCSETN, (char *) &(buf->tx_i_sgtty) );
(void) ioctl(fileno(stdin), TIOCSETC, (char *) &(buf->tx_i_tchars) );
#endif /* SYSV */
#endif
}
@ -1313,37 +1306,36 @@ txSetTermState(
void
txInitTermRec(
#if defined(SYSV) || defined(CYGWIN)
struct termio *buf
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
#if defined(HAVE_TERMIOS_H)
struct termios *buf
#elif defined(HAVE_TERMIO_H)
struct termio *buf
#else
txTermState *buf
#endif /* SYSV */
)
#endif
)
{
#if defined(SYSV) || defined(CYGWIN) || defined(__OpenBSD__) || defined(EMSCRIPTEN)
#if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H)
buf->c_lflag = ISIG; /* raw: no echo and no processing, allow signals */
buf->c_cc[ VMIN ] = 1;
buf->c_cc[ VTIME ] = 0;
#else
#else /* sgtty-style interface */
/* set things up for us, turn off echo, turn on cbreak, no EOF */
buf->tx_i_sgtty.sg_flags |= CBREAK;
buf->tx_i_sgtty.sg_flags &= ~ECHO;
buf->tx_i_tchars.t_eofc = -1;
#endif /* SYSV */
#endif
}
#if defined(SYSV) || defined(CYGWIN)
struct termio closeTermState;
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
#if defined(HAVE_TERMIOS_H)
struct termios closeTermState;
#elif defined(HAVE_TERMIO_H)
struct termio closeTermState;
#else
static txTermState closeTermState;
#endif /* SYSV */
#endif
static bool haveCloseState = FALSE;
@ -1366,21 +1358,18 @@ static bool haveCloseState = FALSE;
void
txSaveTerm(void)
{
#if defined(SYSV) || defined(CYGWIN)
ioctl( fileno( stdin ), TCGETA, &closeTermState);
txEraseChar = closeTermState.c_cc[VERASE];
txKillChar = closeTermState.c_cc[VKILL];
TxEOFChar = closeTermState.c_cc[VEOF];
TxInterruptChar = closeTermState.c_cc[VINTR];
haveCloseState = TRUE;
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
#if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H)
# if defined(HAVE_TERMIOS_H)
(void) tcgetattr( fileno( stdin ), &closeTermState);
# else /* HAVE_TERMIO_H */
ioctl( fileno( stdin ), TCGETA, &closeTermState);
# endif /* HAVE_TERMIOS_H || HAVE_TERMIO_H */
txEraseChar = closeTermState.c_cc[VERASE];
txKillChar = closeTermState.c_cc[VKILL];
TxEOFChar = closeTermState.c_cc[VEOF];
TxInterruptChar = closeTermState.c_cc[VINTR];
haveCloseState = TRUE;
#else
#else /* sgtty-style interface */
struct ltchars lt;
txGetTermState(&closeTermState);
(void) ioctl(fileno(stdin), TIOCGLTC, (char *) &lt);
@ -1393,7 +1382,7 @@ txSaveTerm(void)
TxEOFChar = closeTermState.tx_i_tchars.t_eofc;
TxInterruptChar = closeTermState.tx_i_tchars.t_intrc;
haveCloseState = TRUE;
#endif /* SYSV */
#endif
}
@ -1414,13 +1403,13 @@ txSaveTerm(void)
void
TxSetTerminal(void)
{
#if defined(SYSV) || defined(CYGWIN)
struct termio buf;
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
#if defined(HAVE_TERMIOS_H)
struct termios buf;
#elif defined(HAVE_TERMIO_H)
struct termio buf;
#else
txTermState buf;
#endif /* SYSV */
#endif
#ifdef MAGIC_WRAPPER
/* If using Tk console, don't mess with the terminal settings; */

View File

@ -21,44 +21,18 @@
#ifndef _MAGIC__UTILS__MAGSGTTY_H
#define _MAGIC__UTILS__MAGSGTTY_H
/* maybe this can be #ifndef HAVE_TERMIO_H */
#if !defined(SYSV) && !defined(CYGWIN)
# ifdef ALPHA
# undef MAX
# undef MIN
#if defined(HAVE_TERMIOS_H) /* POSIX */
# include <termios.h>
#elif defined(HAVE_TERMIO_H) /* SYSV */
# include <termio.h>
# include <sys/ioctl.h>
#else /* Fallback for older BSD/V7 systems */
# if defined(HAVE_SGTTY_H)
# include <sgtty.h>
# elif defined(HAVE_SYS_IOCTL_COMPAT_H)
# include <sys/ioctl_compat.h>
# endif
/* unclear what platform requires this OpenBSD/FreeBSD ? */
# ifndef COMPAT_43TTY
# define COMPAT_43TTY
# endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
# include <sys/ioctl.h>
#endif
#if defined(HAVE_TERMIOS_H)
#include <termios.h>
#elif defined(HAVE_SYS_IOCTL_COMPAT_H)
/* unclear which platform(s) require <sys/ioctl_compat.h> and the structure
* of this file is such that it will try to include it by default, better
* to invert the #if and only select this on the known platforms that need
* it so that <termios.h> goes by default, which exists on MacOSX, Linux, etc..
* many possible solutions to make this work by default:
* HAVE_SYS_IOCTL_COMPAT_H ? HAVE_TERMIOS_H ? !defined(linux) at top (MaxOSX is BSD type)
*/
#include <sys/ioctl_compat.h> /* replaced sgtty.h */
#elif defined(HAVE_SGTTY_H)
#include <sgtty.h> /* legacy - struct sgttyb{} defn */
#endif
#else
#if defined(HAVE_TERMIO_H)
#include <termio.h>
#endif
#endif /* !SYSV && !CYGWIN */
#endif /* _MAGIC__UTILS__MAGSGTTY_H */

View File

@ -1124,13 +1124,17 @@ windDoMacro(w, cmd, interactive)
/* next argument looks like a key, which would indicate */
/* an unregistered client as the first argument. A */
/* macro retrieved from an unregistered client returns */
/* nothing but does not generate an error. */
/* nothing but does not generate an error. This allows */
/* the default macro set to declare macros for, e.g., the */
/* wind3d client and fail quietly if magic was compiled */
/* without OpenGL support. */
if (MacroKey(cmd->tx_argv[argstart], &verbose) == 0)
if (MacroKey(cmd->tx_argv[argstart + 1], &verbose) != 0)
{
wc = 0;
argstart++;
return;
}
}
}
@ -1139,6 +1143,11 @@ windDoMacro(w, cmd, interactive)
if (cmd->tx_argc == argstart)
{
if (wc == (WindClient)0)
{
TxError("No such client.\n");
return;
}
h = HashLookOnly(&MacroClients, (char *)wc);
if (h == NULL)
return;
@ -1302,5 +1311,5 @@ windDoMacro(w, cmd, interactive)
return;
}
TxError("Usage: %s [macro_name [string] [help_text]]\n", cmd->tx_argv[0]);
TxError("Usage: %s [client] [macro_name [string] [help_text]]\n", cmd->tx_argv[0]);
}