Fixed the DEF write routine, which had an error in identifying

"slivers";  the error tended to produce artifacts (extra metal)
around contacts.  Fixed an issue that caused the DEF write routine
to open the same file twice instead of a new file for the second
part of the DEF data, and then potentially hit a runaway condition
when trying to merge the two files together.
This commit is contained in:
Tim Edwards 2022-11-09 11:15:06 -05:00
parent 2059d6fbb1
commit f4c5ec3a78
5 changed files with 88 additions and 27 deletions

View File

@ -1 +1 @@
8.3.337
8.3.338

View File

@ -97,7 +97,7 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat
Rect locarea, r;
int extend, lextend, hextend;
float x, y, z, w;
int routeWidth, paintWidth, saveWidth;
int paintWidth, saveWidth, paintExtend;
TileType routeLayer, paintLayer;
HashEntry *he;
lefLayer *lefl = NULL;
@ -188,6 +188,7 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat
else
paintWidth = (lefl) ? lefl->info.route.width :
DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
paintExtend = 0; /* SPECIALNETS always have 0 wire extension */
saveWidth = paintWidth;
}
else
@ -200,6 +201,7 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat
paintWidth = (rule) ? rule->width :
(lefl) ? lefl->info.route.width :
DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
paintExtend = (rule) ? rule->extend : paintWidth;
}
}
else if ((*token == '+') && (special == TRUE))
@ -340,6 +342,7 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat
/* Return to the default width for this layer */
paintWidth = (lefl) ? lefl->info.route.width :
DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
paintExtend = (special) ? 0 : paintWidth;
is_taper = TRUE;
}
else if (!strcmp(token, "TAPERRULE"))
@ -354,13 +357,18 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat
if (rule->lefInfo == lefl)
break;
if (rule) paintWidth = rule->width;
if (rule)
{
paintWidth = rule->width;
paintExtend = rule->extend;
}
is_taper = TRUE;
}
else if (!strcmp(token, "DEFAULT"))
{
paintWidth = (lefl) ? lefl->info.route.width :
DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
paintExtend = (special) ? 0 : paintWidth;
is_taper = TRUE;
}
else
@ -479,6 +487,7 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat
else
paintWidth = (lefl) ? lefl->info.route.width
: DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
paintExtend = (special) ? 0 : paintWidth;
break;
}
}
@ -544,7 +553,8 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat
/* is apparently how everyone interprets it, and is true for */
/* 5.6 spec. */
extend = (special) ? 0 : paintWidth;
extend = paintExtend;
token = LefNextToken(f, TRUE);
if (*token != ')')
{
@ -872,6 +882,7 @@ DefReadNonDefaultRules(f, rootDef, sname, oscale, total)
rule->lefInfo = lefl;
rule->width = 0;
rule->spacing = 0;
rule->extend = 0;
rule->next = ruleset->rule;
ruleset->rule = rule;
}
@ -911,8 +922,19 @@ DefReadNonDefaultRules(f, rootDef, sname, oscale, total)
else
rule->spacing = (int)roundf(fvalue / oscale);
break;
case DEF_NONDEFLAYER_DIAG:
case DEF_NONDEFLAYER_EXT:
if (!inlayer)
LefError(DEF_INFO, "WIREEXT specified without layer.\n");
token = LefNextToken(f, TRUE);
sscanf(token, "%f", &fvalue);
if (rule == NULL)
LefError(DEF_INFO, "No rule for non-default extension.\n");
else if (lefl == NULL)
LefError(DEF_INFO, "No layer for non-default extension.\n");
else
rule->extend = (int)roundf((2 * fvalue) / oscale);
break;
case DEF_NONDEFLAYER_DIAG:
if (!inlayer)
LefError(DEF_INFO,
"Layer value specified without layer.\n");

View File

