diff --git a/VERSION b/VERSION index f248c753..f3ff06b3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.340 +8.3.341 diff --git a/database/DBconnect.c b/database/DBconnect.c index 61ce6510..c57ab7b7 100644 --- a/database/DBconnect.c +++ b/database/DBconnect.c @@ -223,7 +223,6 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData) /* The following lets us call DBSrConnect recursively */ else if (startTile->ti_client == (ClientData)1) return 0; - /* Pass 1. During this pass the client function gets called. */ csa.csa_clientFunc = func; @@ -313,7 +312,6 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData) /* The following lets us call DBSrConnect recursively */ else if (startTile->ti_client == (ClientData)1) return 0; - /* Pass 1. During this pass the client function gets called. */ csa.csa_clientFunc = func; @@ -394,6 +392,7 @@ dbSrConnectFunc(tile, csa) Rect tileArea; int i, pNum; int result = 0; + bool callClient; TileTypeBitMask *connectMask; TileType loctype, checktype; PlaneMask planes; @@ -422,6 +421,7 @@ dbSrConnectFunc(tile, csa) * visited. */ + callClient = TRUE; if (csa->csa_clear) { if (tile->ti_client == (ClientData) CLIENTDEFAULT) continue; @@ -429,13 +429,17 @@ dbSrConnectFunc(tile, csa) } else { - if (tile->ti_client != (ClientData) CLIENTDEFAULT) continue; + if (tile->ti_client == (ClientData) 1) continue; + + /* Allow a process to mark tiles for skipping the client function */ + if (tile->ti_client != (ClientData) CLIENTDEFAULT) + callClient = FALSE; tile->ti_client = (ClientData) 1; } /* Call the client function, if there is one. */ - if (csa->csa_clientFunc != NULL) + if (callClient && (csa->csa_clientFunc != NULL)) { if ((*csa->csa_clientFunc)(tile, pNum, csa->csa_clientData) != 0) { @@ -478,7 +482,7 @@ dbSrConnectFunc(tile, csa) { if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue; } - else if (t2->ti_client != (ClientData) CLIENTDEFAULT) continue; + else if (t2->ti_client == (ClientData) 1) continue; if (IsSplit(t2)) TiSetBody(t2, (ClientData)(t2->ti_body | TT_SIDE)); /* bit set */ STACKPUSH((ClientData)t2, dbConnectStack); @@ -506,7 +510,7 @@ bottomside: { if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue; } - else if (t2->ti_client != (ClientData) CLIENTDEFAULT) continue; + else if (t2->ti_client == (ClientData) 1) continue; if (IsSplit(t2)) { if (SplitDirection(t2)) @@ -540,7 +544,7 @@ rightside: { if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextRight; } - else if (t2->ti_client != (ClientData) CLIENTDEFAULT) goto nextRight; + else if (t2->ti_client == (ClientData) 1) goto nextRight; if (IsSplit(t2)) TiSetBody(t2, (ClientData)(t2->ti_body & ~TT_SIDE)); /* bit clear */ STACKPUSH((ClientData)t2, dbConnectStack); @@ -568,7 +572,7 @@ topside: { if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextTop; } - else if (t2->ti_client != (ClientData) CLIENTDEFAULT) goto nextTop; + else if (t2->ti_client == (ClientData) 1) goto nextTop; if (IsSplit(t2)) { if (SplitDirection(t2)) diff --git a/dbwind/DBWdisplay.c b/dbwind/DBWdisplay.c index 80e25fb2..d8047390 100644 --- a/dbwind/DBWdisplay.c +++ b/dbwind/DBWdisplay.c @@ -422,7 +422,7 @@ DBWredisplay(w, rootArea, clipArea) GrSetStuff(STYLE_LABEL); (void) DBTreeSrLabels(&scontext, &DBAllTypeBits, bitMask, (TerminalPath *) NULL, TF_LABEL_DISPLAY | TF_LABEL_ATTACH, - dbwLabelFunc, (ClientData) NULL); + dbwLabelFunc, (ClientData)(&crec->dbw_visibleLayers)); GrClipTo(&rootClip); } @@ -921,16 +921,26 @@ DBWDrawFontLabel(label, window, trans, style) */ int -dbwLabelFunc(scx, label, tpath) +dbwLabelFunc(scx, label, tpath, clientData) SearchContext *scx; /* Contains pointer to use containing def in * which label appears, and transform to * screen coordinates. */ Label *label; /* Label to be displayed. */ TerminalPath *tpath; /* Contains pointer to full pathname of label */ + ClientData clientData; /* Used for mask for dbw_visibleLayers */ { Rect labRect, tmp; int screenPos, screenRot, newStyle; + TileTypeBitMask *vmask; + + vmask = (TileTypeBitMask *)clientData; + + /* Do not draw the label if the layer to which it is attached is + * not being drawn. + */ + if (!TTMaskHasType(vmask, label->lab_type)) + return 0; if (!dbwAllSame && ((editDef != scx->scx_use->cu_def) || (scx->scx_trans.t_a != editTrans.t_a) diff --git a/lef/defRead.c b/lef/defRead.c index bb5cc6ff..977ac809 100644 --- a/lef/defRead.c +++ b/lef/defRead.c @@ -103,7 +103,6 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat lefLayer *lefl = NULL; lefRule *rule = NULL; int keyword; - bool is_taper = FALSE, end_taper = FALSE; static char *specnet_keys[] = { "SHAPE", @@ -194,9 +193,13 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat else { if (ruleset) + { for (rule = ruleset->rule; rule; rule = rule->next) if (rule->lefInfo == lefl) break; + } + else + rule = NULL; paintWidth = (rule) ? rule->width : (lefl) ? lefl->info.route.width : @@ -343,7 +346,6 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat paintWidth = (lefl) ? lefl->info.route.width : DEFAULT_WIDTH * DBLambda[1] / DBLambda[0]; paintExtend = (special) ? 0 : paintWidth; - is_taper = TRUE; } else if (!strcmp(token, "TAPERRULE")) { @@ -362,23 +364,18 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat 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 LefError(DEF_ERROR, "Unknown nondefault rule \"%s\"\n", token); } else if (*token != '(') /* via name */ { - /* A via directly after a taper rule would cancel the taper rule */ - is_taper = FALSE; - /* A '+' or ';' record ends the route */ if (*token == ';' || *token == '+') break; @@ -569,8 +566,6 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat extend = (int)roundf((2 * z) / oscale); } - end_taper = ((valid == TRUE) && (is_taper == TRUE)) ? TRUE : FALSE; - /* Indicate that we have a valid reference point */ if (valid == FALSE) @@ -644,24 +639,6 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat newRoute->r_r.r_ytop >>= 1; } - /* If a taper rule was in effect and we have a valid */ - /* segment, reset the width after creating the segment. */ - - if (end_taper) - { - is_taper = FALSE; - end_taper = FALSE; - rule = NULL; - if (ruleset) - for (rule = ruleset->rule; rule; rule = rule->next) - if (rule->lefInfo == lefl) - break; - - paintWidth = (rule) ? rule->width : - (lefl) ? lefl->info.route.width : - DEFAULT_WIDTH * DBLambda[1] / DBLambda[0]; - } - endCoord: /* Find the closing parenthesis for the coordinate pair */ while (*token != ')') @@ -845,7 +822,7 @@ DefReadNonDefaultRules(f, rootDef, sname, oscale, total) if (!inlayer) continue; } - else + if (*token == '+') { inlayer = FALSE; rule = NULL; diff --git a/lef/defWrite.c b/lef/defWrite.c index f96c1088..35799141 100644 --- a/lef/defWrite.c +++ b/lef/defWrite.c @@ -50,6 +50,7 @@ typedef struct { TileType type; float x, y, extlen; unsigned char orient; + LefRules *ruleset; /* Non-default ruleset or NULL */ LefMapping *MagicToLefTbl; HashTable *defViaTable; @@ -643,6 +644,7 @@ defWriteNets(f, rootDef, oscale, MagicToLefTable, defViaTable, specialmode) defdata.def = rootDef; defdata.MagicToLefTbl = MagicToLefTable; defdata.outcolumn = 0; + defdata.ruleset = NULL; defdata.specialmode = specialmode; defdata.defViaTable = defViaTable; @@ -839,6 +841,34 @@ defMinWireFunc(tile, yclip) return 0; } +/* Callback function for defNetGeometryFunc(). Determines if any tile */ +/* is enclosed by rect, and if so, marks the tile client so that */ +/* DBSrConnectFunc() will not apply the client function to that tile. */ +/* clientdata value (ClientData)1 means the tile has already been */ +/* processed; (ClientData)CLIENTDEFAULT means that it has not been */ +/* processed. Any other value will cause it to skip the client */ +/* function when it is processed. */ + +int +defExemptWireFunc(tile, rect) + Tile *tile; + Rect *rect; +{ + Rect r; + + /* Do not change the client data of tiles that have been processed! */ + if (tile->ti_client != (ClientData) 1) + { + /* Ignore contacts, which need additional processing */ + if (DBIsContact(TiGetType(tile))) return 0; + + TiToRect(tile, &r); + if (GEO_SURROUND(rect, &r)) + tile->ti_client = (ClientData) 2; + } + return 0; +} + /* Callback function for DBTreeSrUniqueTiles. When no routed areas */ /* were found, we assume that there was no routing material overlapping */ /* the port. So, we need to find the area of a tile defining the port */ @@ -886,7 +916,8 @@ defNetGeometryFunc(tile, plane, defdata) int routeWidth, w, h, midlinex2, topClip, botClip; float x1, y1, x2, y2, extlen; lefLayer *lefType, *lefl; - char *lefName, *taperName, viaName[128], posstr[24]; + char *lefName, viaName[128], posstr[24]; + LefRules *lastruleset = defdata->ruleset; HashEntry *he; HashTable *defViaTable = defdata->defViaTable; LefMapping *MagicToLefTable = defdata->MagicToLefTbl; @@ -1004,7 +1035,6 @@ defNetGeometryFunc(tile, plane, defdata) lefName = MagicToLefTable[ttype].lefName; if (lefName == NULL) return 0; /* Do not write types not in LEF definition */ lefType = MagicToLefTable[ttype].lefInfo; - taperName = NULL; orient = GEO_EAST; w = r.r_xtop - r.r_xbot; @@ -1055,30 +1085,40 @@ defNetGeometryFunc(tile, plane, defdata) * * 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. + * continue to violate minimum width will be ignored. */ if (w < routeWidth) return 0; if (h < routeWidth) { - /* Check upward */ + /* Check upward. */ r = rorig; r.r_ytop = r.r_ybot + routeWidth; r.r_ybot = rorig.r_ytop; - topClip = r.r_ytop; - DBSrPaintArea(tile, def->cd_planes[plane], - &r, &DBNotConnectTbl[ttype], - defMaxWireFunc, (ClientData)&topClip); + do + { + r.r_ytop += routeWidth; + topClip = r.r_ytop; + DBSrPaintArea(tile, def->cd_planes[plane], + &r, &DBNotConnectTbl[ttype], + defMaxWireFunc, (ClientData)&topClip); + } + while (topClip == r.r_ytop); /* Check downward */ r = rorig; r.r_ybot = r.r_ytop - routeWidth; r.r_ytop = rorig.r_ybot; - botClip = r.r_ybot; - DBSrPaintArea(tile, def->cd_planes[plane], - &r, &DBNotConnectTbl[ttype], - defMinWireFunc, (ClientData)&botClip); + do + { + r.r_ybot -= routeWidth; + botClip = r.r_ybot; + DBSrPaintArea(tile, def->cd_planes[plane], + &r, &DBNotConnectTbl[ttype], + defMinWireFunc, (ClientData)&botClip); + } + while (botClip == r.r_ybot); r = rorig; if (topClip > r.r_ytop) r.r_ytop = topClip; @@ -1087,6 +1127,14 @@ defNetGeometryFunc(tile, plane, defdata) /* If height is still less that a route width, bail */ h = r.r_ytop - r.r_ybot; if (h < routeWidth) return 0; + + /* If r is larger than rorig, then exempt all unprocessed */ + /* tiles contained in rorig from being checked again. */ + + if (!GEO_SAMERECT(r, rorig)) + DBSrPaintArea(tile, def->cd_planes[plane], + &r, &DBConnectTbl[ttype], + defExemptWireFunc, (ClientData)&r); } /* Handle non-default width regular nets (use TAPERRULE) */ @@ -1104,7 +1152,9 @@ defNetGeometryFunc(tile, plane, defdata) (h < w) ? h : w, routeWidth); */ - /* Create a nondefault rule. Use one rule per layer and width */ + /* Create a nondefault rule. Use one rule per layer and width */ + /* for now (to do: keep the same ruleset when possible) */ + sprintf(ndname, "%s_width_%d", lefName, (int)((float)ndv * oscale)); he = HashFind(&LefNonDefaultRules, ndname); ruleset = (LefRules *)HashGetValue(he); @@ -1118,8 +1168,12 @@ defNetGeometryFunc(tile, plane, defdata) ruleset->rule->width = ndv; /* Policy is never to use a wire extension on non-default rules. */ ruleset->rule->extend = 0; + /* Spacing is not needed, but set it to the layer default */ + ruleset->rule->spacing = DRCGetDefaultLayerSpacing(ttype, ttype); + /* There will only be one rule in this ruleset */ + ruleset->rule->next = NULL; } - taperName = ruleset->name; + defdata->ruleset = ruleset; } /* Set orientation based on longest side */ @@ -1134,6 +1188,9 @@ defNetGeometryFunc(tile, plane, defdata) midlinex2 = (r.r_ytop + r.r_ybot); } } + else + /* Non-default width has ended and the route returns to default rules */ + defdata->ruleset = NULL; /* Find the route orientation and centerline endpoint coordinates */ @@ -1148,7 +1205,7 @@ defNetGeometryFunc(tile, plane, defdata) extlen = 0; /* NOTE: non-default tapers are not using wire extensions */ - if ((defdata->specialmode == DO_REGULAR) && (taperName == NULL)) + if ((defdata->specialmode == DO_REGULAR) && (defdata->ruleset == NULL)) { x1 = x1 + (routeWidth / 2 * oscale); x2 = x2 - (routeWidth / 2 * oscale); @@ -1165,7 +1222,7 @@ defNetGeometryFunc(tile, plane, defdata) extlen = 0; /* NOTE: non-default tapers are not using wire extensions */ - if ((defdata->specialmode == DO_REGULAR) && (taperName == NULL)) + if ((defdata->specialmode == DO_REGULAR) && (defdata->ruleset == NULL)) { y1 = y1 + (routeWidth / 2 * oscale); y2 = y2 - (routeWidth / 2 * oscale); @@ -1254,9 +1311,6 @@ defNetGeometryFunc(tile, plane, defdata) sameroute = FALSE; } } - else if (taperName != NULL) - /* TAPERRULE can only be put after a NEW layer line */ - sameroute = FALSE; else sameroute = TRUE; } @@ -1267,13 +1321,28 @@ defNetGeometryFunc(tile, plane, defdata) if (sameroute && (defdata->specialmode != DO_REGULAR) && defdata->orient == GEO_CENTER) sameroute = FALSE; + + /* For now, placement of a via after a taper rule cancels the */ + /* taper rule (see above note about combining layer rules). */ + if (sameroute && (defdata->ruleset != NULL)) + { + lastruleset = NULL; + sameroute = FALSE; + } } + /* If a non-default rule has changed, then we start a new route */ + if (lastruleset != defdata->ruleset) + { + sameroute = FALSE; + lastruleset = defdata->ruleset; + } /* Determine if we need to write a NEW (type) record. We do this */ /* if 1) this is the first tile visited (except that we don't */ /* write "NEW"), 2) the current tile doesn't touch the last tile */ - /* visited, or 3) the current type is not equal to the last type. */ + /* visited, 3) the current type is not equal to the last type, or */ + /* 4) a new non-default rule is needed. */ if ((!sameroute) || (ttype != defdata->type)) { @@ -1364,8 +1433,8 @@ defNetGeometryFunc(tile, plane, defdata) defCheckForBreak(strlen(rName) + 1, defdata); fprintf(f, "%s ", rName); - if (taperName != NULL) - fprintf(f, "TAPERRULE %s ", taperName); + if (defdata->ruleset != NULL) + fprintf(f, "TAPERRULE %s ", defdata->ruleset->name); if (defdata->specialmode != DO_REGULAR) defWriteRouteWidth(defdata, routeWidth); defWriteCoord(defdata, x1, y1, GEO_CENTER); @@ -1392,8 +1461,8 @@ defNetGeometryFunc(tile, plane, defdata) { defCheckForBreak(strlen(lefName) + 1, defdata); fprintf(f, "%s ", lefName); - if (taperName != NULL) - fprintf(f, "TAPERRULE %s ", taperName); + if (defdata->ruleset != NULL) + fprintf(f, "TAPERRULE %s ", defdata->ruleset->name); if (defdata->specialmode != DO_REGULAR) defWriteRouteWidth(defdata, routeWidth); @@ -2421,17 +2490,17 @@ defWriteBlockages(f, rootDef, oscale, MagicToLefTable) for (i = 0; i < numblocks; i++) { if (defobsdata.blockData[i] == NULL) continue; - fprintf(f, " - LAYER %s\n", defobsdata.baseNames[i]); + fprintf(f, " - LAYER %s", defobsdata.baseNames[i]); for (lr = defobsdata.blockData[i]; lr; lr = lr->r_next) { - fprintf(f, " RECT %.10g %.10g %.10g %.10g\n", + fprintf(f, "\n RECT ( %.10g %.10g ) ( %.10g %.10g )", (float)(lr->r_r.r_xbot * oscale), (float)(lr->r_r.r_ybot * oscale), (float)(lr->r_r.r_xtop * oscale), (float)(lr->r_r.r_ytop * oscale)); freeMagic(lr); } - fprintf(f, ";\n"); + fprintf(f, " ;\n"); } fprintf(f, "END BLOCKAGES\n\n"); } @@ -2757,11 +2826,12 @@ defMakeInverseLayerMap(do_vias) */ void -DefWriteCell(def, outName, allSpecial, units) +DefWriteCell(def, outName, allSpecial, units, analRetentive) CellDef *def; /* Cell being written */ char *outName; /* Name of output file, or NULL. */ bool allSpecial; /* Treat all nets as SPECIALNETS? */ int units; /* Force units to this value (default 1000) */ + bool analRetentive; /* Force compatibility with stupid tools */ { char *filename, *filename1, *filename2; char line[2048]; @@ -2881,19 +2951,73 @@ DefWriteCell(def, outName, allSpecial, units) if (numrules > 0) { LefRules *nrules; + lefRule *rule; fprintf(f, "NONDEFAULTRULES %d ;\n", numrules); HashStartSearch(&hs); while (he = HashNext(&LefNonDefaultRules, &hs)) { nrules = (LefRules *)HashGetValue(he); + fprintf(f, " - %s", nrules->name); - fprintf(f, " - %s\n", nrules->name); - fprintf(f, " + LAYER %s WIDTH %.10g", + if (analRetentive) + { + /* Some tools can crash or throw an error if all layers + * are not represented in the non-default rule, which + * is an anal retentive interpretation of the DEF spec. + */ + if (LefInfo.ht_table != (HashEntry **)NULL) + { + HashSearch hs2; + HashEntry *he2; + lefLayer *lefl2; + + HashStartSearch(&hs2); + while (he2 = HashNext(&LefInfo, &hs2)) + { + lefl2 = (lefLayer *)HashGetValue(he2); + if (lefl2->lefClass == CLASS_ROUTE) + { + /* Avoid duplicate entries per route layer */ + if (lefl2->refCnt < 0) continue; + lefl2->refCnt = -lefl2->refCnt; + + /* Ignore obstruction layers */ + if (lefl2->type == -1) continue; + + /* Only output rules here for routing layers that + * are not represented in the non-default ruleset. + */ + for (rule = nrules->rule; rule; rule = rule->next) + if (lefl2->type == rule->lefInfo->type) + break; + if (rule != NULL) continue; + fprintf(f, "\n + LAYER %s WIDTH %.10g WIREEXT %.10g", + lefl2->canonName, + (float)(lefl2->info.route.width) * scale, + (float)(lefl2->info.route.width) * scale / 2.0); + } + } + + /* Put the reference counts back to the way they were */ + HashStartSearch(&hs2); + while (he2 = HashNext(&LefInfo, &hs2)) + { + lefl2 = (lefLayer *)HashGetValue(he2); + if (lefl2->refCnt < 0) + lefl2->refCnt = -lefl2->refCnt; + } + } + } + + for (rule = nrules->rule; rule; rule = rule->next) + { + fprintf(f, "\n + 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); + if (nrules->rule->extend > 0) + fprintf(f, " WIREEXT %.10g", (float)nrules->rule->extend / 2.0); + } fprintf(f, " ;\n"); } fprintf(f, "END NONDEFAULTRULES\n\n"); diff --git a/lef/lefCmd.c b/lef/lefCmd.c index dd13d00a..66184559 100644 --- a/lef/lefCmd.c +++ b/lef/lefCmd.c @@ -132,6 +132,16 @@ CmdLef(w, cmd) * the DEF file should be ignored; only * mask geometry will be generated. */ + bool defAnalRetentive = FALSE; /* Deal with situations where tools + * have interpreted ambiguities in the + * LEF/DEF spec in the most stupid way + * possible, and then coded the rule + * in such a way that the tool crashes + * because the developers did not + * entertain the idea that a more + * sensible interpretation was possible. + */ + static char *cmdLefOption[] = { "read [filename] read a LEF file filename[.lef]\n" @@ -366,7 +376,7 @@ CmdLef(w, cmd) else TxPrintf("The \"-nomaster\" option is only for lef write\n"); } - else if (!strncmp(cmd->tx_argv[i], "-units", 5)) + else if (!strncmp(cmd->tx_argv[i], "-units", 6)) { if (is_lef) TxPrintf("The \"-units\" option is only for def write\n"); @@ -385,6 +395,13 @@ CmdLef(w, cmd) } } } + else if (!strncmp(cmd->tx_argv[i], "-anal", 5)) + { + if (is_lef) + TxPrintf("The \"-anal\" option is only for def write\n"); + else + defAnalRetentive = TRUE; + } else goto wrongNumArgs; cargs--; } @@ -402,7 +419,8 @@ CmdLef(w, cmd) else namep = cmd->tx_argv[2]; if (!is_lef) - DefWriteCell(selectedUse->cu_def, namep, allSpecial, units); + DefWriteCell(selectedUse->cu_def, namep, allSpecial, units, + defAnalRetentive); else LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def == EditRootDef, lefTech, lefHide, lefPinOnly,