|
|
|
|
@ -43,7 +43,6 @@ extern char *maskToPrint();
|
|
|
|
|
PlowRule *plowSpacingRulesTbl[TT_MAXTYPES][TT_MAXTYPES];
|
|
|
|
|
PlowRule *plowWidthRulesTbl[TT_MAXTYPES][TT_MAXTYPES];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Special type masks */
|
|
|
|
|
|
|
|
|
|
TileTypeBitMask PlowContactTypes; /* All types that are contacts */
|
|
|
|
|
@ -68,9 +67,597 @@ TileTypeBitMask PlowFixedTypes; /* Fixed-width types (e.g, fets).
|
|
|
|
|
int plowMaxDist[TT_MAXTYPES];
|
|
|
|
|
|
|
|
|
|
/* Forward declarations */
|
|
|
|
|
extern void plowEdgeRule(), plowWidthRule(), plowSpacingRule();
|
|
|
|
|
extern int plowEdgeRule(), plowWidthRule(), plowSpacingRule();
|
|
|
|
|
PlowRule *plowTechOptimizeRule();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlowInit() --
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* One-time-only initialization (clearing) of plow tables on startup.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlowInit()
|
|
|
|
|
{
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < TT_MAXTYPES; i++)
|
|
|
|
|
{
|
|
|
|
|
for (j = 0; j < TT_MAXTYPES; j++)
|
|
|
|
|
{
|
|
|
|
|
plowWidthRulesTbl[i][j] = (PlowRule *)NULL;
|
|
|
|
|
plowSpacingRulesTbl[i][j] = (PlowRule *)NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlowDRCInit --
|
|
|
|
|
*
|
|
|
|
|
* Initialization before processing the "drc" section for plowing.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Clears the rules table.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlowDRCInit()
|
|
|
|
|
{
|
|
|
|
|
register int i, j;
|
|
|
|
|
register PlowRule *pr;
|
|
|
|
|
|
|
|
|
|
/* Remove all old rules from the plowing rules table */
|
|
|
|
|
for (i = 0; i < DBNumTypes; i++)
|
|
|
|
|
{
|
|
|
|
|
for (j = 0; j < DBNumTypes; j++)
|
|
|
|
|
{
|
|
|
|
|
for (pr = plowWidthRulesTbl[i][j]; pr; pr = pr->pr_next)
|
|
|
|
|
freeMagic((char *)pr);
|
|
|
|
|
|
|
|
|
|
for (pr = plowSpacingRulesTbl[i][j]; pr; pr = pr->pr_next)
|
|
|
|
|
freeMagic((char *)pr);
|
|
|
|
|
|
|
|
|
|
plowWidthRulesTbl[i][j] = NULL;
|
|
|
|
|
plowSpacingRulesTbl[i][j] = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlowDRCLine --
|
|
|
|
|
*
|
|
|
|
|
* Process a single line from the "drc" section.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE always.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Adds rules to our plowing rule tables.
|
|
|
|
|
*
|
|
|
|
|
* Organization:
|
|
|
|
|
* We select a procedure based on the first keyword (argv[0])
|
|
|
|
|
* and call it to do the work of implementing the rule. Each
|
|
|
|
|
* such procedure is of the following form:
|
|
|
|
|
*
|
|
|
|
|
* void
|
|
|
|
|
* proc(argc, argv)
|
|
|
|
|
* int argc;
|
|
|
|
|
* char *argv[];
|
|
|
|
|
* {
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*ARGSUSED*/
|
|
|
|
|
bool
|
|
|
|
|
PlowDRCLine(sectionName, argc, argv)
|
|
|
|
|
char *sectionName; /* Unused */
|
|
|
|
|
int argc;
|
|
|
|
|
char *argv[];
|
|
|
|
|
{
|
|
|
|
|
int which;
|
|
|
|
|
static struct
|
|
|
|
|
{
|
|
|
|
|
char *rk_keyword; /* Initial keyword */
|
|
|
|
|
int rk_minargs; /* Min # arguments */
|
|
|
|
|
int rk_maxargs; /* Max # arguments */
|
|
|
|
|
int (*rk_proc)(); /* Procedure implementing this keyword */
|
|
|
|
|
} ruleKeys[] = {
|
|
|
|
|
"edge", 8, 9, plowEdgeRule,
|
|
|
|
|
"edge4way", 8, 9, plowEdgeRule,
|
|
|
|
|
"spacing", 6, 6, plowSpacingRule,
|
|
|
|
|
"width", 4, 4, plowWidthRule,
|
|
|
|
|
0
|
|
|
|
|
}, *rp;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Leave the job of printing error messages to the DRC tech file reader.
|
|
|
|
|
* We only process a few of the various design-rule types here anyway.
|
|
|
|
|
*/
|
|
|
|
|
which = LookupStruct(argv[0], (LookupTable *) ruleKeys, sizeof ruleKeys[0]);
|
|
|
|
|
if (which >= 0)
|
|
|
|
|
{
|
|
|
|
|
rp = &ruleKeys[which];
|
|
|
|
|
if (argc >= rp->rk_minargs && argc <= rp->rk_maxargs)
|
|
|
|
|
(*rp->rk_proc)(argc, argv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowWidthRule --
|
|
|
|
|
*
|
|
|
|
|
* Process a width rule.
|
|
|
|
|
* This is of the form:
|
|
|
|
|
*
|
|
|
|
|
* width layers distance why
|
|
|
|
|
* e.g, width poly,pmc 2 "poly width must be at least 2"
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Updates the plowing width rule table.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plowWidthRule(argc, argv)
|
|
|
|
|
int argc;
|
|
|
|
|
char *argv[];
|
|
|
|
|
{
|
|
|
|
|
char *layers = argv[1];
|
|
|
|
|
int distance = atoi(argv[2]);
|
|
|
|
|
TileTypeBitMask set, setC, tmp1;
|
|
|
|
|
PlaneMask ptest, pmask;
|
|
|
|
|
register PlowRule *pr;
|
|
|
|
|
register TileType i, j;
|
|
|
|
|
int pNum;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* All layers in a width rule must be on the same plane;
|
|
|
|
|
* CoincidentPlanes() below maps contacts to their proper images.
|
|
|
|
|
*/
|
|
|
|
|
ptest = DBTechNoisyNameMask(layers, &set);
|
|
|
|
|
pmask = CoincidentPlanes(&set, ptest);
|
|
|
|
|
|
|
|
|
|
if (pmask == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
pNum = LowestMaskBit(pmask);
|
|
|
|
|
|
|
|
|
|
set = tmp1;
|
|
|
|
|
TTMaskCom2(&setC, &set);
|
|
|
|
|
TTMaskAndMask(&setC, &DBPlaneTypes[pNum]);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Must have types in 'set' for at least 'distance' to the right of
|
|
|
|
|
* any edge between a type in '~set' and a type in 'set'.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < DBNumTypes; i++)
|
|
|
|
|
{
|
|
|
|
|
if (TTMaskHasType(&setC, i))
|
|
|
|
|
{
|
|
|
|
|
for (j = 0; j < DBNumTypes; j++)
|
|
|
|
|
{
|
|
|
|
|
if (DBTypesOnSamePlane(i, j) && TTMaskHasType(&set, j))
|
|
|
|
|
{
|
|
|
|
|
pr = (PlowRule *)mallocMagic(sizeof(PlowRule));
|
|
|
|
|
pr->pr_dist = distance;
|
|
|
|
|
pr->pr_mod = 0;
|
|
|
|
|
pr->pr_ltypes = setC;
|
|
|
|
|
pr->pr_oktypes = set;
|
|
|
|
|
pr->pr_pNum = pNum;
|
|
|
|
|
pr->pr_flags = PR_WIDTH;
|
|
|
|
|
pr->pr_next = plowWidthRulesTbl[i][j];
|
|
|
|
|
plowWidthRulesTbl[i][j] = pr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowSpacingRule --
|
|
|
|
|
*
|
|
|
|
|
* Process a spacing rule.
|
|
|
|
|
* This is of the form:
|
|
|
|
|
*
|
|
|
|
|
* spacing layers1 layers2 distance adjacency why
|
|
|
|
|
* e.g, spacing metal,pmc/m,dmc/m metal,pmc/m,dmc/m 4 touching_ok \
|
|
|
|
|
* "metal spacing must be at least 4"
|
|
|
|
|
*
|
|
|
|
|
* Adjacency may be either "touching_ok" or "touching_illegal". In
|
|
|
|
|
* the former case, no violation occurs when types in layers1 are
|
|
|
|
|
* immediately adjacent to types in layers2. In the second case,
|
|
|
|
|
* such adjacency causes a violation.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Updates the plowing spacing rules.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plowSpacingRule(argc, argv)
|
|
|
|
|
int argc;
|
|
|
|
|
char *argv[];
|
|
|
|
|
{
|
|
|
|
|
char *layers1 = argv[1], *layers2 = argv[2];
|
|
|
|
|
int distance = atoi(argv[3]);
|
|
|
|
|
char *adjacency = argv[4];
|
|
|
|
|
TileTypeBitMask set1, set2, tmp1, tmp2, setR, setRreverse;
|
|
|
|
|
int pNum;
|
|
|
|
|
PlaneMask ptest, planes1, planes2;
|
|
|
|
|
register PlowRule *pr;
|
|
|
|
|
register TileType i, j;
|
|
|
|
|
|
|
|
|
|
ptest = DBTechNoisyNameMask(layers1, &set1);
|
|
|
|
|
planes1 = CoincidentPlanes(&set1, ptest);
|
|
|
|
|
ptest = DBTechNoisyNameMask(layers2, &set2);
|
|
|
|
|
planes2 = CoincidentPlanes(&set2, ptest);
|
|
|
|
|
|
|
|
|
|
if (planes1 == 0 || planes2 == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (strcmp (adjacency, "touching_ok") == 0)
|
|
|
|
|
{
|
|
|
|
|
/* If touching is OK, everything must fall in the same plane. */
|
|
|
|
|
if (planes1 != planes2)
|
|
|
|
|
return 0;
|
|
|
|
|
pNum = LowestMaskBit(planes1);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Must not have 'set2' for 'distance' to the right of an edge between
|
|
|
|
|
* 'set1' and the types in neither 'set1' nor 'set2' (ie, 'setR').
|
|
|
|
|
*/
|
|
|
|
|
set1 = tmp1;
|
|
|
|
|
set2 = tmp2;
|
|
|
|
|
planes1 = planes2 = PlaneNumToMaskBit(pNum);
|
|
|
|
|
TTMaskCom(&tmp1);
|
|
|
|
|
TTMaskCom(&tmp2);
|
|
|
|
|
TTMaskAndMask(&tmp1, &tmp2);
|
|
|
|
|
TTMaskAndMask(&tmp2, &DBPlaneTypes[pNum]);
|
|
|
|
|
setRreverse = setR = tmp1;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp (adjacency, "touching_illegal") == 0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Must not have 'set2' for 'distance' to the right of an edge between
|
|
|
|
|
* 'set1' and the types not in 'set1' (ie, 'setR').
|
|
|
|
|
*/
|
|
|
|
|
TTMaskCom2(&setR, &set1);
|
|
|
|
|
TTMaskCom2(&setRreverse, &set2);
|
|
|
|
|
}
|
|
|
|
|
else return 0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < DBNumTypes; i++)
|
|
|
|
|
{
|
|
|
|
|
for (j = 0; j < DBNumTypes; j++)
|
|
|
|
|
{
|
|
|
|
|
if (i == j || !DBTypesOnSamePlane(i, j)) continue;
|
|
|
|
|
|
|
|
|
|
/* LHS is an element of set1 and RHS is an element of setR */
|
|
|
|
|
if (TTMaskHasType(&set1, i) && TTMaskHasType(&setR, j))
|
|
|
|
|
{
|
|
|
|
|
/* May have to insert several buckets on different planes */
|
|
|
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
|
|
|
{
|
|
|
|
|
if (!PlaneMaskHasPlane(planes2, pNum))
|
|
|
|
|
continue;
|
|
|
|
|
pr = (PlowRule *)mallocMagic(sizeof(PlowRule));
|
|
|
|
|
TTMaskClearMask3(&tmp1, &DBPlaneTypes[pNum], &set2);
|
|
|
|
|
TTMaskCom2(&tmp2, &setRreverse);
|
|
|
|
|
TTMaskAndMask3(&pr->pr_ltypes, &DBPlaneTypes[pNum], &tmp2);
|
|
|
|
|
pr->pr_oktypes = tmp1;
|
|
|
|
|
pr->pr_dist = distance;
|
|
|
|
|
pr->pr_mod = 0;
|
|
|
|
|
pr->pr_pNum = pNum;
|
|
|
|
|
pr->pr_flags = 0;
|
|
|
|
|
pr->pr_next = plowSpacingRulesTbl[i][j];
|
|
|
|
|
plowSpacingRulesTbl[i][j] = pr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Also apply backwards, unless it would create duplicates */
|
|
|
|
|
if (TTMaskEqual(&set1, &set2)) continue;
|
|
|
|
|
|
|
|
|
|
/* LHS is an element of set2, RHS is an element of setRreverse */
|
|
|
|
|
if (TTMaskHasType(&set2, i) && TTMaskHasType(&setRreverse, j))
|
|
|
|
|
{
|
|
|
|
|
/* May have to insert several buckets on different planes */
|
|
|
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
|
|
|
{
|
|
|
|
|
if (!PlaneMaskHasPlane(planes1, pNum)) continue;
|
|
|
|
|
pr = (PlowRule *)mallocMagic(sizeof(PlowRule));
|
|
|
|
|
TTMaskClearMask3(&tmp1, &DBPlaneTypes[pNum], &set1);
|
|
|
|
|
TTMaskCom2(&tmp2, &setRreverse);
|
|
|
|
|
TTMaskAndMask3(&pr->pr_ltypes, &DBPlaneTypes[pNum], &tmp2);
|
|
|
|
|
pr->pr_oktypes = tmp1;
|
|
|
|
|
pr->pr_dist = distance;
|
|
|
|
|
pr->pr_mod = 0;
|
|
|
|
|
pr->pr_pNum = pNum;
|
|
|
|
|
pr->pr_flags = 0;
|
|
|
|
|
pr->pr_next = plowSpacingRulesTbl[i][j];
|
|
|
|
|
plowSpacingRulesTbl[i][j] = pr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowEdgeRule --
|
|
|
|
|
*
|
|
|
|
|
* Process a primitive edge rule.
|
|
|
|
|
* This is of the form:
|
|
|
|
|
*
|
|
|
|
|
* edge layers1 layers2 dist OKtypes cornerTypes cornerDist why [plane]
|
|
|
|
|
* or edge4way layers1 layers2 dist OKtypes cornerTypes cornerDist why [plane]
|
|
|
|
|
* e.g, edge poly,pmc s 1 diff poly,pmc "poly-diff separation must be 2"
|
|
|
|
|
*
|
|
|
|
|
* An "edge" rule is applied only down and to the left.
|
|
|
|
|
* An "edge4way" rule is applied in all four directions.
|
|
|
|
|
*
|
|
|
|
|
* For plowing, we consider edge rules to be spacing rules.
|
|
|
|
|
* Ordinary "edge" rules can be handled exactly (taking the distance
|
|
|
|
|
* to be the maximum of dist and cornerDist above), because they are
|
|
|
|
|
* always applied in the proper direction. Each edge rule produces
|
|
|
|
|
* one normal spacing rule, and possibly an additional spacing rule
|
|
|
|
|
* that is only applied in the penumbra (if cornerTypes and layers2
|
|
|
|
|
* are different).
|
|
|
|
|
*
|
|
|
|
|
* An "edge4way" rule also requires a conservative approximation to
|
|
|
|
|
* handle the case when it is being applied in the opposite direction.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Updates the plowing spacing rules.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plowEdgeRule(argc, argv)
|
|
|
|
|
int argc;
|
|
|
|
|
char *argv[];
|
|
|
|
|
{
|
|
|
|
|
char *layers1 = argv[1], *layers2 = argv[2];
|
|
|
|
|
int distance = atoi(argv[3]);
|
|
|
|
|
char *okTypes = argv[4], *cornerTypes = argv[5];
|
|
|
|
|
int cdist = atoi(argv[6]);
|
|
|
|
|
TileTypeBitMask set1, set2, tmp1, tmp2, tmp3, setC, setM;
|
|
|
|
|
TileTypeBitMask setOK, setLeft, setRight;
|
|
|
|
|
int pNum, checkPlane, flags;
|
|
|
|
|
PlaneMask ptest, planes1, planes2, pmask;
|
|
|
|
|
bool needPenumbraOnly;
|
|
|
|
|
bool isFourWay = (strcmp(argv[0], "edge4way") == 0);
|
|
|
|
|
register PlowRule *pr;
|
|
|
|
|
register TileType i, j;
|
|
|
|
|
|
|
|
|
|
ptest = DBTechNoisyNameMask(layers1, &set1);
|
|
|
|
|
planes1 = CoincidentPlanes(&set1, ptest);
|
|
|
|
|
ptest = DBTechNoisyNameMask(layers2, &set2);
|
|
|
|
|
planes2 = CoincidentPlanes(&set2, ptest);
|
|
|
|
|
distance = MAX(distance, cdist);
|
|
|
|
|
|
|
|
|
|
/* Make sure that all edges between the two sets exist on one plane */
|
|
|
|
|
if (planes1 == 0 || planes2 == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
if (planes1 != planes2)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
set1 = tmp1;
|
|
|
|
|
set2 = tmp2;
|
|
|
|
|
ptest = DBTechNoisyNameMask(cornerTypes, &tmp3);
|
|
|
|
|
pmask = CoincidentPlanes(&tmp3, ptest);
|
|
|
|
|
if (pmask == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
pNum = LowestMaskBit(pmask);
|
|
|
|
|
|
|
|
|
|
/* If an explicit check plane was specified, use it */
|
|
|
|
|
checkPlane = pNum;
|
|
|
|
|
if (argc == 9)
|
|
|
|
|
{
|
|
|
|
|
checkPlane = DBTechNamePlane(argv[8]);
|
|
|
|
|
if (checkPlane < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the images of everything in okTypes on the check plane */
|
|
|
|
|
ptest = DBTechNoisyNameMask(okTypes, &setM);
|
|
|
|
|
pmask = CoincidentPlanes(&setM, ptest);
|
|
|
|
|
if (pmask == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
needPenumbraOnly = !TTMaskEqual(&set2, &setC);
|
|
|
|
|
TTMaskCom2(&setLeft, &setC);
|
|
|
|
|
TTMaskAndMask(&setLeft, &DBPlaneTypes[pNum]);
|
|
|
|
|
TTMaskCom2(&setRight, &set2);
|
|
|
|
|
TTMaskAndMask(&setRight, &DBPlaneTypes[pNum]);
|
|
|
|
|
flags = isFourWay ? PR_EDGE4WAY : PR_EDGE;
|
|
|
|
|
for (i = 0; i < DBNumTypes; i++)
|
|
|
|
|
{
|
|
|
|
|
if (TTMaskHasType(&set1, i))
|
|
|
|
|
{
|
|
|
|
|
for (j = 0; j < DBNumTypes; j++)
|
|
|
|
|
{
|
|
|
|
|
if (TTMaskHasType(&set2, j))
|
|
|
|
|
{
|
|
|
|
|
pr = (PlowRule *)mallocMagic(sizeof(PlowRule));
|
|
|
|
|
pr->pr_ltypes = setLeft;
|
|
|
|
|
pr->pr_oktypes = setM;
|
|
|
|
|
pr->pr_dist = distance;
|
|
|
|
|
pr->pr_mod = 0;
|
|
|
|
|
pr->pr_pNum = checkPlane;
|
|
|
|
|
pr->pr_next = plowSpacingRulesTbl[i][j];
|
|
|
|
|
pr->pr_flags = flags;
|
|
|
|
|
plowSpacingRulesTbl[i][j] = pr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (needPenumbraOnly && TTMaskHasType(&setC, j))
|
|
|
|
|
{
|
|
|
|
|
pr = (PlowRule *)mallocMagic(sizeof(PlowRule));
|
|
|
|
|
pr->pr_ltypes = setRight;
|
|
|
|
|
pr->pr_oktypes = setM;
|
|
|
|
|
pr->pr_dist = distance;
|
|
|
|
|
pr->pr_mod = 0;
|
|
|
|
|
pr->pr_pNum = checkPlane;
|
|
|
|
|
pr->pr_next = plowSpacingRulesTbl[i][j];
|
|
|
|
|
pr->pr_flags = flags|PR_PENUMBRAONLY;
|
|
|
|
|
plowSpacingRulesTbl[i][j] = pr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isFourWay)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Four-way edge rules are applied by the design-rule checker
|
|
|
|
|
* both forwards and backwards. Since plowing can only look
|
|
|
|
|
* forward, we need to approximate the backward rules with
|
|
|
|
|
* a collection of forward rules.
|
|
|
|
|
*
|
|
|
|
|
* Suppose we have the following 4-way rule:
|
|
|
|
|
*
|
|
|
|
|
* CORNER
|
|
|
|
|
* --------+
|
|
|
|
|
* LEFT | RIGHT : OKTypes
|
|
|
|
|
*
|
|
|
|
|
* To check it in the following (backward) configuration, using
|
|
|
|
|
* only rightward-looking rules,
|
|
|
|
|
*
|
|
|
|
|
* OKTypes : RIGHT | LEFT
|
|
|
|
|
* +--------
|
|
|
|
|
* CORNER
|
|
|
|
|
*
|
|
|
|
|
* we generate the following forward rules (with the same distance):
|
|
|
|
|
*
|
|
|
|
|
* ~t
|
|
|
|
|
* --------+
|
|
|
|
|
* t | ~t : ~LEFT
|
|
|
|
|
*
|
|
|
|
|
* for each t in ~OKTypes. In plowing terms, each rule will have LTYPES of
|
|
|
|
|
* t and OKTYPES of ~LEFT. In effect, this is creating a forward spacing
|
|
|
|
|
* rule between each of the types ~OKTypes, and the materials in LEFT.
|
|
|
|
|
* The edge is found on checkPlane, and checked on plane pNum.
|
|
|
|
|
*
|
|
|
|
|
* Because the corner and right-hand types for these rules are the same,
|
|
|
|
|
* we don't need to generate any PR_PENUMBRAONLY rules.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
setRight = setM;
|
|
|
|
|
TTMaskCom2(&setLeft, &setM);
|
|
|
|
|
TTMaskAndMask(&setLeft, &DBPlaneTypes[checkPlane]);
|
|
|
|
|
TTMaskCom2(&setOK, &set1);
|
|
|
|
|
TTMaskAndMask(&setOK, &DBPlaneTypes[pNum]);
|
|
|
|
|
for (i = 0; i < DBNumTypes; i++)
|
|
|
|
|
{
|
|
|
|
|
if (TTMaskHasType(&setLeft, i))
|
|
|
|
|
{
|
|
|
|
|
for (j = 0; j < DBNumTypes; j++)
|
|
|
|
|
{
|
|
|
|
|
if (TTMaskHasType(&setRight, j))
|
|
|
|
|
{
|
|
|
|
|
pr = (PlowRule *)mallocMagic(sizeof(PlowRule));
|
|
|
|
|
TTMaskSetOnlyType(&pr->pr_ltypes, i);
|
|
|
|
|
pr->pr_oktypes = setOK;
|
|
|
|
|
pr->pr_dist = distance;
|
|
|
|
|
pr->pr_mod = 0;
|
|
|
|
|
pr->pr_pNum = pNum;
|
|
|
|
|
pr->pr_flags = flags|PR_EDGEBACK;
|
|
|
|
|
pr->pr_next = plowSpacingRulesTbl[i][j];
|
|
|
|
|
plowSpacingRulesTbl[i][j] = pr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlowDRCFinal --
|
|
|
|
|
*
|
|
|
|
|
* Called after all lines of the drc section in the technology file have been
|
|
|
|
|
* read. The preliminary plowing rules tables are pruned by removing rules
|
|
|
|
|
* covered by other (longer distance) rules.
|
|
|
|
|
*
|
|
|
|
|
* We also construct plowMaxDist[] to contain for entry 't' the maximum
|
|
|
|
|
* distance associated with any plowing rule in a bucket with 't' on its
|
|
|
|
|
* LHS.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* May remove PlowRules from the linked lists of the width and
|
|
|
|
|
* spacing rules tables. Sets the values in plowMaxDist[].
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlowDRCFinal()
|
|
|
|
|
{
|
|
|
|
|
register PlowRule *pr;
|
|
|
|
|
register TileType i, j;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < DBNumTypes; i++)
|
|
|
|
|
{
|
|
|
|
|
plowMaxDist[i] = 0;
|
|
|
|
|
for (j = 0; j < DBNumTypes; j++)
|
|
|
|
|
{
|
|
|
|
|
if (pr = plowWidthRulesTbl[i][j])
|
|
|
|
|
{
|
|
|
|
|
pr = plowWidthRulesTbl[i][j] = plowTechOptimizeRule(pr);
|
|
|
|
|
for ( ; pr; pr = pr->pr_next)
|
|
|
|
|
if (pr->pr_dist > plowMaxDist[i])
|
|
|
|
|
plowMaxDist[i] = pr->pr_dist;
|
|
|
|
|
}
|
|
|
|
|
if (pr = plowSpacingRulesTbl[i][j])
|
|
|
|
|
{
|
|
|
|
|
pr = plowSpacingRulesTbl[i][j] = plowTechOptimizeRule(pr);
|
|
|
|
|
for ( ; pr; pr = pr->pr_next)
|
|
|
|
|
if (pr->pr_dist > plowMaxDist[i])
|
|
|
|
|
plowMaxDist[i] = pr->pr_dist;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
@ -170,9 +757,13 @@ next: ;
|
|
|
|
|
void
|
|
|
|
|
PlowTechInit()
|
|
|
|
|
{
|
|
|
|
|
register TileType i, j;
|
|
|
|
|
PlowRule *pr;
|
|
|
|
|
|
|
|
|
|
PlowFixedTypes = DBZeroTypeBits;
|
|
|
|
|
PlowCoveredTypes = DBZeroTypeBits;
|
|
|
|
|
PlowDragTypes = DBZeroTypeBits;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
@ -286,8 +877,54 @@ PlowTechFinal()
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowScaleUp ---
|
|
|
|
|
*
|
|
|
|
|
* PlowAfterTech ---
|
|
|
|
|
* Scale all plow distances according to the current DRC scale factor.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void plowScaleUp(PlowRule *pr, int scalefactor)
|
|
|
|
|
{
|
|
|
|
|
int dist;
|
|
|
|
|
|
|
|
|
|
if (pr->pr_dist > 0)
|
|
|
|
|
{
|
|
|
|
|
dist = pr->pr_dist;
|
|
|
|
|
if (pr->pr_mod != 0)
|
|
|
|
|
pr->pr_dist--;
|
|
|
|
|
pr->pr_dist *= scalefactor;
|
|
|
|
|
pr->pr_dist += (short)pr->pr_mod;
|
|
|
|
|
pr->pr_mod = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowScaleDown ---
|
|
|
|
|
*
|
|
|
|
|
* Scale all plow distances according to the current DRC scale factor.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void plowScaleDown(PlowRule *pr, int scalefactor)
|
|
|
|
|
{
|
|
|
|
|
int dist;
|
|
|
|
|
|
|
|
|
|
if (pr->pr_dist > 0)
|
|
|
|
|
{
|
|
|
|
|
dist = pr->pr_dist;
|
|
|
|
|
pr->pr_dist /= scalefactor;
|
|
|
|
|
if ((pr->pr_mod = (unsigned char)(dist % scalefactor)) != 0)
|
|
|
|
|
pr->pr_dist++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DRCPlowScale ---
|
|
|
|
|
*
|
|
|
|
|
* Routine to run after the entire techfile has been processed (or reloaded),
|
|
|
|
|
* or when the DRC rules have been rescaled, after an internal grid rescaling.
|
|
|
|
|
@ -297,9 +934,35 @@ PlowTechFinal()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlowAfterTech()
|
|
|
|
|
DRCPlowScale(int scaled, int scalen, bool adjustmax)
|
|
|
|
|
{
|
|
|
|
|
/* This remains to be done. . . */
|
|
|
|
|
PlowRule *pr;
|
|
|
|
|
TileType i, j;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < TT_MAXTYPES; i++)
|
|
|
|
|
{
|
|
|
|
|
for (j = 0; j < TT_MAXTYPES; j++)
|
|
|
|
|
{
|
|
|
|
|
for (pr = plowWidthRulesTbl[i][j]; pr; pr = pr->pr_next)
|
|
|
|
|
{
|
|
|
|
|
plowScaleUp(pr, scaled);
|
|
|
|
|
plowScaleDown(pr, scalen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (pr = plowSpacingRulesTbl[i][j]; pr; pr = pr->pr_next)
|
|
|
|
|
{
|
|
|
|
|
plowScaleUp(pr, scaled);
|
|
|
|
|
plowScaleDown(pr, scalen);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Scale plowMaxDist */
|
|
|
|
|
if (adjustmax)
|
|
|
|
|
{
|
|
|
|
|
plowMaxDist[i] *= scaled;
|
|
|
|
|
plowMaxDist[i] /= scalen;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|