Implemented the new feature discussed in the github discussion #492.

This features allows two new instructions in the tech file "drc"
section:  "exception <name>|none" and "exemption <name>|none".  The
purpose of these rules is to allow DRC rule exceptions for certain
areas which are marked, usually by a GDS identifier layer.  Because
GDS identifier layers can be cast as "mask-hint" properties, the
DRC rule exceptions make use of that (recent) feature.  So rules
can be specified as "exceptions" (rule applies for layout inside
the marked area) or "exemptions" (rule is ignored for layout inside
the marked area).  Rules following the statements will have the
exception or exemption applied until another exception or exemption
statement is given.  Either "exception none" or "exemption none" will
stop applying any rule exception or exemption.  This is especially
useful for applications like SRAM where there may be a number of
rule exceptions on different layers.  The previous way to handle
that was to create new layers in magic for any layer that needed a
rule exception.  That mainly resulted in very messy tech files,
and a large number of defined layers.  This implementation is both
simpler and cleaner.
This commit is contained in:
R. Timothy Edwards 2026-03-08 20:12:58 -04:00
parent 037daf1121
commit 52f4c10da8
7 changed files with 303 additions and 47 deletions

View File

@ -1 +1 @@
8.3.615
8.3.616

View File

@ -358,6 +358,7 @@ struct propUseDefStruct {
CellDef *puds_source;
CellDef *puds_dest;
Transform *puds_trans; /* Transform from source use to dest */
Rect *puds_area; /* Clip area in source coordinates */
};
/*
@ -387,11 +388,12 @@ dbCopyMaskHintsFunc(key, proprec, puds)
{
CellDef *dest = puds->puds_dest;
Transform *trans = puds->puds_trans;
Rect *clip = puds->puds_area;
PropertyRecord *parentproprec, *newproprec;
char *parentprop, *newvalue, *vptr;
Rect r, rnew;
bool propfound;
int i;
int i, j;
if (!strncmp(key, "MASKHINTS_", 10))
{
@ -407,29 +409,33 @@ dbCopyMaskHintsFunc(key, proprec, puds)
(proprec->prop_len + parentproprec->prop_len - 2) *
sizeof(int));
newproprec->prop_type = PROPERTY_TYPE_DIMENSION;
newproprec->prop_len = proprec->prop_len + parentproprec->prop_len;
newproprec->prop_len = parentproprec->prop_len;
}
else
{
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(proprec->prop_len - 2) * sizeof(int));
newproprec->prop_type = PROPERTY_TYPE_DIMENSION;
newproprec->prop_len = proprec->prop_len;
newproprec->prop_len = 0;
}
for (i = 0; i < proprec->prop_len; i += 4)
for (i = 0, j = 0; i < proprec->prop_len; i += 4)
{
r.r_xbot = proprec->prop_value.prop_integer[i];
r.r_ybot = proprec->prop_value.prop_integer[i + 1];
r.r_xtop = proprec->prop_value.prop_integer[i + 2];
r.r_ytop = proprec->prop_value.prop_integer[i + 3];
GeoTransRect(trans, &r, &rnew);
newproprec->prop_value.prop_integer[i] = rnew.r_xbot;
newproprec->prop_value.prop_integer[i + 1] = rnew.r_ybot;
newproprec->prop_value.prop_integer[i + 2] = rnew.r_xtop;
newproprec->prop_value.prop_integer[i + 3] = rnew.r_ytop;
GeoClip(&r, clip);
if (!GEO_RECTNULL(&r))
{
GeoTransRect(trans, &r, &rnew);
newproprec->prop_value.prop_integer[j] = rnew.r_xbot;
newproprec->prop_value.prop_integer[j + 1] = rnew.r_ybot;
newproprec->prop_value.prop_integer[j + 2] = rnew.r_xtop;
newproprec->prop_value.prop_integer[j + 3] = rnew.r_ytop;
newproprec->prop_len += 4;
j += 4;
}
}
if (propfound)
@ -474,6 +480,7 @@ DBCellCopyMaskHints(child, parent, transform)
puds.puds_source = child->cu_def;
puds.puds_dest = parent;
puds.puds_trans = transform;
puds.puds_area = (Rect *)&TiPlaneRect;
DBPropEnum(child->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
}
@ -507,6 +514,7 @@ dbFlatCopyMaskHintsFunc(scx, def)
puds.puds_source = scx->scx_use->cu_def;
puds.puds_dest = def;
puds.puds_trans = &scx->scx_trans;
puds.puds_area = &scx->scx_area;
DBPropEnum(use->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);

View File

@ -45,7 +45,7 @@ extern int drcArrayYankFunc(), drcArrayOverlapFunc();
static DRCCookie drcArrayCookie = {
0, 0, 0, 0,
{ {0} }, { {0} },
0, 0, 0,
0, DRC_EXCEPTION_NONE, 0, 0,
DRC_ARRAY_OVERLAP_TAG,
(DRCCookie *) NULL
};

View File

@ -48,7 +48,7 @@ int dbDRCDebug = 0;
static DRCCookie drcOverlapCookie = {
0, 0, 0, 0,
{ {0} }, { {0} },
0, 0, 0,
0, DRC_EXCEPTION_NONE, 0, 0,
DRC_OVERLAP_TAG,
(DRCCookie *) NULL
};
@ -727,6 +727,59 @@ drcTile (tile, dinfo, arg)
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
cptr = cptr->drcc_next)
{
/* Handle rule exceptions and exemptions */
if (cptr->drcc_exception != (char)DRC_EXCEPTION_NONE)
{
PropertyRecord *proprec;
bool propfound, isinside;
char *name;
char idx = cptr->drcc_exception;
if (idx < 0) idx = -idx - 1;
name = DRCCurStyle->DRCExceptionList[idx];
/* Is there any exception area defined? */
proprec = DBPropGet(arg->dCD_celldef, name, &propfound);
/* Quickest case: Rule is an exception but there are no
* exception areas.
*/
if ((!propfound) && (cptr->drcc_exception >= 0))
continue;
/* If an exception area exists, is the error edge inside? */
if (propfound)
{
int i;
Rect r, redge;
redge.r_xbot = redge.r_xtop = edgeX;
redge.r_ybot = edgeBot;
redge.r_ytop = edgeTop;
isinside = FALSE;
for (i = 0; i < proprec->prop_len; i += 4)
{
if ((i + 4) > proprec->prop_len) break;
r.r_xbot = proprec->prop_value.prop_integer[i];
r.r_ybot = proprec->prop_value.prop_integer[i + 1];
r.r_xtop = proprec->prop_value.prop_integer[i + 2];
r.r_ytop = proprec->prop_value.prop_integer[i + 3];
if (GEO_OVERLAP(&redge, &r))
{
isinside = TRUE;
break;
}
}
}
/* Exemption rules are ignored if the edge is inside
* an exception area. Exception rules are ignored if
* the edge is outside an exception area.
*/
if (isinside && (cptr->drcc_exception < 0)) continue;
if (!isinside && (cptr->drcc_exception >= 0)) continue;
}
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
/* the code above for non-Manhattan shapes and do not */
/* need to be processed again. */
@ -1136,6 +1189,59 @@ drcTile (tile, dinfo, arg)
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
cptr = cptr->drcc_next)
{
/* Handle rule exceptions and exemptions */
if (cptr->drcc_exception != (char)DRC_EXCEPTION_NONE)
{
PropertyRecord *proprec;
bool propfound, isinside;
char *name;
char idx = cptr->drcc_exception;
if (idx < 0) idx = -idx - 1;
name = DRCCurStyle->DRCExceptionList[idx];
/* Is there any exception area defined? */
proprec = DBPropGet(arg->dCD_celldef, name, &propfound);
/* Quickest case: Rule is an exception but there are no
* exception areas.
*/
if ((!propfound) && (cptr->drcc_exception >= 0))
continue;
/* If an exception area exists, is the error edge inside? */
if (propfound)
{
int i;
Rect r, redge;
redge.r_ybot = redge.r_ytop = edgeY;
redge.r_xbot = edgeLeft;
redge.r_xtop = edgeRight;
isinside = FALSE;
for (i = 0; i < proprec->prop_len; i += 4)
{
if ((i + 4) > proprec->prop_len) break;
r.r_xbot = proprec->prop_value.prop_integer[i];
r.r_ybot = proprec->prop_value.prop_integer[i + 1];
r.r_xtop = proprec->prop_value.prop_integer[i + 2];
r.r_ytop = proprec->prop_value.prop_integer[i + 3];
if (GEO_OVERLAP(&redge, &r))
{
isinside = TRUE;
break;
}
}
}
/* Exemption rules are ignored if the edge is inside
* an exception area. Exception rules are ignored if
* the edge is outside an exception area.
*/
if (isinside && (cptr->drcc_exception < 0)) continue;
if (!isinside && (cptr->drcc_exception >= 0)) continue;
}
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
/* the code above for non-Manhattan shapes and do not */
/* need to be processed again. */

View File

@ -52,7 +52,7 @@ static ClientData drcSubClientData; /* To be passed to error function. */
static DRCCookie drcSubcellCookie = {
0, 0, 0, 0,
{ {0} }, { {0} },
0, 0, 0,
0, DRC_EXCEPTION_NONE, 0, 0,
DRC_SUBCELL_OVERLAP_TAG,
(DRCCookie *) NULL
};
@ -65,7 +65,7 @@ static DRCCookie drcSubcellCookie = {
static DRCCookie drcInSubCookie = {
0, 0, 0, 0,
{ {0} }, { {0} },
0, 0, 0,
0, DRC_EXCEPTION_NONE, 0, 0,
DRC_IN_SUBCELL_TAG,
(DRCCookie *) NULL
};
@ -79,7 +79,7 @@ static DRCCookie drcInSubCookie = {
static DRCCookie drcOffGridCookie = {
0, 0, 0, 0,
{ {0} }, { {0} },
0, 0, 0,
0, DRC_EXCEPTION_NONE, 0, 0,
DRC_OFFGRID_TAG,
(DRCCookie *) NULL
};

View File

@ -72,6 +72,12 @@ static int drcRulesOptimized = 0;
static int DRCtag = 0;
/* Keep track of what rule exemption or exception is in effect
* while reading the DRC tech file section.
*/
static char drcCurException = (char)DRC_EXCEPTION_NONE;
/*
* Forward declarations.
*/
@ -79,6 +85,7 @@ int drcWidth(), drcSpacing(), drcEdge(), drcNoOverlap();
int drcExactOverlap(), drcExtend();
int drcSurround(), drcRectOnly(), drcOverhang();
int drcStepSize(), drcOption(), drcOffGrid();
int drcException(), drcExemption();
int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles();
int drcCifSetStyle(), drcCifWidth(), drcCifSpacing();
int drcCifMaxwidth(), drcCifArea();
@ -301,6 +308,12 @@ drcTechFreeStyle()
/* Clear the Why string list */
freeMagic(DRCCurStyle->DRCWhyList);
/* Clear the exception list */
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
freeMagic(DRCCurStyle->DRCExceptionList[i]);
if (DRCCurStyle->DRCExceptionList != (char **)NULL)
freeMagic(DRCCurStyle->DRCExceptionList);
freeMagic(DRCCurStyle);
DRCCurStyle = NULL;
}
@ -384,6 +397,60 @@ drcWhyCreate(whystring)
return DRCCurStyle->DRCWhySize;
}
/*
* ----------------------------------------------------------------------------
* drcExceptionCreate --
*
* Create an entry for a DRC rule exception/exemption type, if it does
* not already exist.
*
* Results:
* The index of the exception (which is a signed character).
*
* Side effects:
* Adds to the DRCExceptionList if "name" has not been used before.
* Calls StrDup() and increments DRCExceptionSize.
*
* ----------------------------------------------------------------------------
*/
char
drcExceptionCreate(name)
char *name;
{
int i;
char **newlist;
/* NOTE: DRCExceptionList has "MASKHINTS_" prepended to the names */
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
if (!strcmp(name, DRCCurStyle->DRCExceptionList[i] + 10))
return (char)i;
if (i > 127)
{
/* I would be shocked if this code ever got executed. */
TxError("Error: Too many rule exceptions! Limit is 127.\n");
return (char)DRC_EXCEPTION_NONE;
}
/* Create a new list that is one entry longer than the old list.
* This is not elegant but there will never be more than a handful
* of exceptions in a rule deck.
*/
newlist = (char **)mallocMagic((i + 1) * sizeof(char *));
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
newlist[i] = DRCCurStyle->DRCExceptionList[i];
/* The rule deck does not have the "MASKHINTS_" prefix on the name */
newlist[i] = (char *)mallocMagic(strlen(name) + 11);
sprintf(newlist[i], "MASKHINTS_%s", name);
DRCCurStyle->DRCExceptionSize++;
if (DRCCurStyle->DRCExceptionList != (char **)NULL)
freeMagic(DRCCurStyle->DRCExceptionList);
DRCCurStyle->DRCExceptionList = newlist;
return (char)i;
}
/*
* ----------------------------------------------------------------------------
*
@ -571,6 +638,8 @@ DRCTechStyleInit()
DRCCurStyle->DRCStepSize = 0;
DRCCurStyle->DRCFlags = (char)0;
DRCCurStyle->DRCWhySize = 0;
DRCCurStyle->DRCExceptionList = (char **)NULL;
DRCCurStyle->DRCExceptionSize = 0;
HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS);
@ -663,6 +732,7 @@ DRCTechStyleInit()
}
drcCifInit();
drcCurException = (char)DRC_EXCEPTION_NONE;
}
/*
@ -955,6 +1025,7 @@ drcCifAssign(cookie, dist, next, mask, corner, tag, cdist, flags, planeto, plane
(cookie)->drcc_plane = planeto;
(cookie)->drcc_mod = 0;
(cookie)->drcc_cmod = 0;
(cookie)->drcc_exception = drcCurException;
}
// This is like drcCifAssign, but checks for bad plane numbers in planeto and
@ -1031,50 +1102,37 @@ DRCTechAddRule(sectionName, argc, argv)
int (*rk_proc)(); /* Procedure implementing this keyword */
const char *rk_err; /* Error message */
} ruleKeys[] = {
{"angles", 4, 4, drcAngles,
"layers 45|90 why"},
{"angles", 4, 4, drcAngles, "layers 45|90 why"},
{"edge", 8, 10, drcEdge,
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
{"edge4way", 8, 10, drcEdge,
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
{"exact_overlap", 2, 2, drcExactOverlap,
"layers"},
{"exact_overlap", 2, 2, drcExactOverlap, "layers"},
{"exception", 2, 2, drcException, "name"},
{"exemption", 2, 2, drcExemption, "name"},
{"extend", 5, 6, drcExtend,
"layers1 layers2 distance [option] why"},
{"no_overlap", 3, 3, drcNoOverlap,
"layers1 layers2"},
{"option", 2, 2, drcOption,
"option_name option_value"},
{"overhang", 5, 5, drcOverhang,
"layers1 layers2 distance why"},
{"rect_only", 3, 3, drcRectOnly,
"layers why"},
{"no_overlap", 3, 3, drcNoOverlap, "layers1 layers2"},
{"option", 2, 2, drcOption, "option_name option_value"},
{"overhang", 5, 5, drcOverhang, "layers1 layers2 distance why"},
{"rect_only", 3, 3, drcRectOnly, "layers why"},
{"spacing", 6, 7, drcSpacing,
"layers1 layers2 separation [layers3] adjacency why"},
{"stepsize", 2, 2, drcStepSize,
"step_size"},
{"stepsize", 2, 2, drcStepSize, "step_size"},
{"surround", 6, 7, drcSurround,
"layers1 layers2 distance presence why"},
{"width", 4, 5, drcWidth,
"layers width why"},
{"width", 4, 5, drcWidth, "layers width why"},
{"widespacing", 7, 8, drcSpacing,
"layers1 width layers2 separation adjacency why"},
{"area", 5, 5, drcArea,
"layers area horizon why"},
{"off_grid", 4, 4, drcOffGrid,
"layers pitch why"},
{"maxwidth", 4, 6, drcMaxwidth,
"layers maxwidth bends why"},
{"cifstyle", 2, 2, drcCifSetStyle,
"cif_style"},
{"cifwidth", 4, 4, drcCifWidth,
"layers width why"},
{"area", 5, 5, drcArea, "layers area horizon why"},
{"off_grid", 4, 4, drcOffGrid, "layers pitch why"},
{"maxwidth", 4, 6, drcMaxwidth, "layers maxwidth bends why"},
{"cifstyle", 2, 2, drcCifSetStyle, "cif_style"},
{"cifwidth", 4, 4, drcCifWidth, "layers width why"},
{"cifspacing", 6, 6, drcCifSpacing,
"layers1 layers2 separation adjacency why"},
{"cifarea", 5, 5, drcCifArea,
"layers area horizon why"},
{"cifmaxwidth", 5, 5, drcCifMaxwidth,
"layers maxwidth bends why"},
{"cifarea", 5, 5, drcCifArea, "layers area horizon why"},
{"cifmaxwidth", 5, 5, drcCifMaxwidth, "layers maxwidth bends why"},
{"rectangle", 5, 5, drcRectangle,
"layers maxwidth [even|odd|any] why"},
{0}
@ -3634,6 +3692,83 @@ drcRectangle(argc, argv)
return maxwidth;
}
/*
* ----------------------------------------------------------------------------
*
* drcException, drcExemption --
*
* Process a DRC exception declaration
* This is of the form:
*
* exception exception_name|none
* or
* exemption exemption_name|none
*
* e.g,
*
* exception SRAM
* exemption SRAM
*
* The exception_name or exemption_name is the suffix part of a MASKHINTS_*
* property name; e.g., the name SRAM corresponds to a property called
* MASKHINTS_SRAM. This declaration is followed by a block of DRC rules
* that are subject to the exception or the exemption. An exception is the
* opposite of an exemption: If a rule is excepted, then the rule applies
* within areas delineated by bounding boxes defined by the
* MASKHINTS_<exception_name> property. If a rule is exempted, then the
* rule applies only outside of areas delineated by bounding boxes defined
* by the MASKHINTS_<exemption_name> property. The block of rules subject
* to the exemption or exception ends with another exception or exemption
* declaration. If the following rules are not to be excepted or exempted
* at all, then use "exception none" or "exemption none".
*
* Results:
* Returns 0.
*
* Side effects:
* Updates drcCurException. drcCurException is zero or positive for
* exceptions and negative for exemptions. The index can be
* recovered from a negative value by negating it and subtracting 1.
*
* ----------------------------------------------------------------------------
*/
int
drcException(argc, argv)
int argc;
char *argv[];
{
int i;
if (DRCCurStyle == NULL) return 0;
/* Assume that argc must be 2 because the parser insists upon it */
if (!strcmp(argv[1], "none"))
drcCurException = (char)DRC_EXCEPTION_NONE;
else
drcCurException = drcExceptionCreate(argv[1]);
return (0);
}
int
drcExemption(argc, argv)
int argc;
char *argv[];
{
int i;
if (DRCCurStyle == NULL) return 0;
/* Assume that argc must be 2 because the parser insists upon it */
if (!strcmp(argv[1], "none"))
drcCurException = (char)DRC_EXCEPTION_NONE;
else
drcCurException = -(drcExceptionCreate(argv[1])) - 1;
return (0);
}
/*
* ----------------------------------------------------------------------------
*
@ -4119,6 +4254,7 @@ drcTechFinalStyle(style)
if (dp->drcc_dist > next->drcc_dist) continue;
if (dp->drcc_cdist > next->drcc_cdist) continue;
if (dp->drcc_plane != next->drcc_plane) continue;
if (dp->drcc_exception != next->drcc_exception) continue;
if (dp->drcc_flags & DRC_REVERSE)
{
if (!(next->drcc_flags & DRC_REVERSE)) continue;

View File

@ -36,6 +36,7 @@ typedef struct drccookie
TileTypeBitMask drcc_mask; /* Legal types on RHS */
TileTypeBitMask drcc_corner; /* Types that trigger corner check */
unsigned short drcc_flags; /* Miscellaneous flags, see below. */
char drcc_exception; /* Index to list of exceptions */
int drcc_edgeplane; /* Plane of edge */
int drcc_plane; /* Index of plane on which to check
* legal types. */
@ -91,6 +92,9 @@ typedef struct drccookie
#define DRC_UNPROCESSED CLIENTDEFAULT
#define DRC_PROCESSED 1
/* drcc_exception defaults to -128 (0x80) meaning no exceptions/exemptions */
#define DRC_EXCEPTION_NONE (char)0x80
/*
* Background DRC (DRC Idle proc) for Tcl-based Magic
*/
@ -177,6 +181,8 @@ typedef struct drcstyle
unsigned short DRCFlags; /* Option flags */
char **DRCWhyList; /* Indexed list of "why" text strings */
int DRCWhySize; /* Length of DRCWhyList */
char **DRCExceptionList; /* Indexed list of DRC exceptions */
int DRCExceptionSize; /* Length of DRCExceptionList */
PaintResultType DRCPaintTable[NP][NT][NT];
} DRCStyle;