@ -319,7 +319,7 @@ defnodeCount(node, res, cap, total)
if (pwr)
{
/* Diagnostic */
TxPrintf("Node %s is defined in the \"globals\" array\n");
TxPrintf("Node %s is defined in the \"globals\" array\n", pwr);
node->efnode_flags |= EF_SPECIAL;
}
@ -771,6 +771,8 @@ defnodeVisit(node, res, cap, defdata)
scx.scx_area = node->efnode_loc;
scx.scx_use = def->cd_parents;
scx.scx_trans = GeoIdentityTransform;
rport = GeoNullRect;
DBTreeSrUniqueTiles(&scx, &tmask, 0, defPortTileFunc, (ClientData)&rport);
/* Add the residue types to any contact type */
@ -780,14 +782,24 @@ defnodeVisit(node, res, cap, defdata)
TTMaskSetMask(&tmask, rmask);
TTMaskSetType(&tmask, magictype);
}
/* Expand the rectangle around the port to overlap any */
/* connecting material. */
rport.r_xbot--;
rport.r_ybot--;
rport.r_xtop++;
rport.r_ytop++;
DBSrConnect(def, &rport, &tmask, DBConnectTbl, &TiPlaneRect,
/* Check if anything was found in the location (e.g., .ext file
* could be invalid or outdated).
*/
if (GEO_RECTNULL(&rport))
TxError("Nothing found at node %s location (bad .ext file?)!\n", ndn);
else
{
/* Expand the rectangle around the port to overlap any */
/* connecting material. */
rport.r_xbot--;
rport.r_ybot--;
rport.r_xtop++;
rport.r_ytop++;
DBSrConnect(def, &rport, &tmask, DBConnectTbl, &TiPlaneRect,
defNetGeometryFunc, (ClientData)defdata);
}
}
/* Was there a last record pending? If so, write it. */
@ -1030,13 +1042,20 @@ defNetGeometryFunc(tile, plane, defdata)
}
}
/* Check for non-default widths */
if ((h != routeWidth) && (w != routeWidth))
/* Check for non-default widths and slivers */
if (((h != routeWidth) && (w != routeWidth)) ||
((h == routeWidth) && (w < routeWidth)) ||
((w == routeWidth) && (h < routeWidth)))
{
/* Handle slivers. There are two main cases:
* (1) Sliver is part of a via extension, so it can be ignored.
* (2) Sliver is a route split into several tiles due to geometry
* to the left. Expand up and down to include all tiles.
*
* Slivers that violate design rule widths are assumed to get
* merged with another tile to make a full shape. Slivers that
* continue to violate minimum width with be ignored.
*/
if (w < routeWidth) return 0;
@ -1097,6 +1116,8 @@ defNetGeometryFunc(tile, plane, defdata)
ruleset->rule = (lefRule *)mallocMagic(sizeof(lefRule));
ruleset->rule->lefInfo = lefType;
ruleset->rule->width = ndv;
/* Policy is never to use a wire extension on non-default rules. */
ruleset->rule->extend = 0;
}
taperName = ruleset->name;
}
@ -1123,7 +1144,8 @@ defNetGeometryFunc(tile, plane, defdata)
if (routeWidth == 0) routeWidth = h;
extlen = 0;
if (defdata->specialmode == DO_REGULAR)
/* NOTE: non-default tapers are not using wire extensions */
if ((defdata->specialmode == DO_REGULAR) && (taperName == NULL))
{
x1 = x1 + (routeWidth / 2 * oscale);
x2 = x2 - (routeWidth / 2 * oscale);
@ -1139,7 +1161,8 @@ defNetGeometryFunc(tile, plane, defdata)
if (routeWidth == 0) routeWidth = w;
extlen = 0;
if (defdata->specialmode == DO_REGULAR)
/* NOTE: non-default tapers are not using wire extensions */
if ((defdata->specialmode == DO_REGULAR) && (taperName == NULL))
{
y1 = y1 + (routeWidth / 2 * oscale);
y2 = y2 - (routeWidth / 2 * oscale);
@ -2282,13 +2305,12 @@ defWritePins(f, rootDef, lefMagicToLefLayer, oscale)
/*
*------------------------------------------------------------
*
* defWriteNets --
* defWriteBlockages --
*
* Output the NETS section of a DEF file. We make use of
* the connectivity search routines used by "getnode" to
* determine unique notes and assign a net name to each.
* Then, we generate the geometry output for each NET
* entry.
* Output the BLOCKAGES section of a DEF file. Write
* geometry for any layer that is defined as an
* obstruction layer in the technology file "lef"
* section.
*
* Results:
* None.
@ -2798,7 +2820,7 @@ DefWriteCell(def, outName, allSpecial, units)
/* Not done yet with output, so keep this file open. . . */
f2 = lefFileOpen(def, outName, ".def.part", "w", &filename);
f2 = lefFileOpen(def, outName, ".def_part", "w", &filename);
if (f2 == NULL)
{
@ -2850,16 +2872,19 @@ DefWriteCell(def, outName, allSpecial, units)
nrules = (LefRules *)HashGetValue(he);
fprintf(f, " - %s\n", nrules->name);
fprintf(f, " + LAYER %s WIDTH %.10g ;\n",
fprintf(f, " + LAYER %s WIDTH %.10g",
nrules->rule->lefInfo->canonName,
((float)nrules->rule->width * scale));
if (nrules->rule->extend > 0)
fprintf(f, " WIREEXT %.10g", (float)nrules->rule->extend / 2.0);
fprintf(f, " ;\n");
}
fprintf(f, "END NONDEFAULTRULES\n\n");
}
/* Append contents of file with NETS and SPECIALNETS sections */
f2 = lefFileOpen(def, outName, ".def.part", "r", &filename);
f2 = lefFileOpen(def, outName, ".def_part", "r", &filename);
if (f2 == NULL)
{
/* This should not happen because the file was just written. . . */

View File

@ -107,6 +107,7 @@ typedef struct _lefRule {
lefLayer *lefInfo; /* Layer or via referenced by the rule */
int width; /* Non-default width value for layer */
int spacing; /* Non-default spacing value for layer */
int extend; /* Non-default extension value for layer */
struct _lefRule *next;
} lefRule;

View File

@ -1886,6 +1886,7 @@ newrule:
rule->lefInfo = lefl;
rule->width = 0;
rule->spacing = 0;
rule->extend = 0;
rule->next = ruleset->rule;
ruleset->rule = rule;
}
@ -1928,8 +1929,20 @@ newrule:
rule->spacing = (int)roundf(fvalue / oscale);
LefEndStatement(f);
break;
case LEF_NONDEFLAYER_DIAG:
case LEF_NONDEFLAYER_EXT:
if (!inlayer)
LefError(DEF_INFO, "WIREEXT specified without layer.\n");
token = LefNextToken(f, TRUE);
sscanf(token, "%f", &fvalue);
if (rule == NULL)
LefError(LEF_INFO, "No rule for non-default extension.\n");
else if (lefl == NULL)
LefError(LEF_INFO, "No layer for non-default extension.\n");
else
rule->extend = (int)roundf((2 * fvalue) / oscale);
LefEndStatement(f);
break;
case LEF_NONDEFLAYER_DIAG:
if (!inlayer)
LefError(LEF_INFO,
"Layer value specified without layer.\n");