/* * lefTech.c -- * * This module incorporates the LEF/DEF format for standard-cell place and * route. Defines technology file layer mapping between LEF and magic layer * types. * * Version 0.1 (December 5, 2003): LEF section of the technology file. * Lets the technology file state how layers declared in the LEF and DEF * files should correspond to magic layout units. If these are not * declared, magic will attempt to relate layer names in the LEF file to * magic layer names and their aliases. The LEF section allows the declaration * of obstruction layer names, which may be the same as actual layer names in * the LEF or DEF file, but which should declare a type that takes up space * on the routing plane but does not connect to any other material. Otherwise, * some LEF/DEF files will end up merging ports together with the obstruction * layer. * * Layer name case sensitivity should depend on the * NAMESCASESENSITIVE [ON|OFF] LEF instruction! */ #ifndef lint static const char rcsid[] __attribute__ ((unused)) = "$Header$"; #endif /* not lint */ #include #include #include #include "tcltk/tclmagic.h" #include "utils/magic.h" #include "utils/geometry.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "utils/malloc.h" #include "lef/lefInt.h" #include "drc/drc.h" #include "cif/cif.h" /* C99 compat */ #include "utils/tech.h" /* ---------------------------------------------------------------------*/ /* Layer and Via routing information table. */ HashTable LefInfo; /* Non-default rule table (currently used only by DEF read/write) */ HashTable LefNonDefaultRules; /* *----------------------------------------------------------------------------- * LefInit -- * * Things that need to be initialized on startup, before the technology * file is read in. * * Results: * None. * * Side effects: * Hash Table initialization. * *----------------------------------------------------------------------------- */ void LefInit(void) { /* Ensure that the table has a null entry so we don't run HashKill */ /* on it when we to the tech initialization. */ LefInfo.ht_table = (HashEntry **) NULL; LefNonDefaultRules.ht_table = (HashEntry **) NULL; } /* *----------------------------------------------------------------------------- * LefTechInit -- * * Called once at beginning of technology file read-in to initialize * data structures. * * Results: * None. * * Side effects: * Clears out the LEF layer info table. Because multiple LEF names * can point to the same record, this is handled by reference count. * ---------------------------------------------------------------------------- */ void LefTechInit(void) { HashSearch hs; HashEntry *he; lefLayer *lefl; if (LefInfo.ht_table != (HashEntry **) NULL) { HashStartSearch(&hs); while ((he = HashNext(&LefInfo, &hs))) { lefl = (lefLayer *)HashGetValue(he); if (!lefl) continue; lefl->refCnt--; if (lefl->refCnt <= 0) { /* Via detailed information, if it exists, */ /* needs to have its allocated memory free'd. */ if (lefl->lefClass == CLASS_VIA) if (lefl->info.via.lr != NULL) freeMagic(lefl->info.via.lr); freeMagic(lefl); } } HashKill(&LefInfo); HashKill(&LefNonDefaultRules); } HashInit(&LefInfo, 32, HT_STRINGKEYS); HashInit(&LefNonDefaultRules, 32, HT_STRINGKEYS); lefCurrentLine = -1; } /* *----------------------------------------------------------------------------- * lefRemoveGeneratedVias -- * * Remove the Generated Vias created during a DEF file write * from the LEF layer hash table. By design, each of these * generated layers gets a refCnt of zero, so they are easy * to find. * * Results: * None. * * Side effects: * Memory freed in the hash table. * *----------------------------------------------------------------------------- */ void lefRemoveGeneratedVias(void) { HashSearch hs; HashEntry *he; lefLayer *lefl; if (LefInfo.ht_table != (HashEntry **) NULL) { HashStartSearch(&hs); while ((he = HashNext(&LefInfo, &hs))) { lefl = (lefLayer *)HashGetValue(he); if (!lefl) continue; if (lefl->refCnt == 0) { if (lefl->lefClass == CLASS_VIA) if (lefl->info.via.lr != NULL) freeMagic(lefl->info.via.lr); freeMagic(lefl); HashSetValue(he, NULL); } } } } /* *----------------------------------------------------------------------------- * LefTechLine -- * * This procedure is invoked by the technology module once for * each line in the "lef" section of the technology file. * * Results: * Always returns TRUE (otherwise the technology module would * abort Magic with a fatal error). * * Side effects: * Builds up the LEF layer table, prints error messages if necessary. * ---------------------------------------------------------------------------- */ #define LEFTECH_OBS 0 #define LEFTECH_LAYER 1 #define LEFTECH_ROUTE 2 #define LEFTECH_ROUTING 3 #define LEFTECH_MASTER 4 #define LEFTECH_CUT 5 #define LEFTECH_CONTACT 6 #define LEFTECH_OVERLAP 7 #define LEFTECH_BOUND 8 #define LEFTECH_IGNORE 9 bool LefTechLine( const char *sectionName, /* Name of this section (unused). */ int argc, /* Number of arguments on line. */ char *argv[]) /* Pointers to fields of line. */ { bool isObstruction, isContact, isInactive; HashEntry *he; TileType mtype, mtype2 = -1; TileTypeBitMask mmask; lefLayer *lefl, *newlefl; int i, option; static const char * const keywords[] = { "obstruction", "layer", "route", "routing", "masterslice", "cut", "contact", "overlap", "bound", "ignore", NULL }; option = Lookup(argv[0], keywords); if (option < 0) { TechError("Unknown LEF section keyword: %s. Line ignored.\n", argv[0]); return TRUE; } if ((option != LEFTECH_IGNORE) && (argc < 3)) { TechError("No LEF layer names present!\n"); return TRUE; } isInactive = FALSE; switch (option) { case LEFTECH_IGNORE: isInactive = TRUE; break; case LEFTECH_OBS: isObstruction = TRUE; break; default: isObstruction = FALSE; } TTMaskZero(&mmask); i = 0; if (!isInactive) { DBTechNoisyNameMask(argv[1], &mmask); for (mtype2 = TT_TECHDEPBASE; mtype2 < DBNumUserLayers; mtype2++) { if (TTMaskHasType(&mmask, mtype2)) { if (++i == 1) mtype = mtype2; else break; } } if (mtype2 == DBNumUserLayers) mtype2 = -1; if (i == 0) { TechError("Bad magic layer type \"%s\" in LEF layer definition.\n", argv[1]); return TRUE; } else if ((i == 2) && (option != LEFTECH_OBS)) { TechError("Can only define multiple types for via obstruction layers.\n"); return TRUE; } else if (i > 2) { TechError("Too many types in LEF layer definition.\n"); return TRUE; } isContact = DBIsContact(mtype); if (option == LEFTECH_LAYER) option = (isContact) ? LEFTECH_CUT : LEFTECH_ROUTE; else if (isContact && (option != LEFTECH_CUT && option != LEFTECH_CONTACT && option != LEFTECH_OBS)) TechError("Attempt to define cut type %s as %s.\n", DBTypeLongNameTbl[mtype], keywords[option]); else if (!isContact && (option == LEFTECH_CUT || option == LEFTECH_CONTACT)) TechError("Attempt to define non-cut type %s as a cut.\n", DBTypeLongNameTbl[mtype]); } /* All other aliases are stuffed in the hash table but point to the */ /* same record as the first. If any name is repeated, then report */ /* an error condition. */ newlefl = NULL; for (i = 2 - isInactive; i < argc; i++) { he = HashFind(&LefInfo, argv[i]); lefl = (lefLayer *)HashGetValue(he); if (lefl == NULL) { /* Create an entry in the hash table for this layer or obstruction */ if (newlefl == NULL) { float oscale = CIFGetOutputScale(1000); /* FIXME unused return value from call to function with no side-effects */ newlefl = (lefLayer *)mallocMagic(sizeof(lefLayer)); newlefl->refCnt = 0; newlefl->type = -1; newlefl->obsType = -1; if (!isInactive) { if (isObstruction) newlefl->obsType = mtype; else newlefl->type = mtype; } newlefl->canonName = (const char *)he->h_key.h_name; /* "isObstruction" records whether the type is an */ /* obstruction or not. So recast the option to a route */ /* or a contact and handle accordingly. */ if (option == LEFTECH_OBS) option = (isContact) ? LEFTECH_CONTACT : LEFTECH_ROUTE; /* Fill in default values per type */ switch (option) { case LEFTECH_CUT: newlefl->lefClass = CLASS_VIA; newlefl->info.via.area = GeoNullRect; newlefl->info.via.cell = (CellDef *)NULL; newlefl->info.via.lr = (LinkedRect *)NULL; newlefl->info.via.obsType = mtype2; break; case LEFTECH_CONTACT: newlefl->lefClass = CLASS_VIA; newlefl->info.via.area.r_xbot = -1; newlefl->info.via.area.r_ybot = -1; newlefl->info.via.area.r_xtop = -1; newlefl->info.via.area.r_ytop = -1; /* To be filled */ newlefl->info.via.cell = (CellDef *)NULL; newlefl->info.via.lr = (LinkedRect *)NULL; newlefl->info.via.obsType = mtype2; break; case LEFTECH_ROUTE: case LEFTECH_ROUTING: newlefl->lefClass = CLASS_ROUTE; /* Set provisional width (to be removed) */ newlefl->info.route.width = DRCGetDefaultLayerWidth(mtype); if (newlefl->info.route.width == 0) newlefl->info.route.width = DEFAULT_WIDTH; else newlefl->info.route.width = -1; /* To be filled */ /* Set provisional spacing (to be removed) */ newlefl->info.route.spacing = DRCGetDefaultLayerSpacing(mtype, mtype); if (newlefl->info.route.spacing == 0) newlefl->info.route.spacing = DEFAULT_SPACING; else newlefl->info.route.spacing = -1; /* To be filled */ newlefl->info.route.pitch = 0; newlefl->info.route.hdirection = TRUE; break; case LEFTECH_BOUND: newlefl->lefClass = CLASS_BOUND; break; case LEFTECH_MASTER: newlefl->lefClass = CLASS_MASTER; break; case LEFTECH_OVERLAP: newlefl->lefClass = CLASS_OVERLAP; break; case LEFTECH_IGNORE: newlefl->lefClass = CLASS_IGNORE; break; } } HashSetValue(he, newlefl); newlefl->refCnt++; } else if (lefl->lefClass != CLASS_IGNORE) { if ((lefl->obsType == -1) && isObstruction) { lefl->obsType = mtype; if (lefl->lefClass == CLASS_VIA) lefl->info.via.obsType = mtype2; } else if ((lefl->type == -1) && !isObstruction) lefl->type = mtype; else TechError("LEF name %s already used for magic type %s\n", argv[i], DBTypeLongNameTbl[lefl->type]); } } return TRUE; } /* *----------------------------------------------------------------------------- * LefTechScale -- * * Change parameters of the LEF section as required when * redefining magic's internal grid relative to the technology lambda. * * ---------------------------------------------------------------------------- */ void LefTechScale( int scalen, int scaled) { HashSearch hs; HashEntry *he; lefLayer *lefl; if (LefInfo.ht_table != (HashEntry **) NULL) { HashStartSearch(&hs); while ((he = HashNext(&LefInfo, &hs))) { lefl = (lefLayer *)HashGetValue(he); if (!lefl) continue; if (lefl->refCnt >= 1) { /* Avoid scaling more than once. . . */ if (lefl->refCnt > 1) lefl->refCnt = -lefl->refCnt; if (lefl->lefClass == CLASS_VIA) { DBScalePoint(&lefl->info.via.area.r_ll, scaled, scalen); DBScalePoint(&lefl->info.via.area.r_ur, scaled, scalen); } else if (lefl->lefClass == CLASS_ROUTE) { lefl->info.route.width *= scaled; lefl->info.route.width /= scalen; lefl->info.route.spacing *= scaled; lefl->info.route.spacing /= scalen; lefl->info.route.pitch *= scaled; lefl->info.route.pitch /= scalen; } } } /* Return all refCnt values to normal */ HashStartSearch(&hs); while ((he = HashNext(&LefInfo, &hs))) { lefl = (lefLayer *)HashGetValue(he); if (!lefl) continue; if (lefl->refCnt < 0) lefl->refCnt = -lefl->refCnt; } } } /* *----------------------------------------------------------------------------- * LefTechSetDefaults -- * * Change parameters of the LEF section after scaling (see above) * to set default values for each route and contact layer (width and * spacing have been set to -1). This is because the value is in * lambda, and calling the DRC defaults before scaling can produce * a rounded value which is then incorrect when scaled. * * ---------------------------------------------------------------------------- */ void LefTechSetDefaults(void) { HashSearch hs; HashEntry *he; lefLayer *lefl; if (LefInfo.ht_table != (HashEntry **) NULL) { HashStartSearch(&hs); while ((he = HashNext(&LefInfo, &hs))) { lefl = (lefLayer *)HashGetValue(he); if (!lefl) continue; if (lefl->lefClass == CLASS_VIA) { if ((lefl->info.via.area.r_xbot == -1) && (lefl->info.via.area.r_ybot == -1) && (lefl->info.via.area.r_xtop == -1) && (lefl->info.via.area.r_ytop == -1)) { lefl->info.via.area.r_xtop = DRCGetDefaultLayerWidth(lefl->type); lefl->info.via.area.r_ytop = lefl->info.via.area.r_xtop; lefl->info.via.area.r_xbot = -lefl->info.via.area.r_xtop; lefl->info.via.area.r_ybot = -lefl->info.via.area.r_ytop; } } else if (lefl->lefClass == CLASS_ROUTE) { if (lefl->info.route.width == -1) lefl->info.route.width = DRCGetDefaultLayerWidth(lefl->type); if (lefl->info.route.spacing == -1) lefl->info.route.width = DRCGetDefaultLayerSpacing(lefl->type, lefl->type); } } } }