From f4c5ec3a78478d35c7be6a8b803103da4dc4afd3 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 9 Nov 2022 11:15:06 -0500 Subject: [PATCH] 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. --- VERSION | 2 +- lef/defRead.c | 30 +++++++++++++++++++--- lef/defWrite.c | 67 ++++++++++++++++++++++++++++++++++---------------- lef/lefInt.h | 1 + lef/lefRead.c | 15 ++++++++++- 5 files changed, 88 insertions(+), 27 deletions(-) diff --git a/VERSION b/VERSION index 8ec2624e..7b425238 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.337 +8.3.338 diff --git a/lef/defRead.c b/lef/defRead.c index d11404db..bb5cc6ff 100644 --- a/lef/defRead.c +++ b/lef/defRead.c @@ -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"); diff --git a/lef/defWrite.c b/lef/defWrite.c index c99ca9ee..afdbdc84 100644 --- a/lef/defWrite.c +++ b/lef/defWrite.c @@ -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. . . */ diff --git a/lef/lefInt.h b/lef/lefInt.h index 61c843a5..1e20f1b0 100644 --- a/lef/lefInt.h +++ b/lef/lefInt.h @@ -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; diff --git a/lef/lefRead.c b/lef/lefRead.c index 18d28d6c..626a07c7 100644 --- a/lef/lefRead.c +++ b/lef/lefRead.c @@ -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");