/* * ExtTech.c -- * * Circuit extraction. * Code to read and process the sections of a technology file * that are specific to circuit extraction. * * ********************************************************************* * * Copyright (C) 1985, 1990 Regents of the University of California. * * * Permission to use, copy, modify, and distribute this * * * software and its documentation for any purpose and without * * * fee is hereby granted, provided that the above copyright * * * notice appear in all copies. The University of California * * * makes no representations about the suitability of this * * * software for any purpose. It is provided "as is" without * * * express or implied warranty. Export of this software outside * * * of the United States of America may require an export license. * * ********************************************************************* */ #ifndef lint static char sccsid[] = "@(#)ExtTech.c 4.8 MAGIC (Berkeley) 10/26/85"; #endif #include #include #ifdef SYSV #include #endif #include "misc/magic.h" #include "utils/utils.h" #include "utils/geometry.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "database/databaseInt.h" #include "utils/malloc.h" #include "textio/textio.h" #include "tech/tech.h" #include "debug/debug.h" #include "extract/extract.h" #include "extract/extractInt.h" #include "cif/CIFint.h" /* Current extraction style */ ExtStyle *ExtCurStyle = NULL; /* List of all styles */ ExtStyle *ExtAllStyles = NULL; /* * Table used for parsing the extract section of a .tech file * Each line in the extract section is of a type determined by * its first keyword. There is one entry in the following table * for each such keyword. */ typedef enum { AREAC, CONTACT, CSCALE, FET, FETRESIST, LAMBDA, OVERC, PERIMC, PLANEORDER, NOPLANEORDER, RESIST, RSCALE, SIDEHALO, SIDEOVERLAP, SIDEWALL, STEP, STYLE } Key; static struct keydesc { char *k_name; Key k_key; int k_minargs; int k_maxargs; char *k_usage; } keyTable[] = { "areacap", AREAC, 3, 3, "types capacitance", "contact", CONTACT, 4, 4, "type size resistance", "cscale", CSCALE, 2, 2, "capacitance-scalefactor", "fet", FET, 8, 9, "types terminal-types min-#-terminals name [subs-types] subs-node gscap gate-chan-cap", "fetresist", FETRESIST, 4, 4, "type region ohms-per-square", "lambda", LAMBDA, 2, 2, "units-per-lambda", "overlap", OVERC, 4, 5, "toptypes bottomtypes capacitance [shieldtypes]", "perimc", PERIMC, 4, 4, "intypes outtypes capacitance", "planeorder", PLANEORDER, 3, 3, "plane index", "noplaneordering", NOPLANEORDER, 1, 1, "(no arguments needed)", "resist", RESIST, 3, 3, "types resistance", "rscale", RSCALE, 2, 2, "resistance-scalefactor", "sidehalo", SIDEHALO, 2, 2, "halo(lambda)", "sideoverlap", SIDEOVERLAP, 5, 6, "intypes outtypes ovtypes capacitance [shieldtypes]", "sidewall", SIDEWALL, 6, 6, "intypes outtypes neartypes fartypes capacitance", "step", STEP, 2, 2, "size(lambda)", "style", STYLE, 2, 2, "stylename", 0 }; /* * ---------------------------------------------------------------------------- * * ExtSetStyle -- * * Set the current extraction style to 'name', or print * the available and current styles if 'name' is NULL. * * Results: * None. * * Side effects: * Just told you. * * ---------------------------------------------------------------------------- */ Void ExtSetStyle(name) char *name; { ExtStyle *style, *match; int length; if (name == NULL) goto badStyle; match = NULL; length = strlen(name); for (style = ExtAllStyles; style; style = style->exts_next) { if (strncmp(name, style->exts_name, length) == 0) { if (match != NULL) { TxError("Extraction style \"%s\" is ambiguous.\n", name); goto badStyle; } match = style; } } if (match != NULL) { ExtCurStyle = match; TxPrintf("Extraction style is now \"%s\"\n", name); return; } TxError("\"%s\" is not one of the extraction styles Magic knows.\n", name); badStyle: TxPrintf("The extraction styles are: "); for (style = ExtAllStyles; style; style = style->exts_next) { if (style == ExtAllStyles) TxPrintf("%s", style->exts_name); else TxPrintf(", %s", style->exts_name); } TxPrintf(".\n"); if (ExtCurStyle != NULL) TxPrintf("The current style is \"%s\".\n", ExtCurStyle->exts_name); } /* * ---------------------------------------------------------------------------- * * extTechStyleNew -- * * Allocate a new style with zeroed technology variables. * * Results: * Allocates a new ExtStyle and returns it. * * Side effects: * See above. * * ---------------------------------------------------------------------------- */ ExtStyle * extTechStyleNew(name) char *name; { ExtStyle *style; register TileType r, s; style = (ExtStyle *) mallocMagic(sizeof (ExtStyle)); style->exts_next = NULL; style->exts_name = StrDup((char **) NULL, name); style->exts_sidePlanes = style->exts_overlapPlanes = 0; TTMaskZero(&style->exts_transMask); for (r = 0; r < NP; r++) { TTMaskZero(&style->exts_sideTypes[r]); TTMaskZero(&style->exts_overlapTypes[r]); style->exts_planeOrder[r] = -1; } for (r = 0; r < NT; r++) { TTMaskZero(&style->exts_nodeConn[r]); TTMaskZero(&style->exts_resistConn[r]); TTMaskZero(&style->exts_transConn[r]); style->exts_allConn[r] = DBAllTypeBits; style->exts_sheetResist[r] = 0; style->exts_viaSize[r] = 0; style->exts_viaResist[r] = 0; style->exts_areaCap[r] = (CapValue) 0; style->exts_overlapOtherPlanes[r] = 0; TTMaskZero(&style->exts_overlapOtherTypes[r]); TTMaskZero(&style->exts_sideEdges[r]); for (s = 0; s < NT; s++) { TTMaskZero(&style->exts_sideCoupleOtherEdges[r][s]); TTMaskZero(&style->exts_sideOverlapOtherTypes[r][s]); style->exts_sideOverlapOtherPlanes[r][s] = 0; style->exts_sideCoupleCap[r][s] = (EdgeCap *) NULL; style->exts_sideOverlapCap[r][s] = (EdgeCap *) NULL; style->exts_perimCap[r][s] = (CapValue) 0; style->exts_overlapCap[r][s] = (CapValue) 0; TTMaskZero(&style->exts_overlapShieldTypes[r][s]); style->exts_overlapShieldPlanes[r][s] = 0; style->exts_sideOverlapShieldPlanes[r][s] = 0; } TTMaskZero(&style->exts_perimCapMask[r]); TTMaskZero(&style->exts_transSDTypes[r]); TTMaskZero(&style->exts_subsTransistorTypes[r]); style->exts_transSDCount[r] = 0; style->exts_transGateCap[r] = (CapValue) 0; style->exts_transSDCap[r] = (CapValue) 0; style->exts_transSubstrateName[r] = (char *) NULL; HashInit(&style->exts_transResist[r], 8, HT_STRINGKEYS); style->exts_linearResist[r] = 0; } style->exts_sideCoupleHalo = 0; style->exts_stepSize = 100; style->exts_unitsPerLambda = 100; style->exts_resistScale = 1000; style->exts_capScale = 1000; style->exts_numResistClasses = 0; style->exts_planeOrderStatus = needPlaneOrder ; for (r = 0; r < DBNumTypes; r++) { style->exts_resistByResistClass[r] = 0; TTMaskZero(&style->exts_typesByResistClass[r]); style->exts_typesResistChanged[r] = DBAllButSpaceAndDRCBits; TTMaskSetType(&style->exts_typesResistChanged[r], TT_SPACE); style->exts_typeToResistClass[r] = -1; } return (style); } /* * ---------------------------------------------------------------------------- * * aToCap -- * * Utility procedure for reading capacitance values. * * Returns: * A value of type CapValue. * * Side effects: * none. * ---------------------------------------------------------------------------- */ CapValue aToCap(str) char *str; { CapValue capVal; if (sscanf(str, "%lf", &capVal) != 1) { capVal = (CapValue) 0; TechError("Capacitance value %s must be a number\n", str); } return capVal; } /* * ---------------------------------------------------------------------------- * * ExtTechLine -- * * Process a line from the "extract" section of a technology file. * * Each line in the extract section of a technology begins * with a keyword that identifies the format of the rest of * the line. * * The following three kinds of lines are used to define the resistance * and parasitic capacitance to substrate of each tile type: * * resist types resistance * areacap types capacitance * perimcap inside outside capacitance * * where 'types', 'inside', and 'outside' are comma-separated lists * of tile types, 'resistance' is an integer giving the resistance * per square in milli-ohms, and 'capacitance' is an integer giving * capacitance (per square lambda for areacap, or per lambda perimeter * for perimcap) in attofarads. * * The perimeter (sidewall) capacitance depends both on the types * inside and outside the perimeter. For a given 'perimcap' line, * any segment of perimeter with a type in 'inside' inside the * perimeter and a type in 'outside' ontside the perimeter will * have the indicated capacitance. * * Both area and perimeter capacitance computed from the information * above apply between a given node and the substrate beneath it, as * determined by extSubstrate[]. * * Contact resistances are specified by: * * contact type minsize resistance * * where type is the type of contact tile, minsize is chosen so that contacts * that are integer multiples of minsize get an additional contact cut for each * increment of minsize, and resistance is in milliohms. * * +++ FOR NOW, CONSIDER ALL SUBSTRATE TO BE AT GROUND +++ * * Overlap coupling capacitance is specified by: * * overlap toptypes bottomtypes capacitance [shieldtypes] * * where 'toptypes' and 'bottomtypes' are comma-separated lists of tile types, * and 'capacitance' is an integer giving capacitance in attofarads per * square lambda of overlap. The sets 'toptypes' and 'bottomtypes' should * be disjoint. Also, the union of the planes of 'toptypes' should be disjoint * from the union of the planes of 'bottomtypes'. If 'shieldtypes' are * present, they should also be a comma-separated list of types, on * planes disjoint from those of either 'toptypes' or 'bottomtypes'. * * Whenever a tile of a type in 'toptypes' overlaps one of a type in * 'bottomtypes', we deduct the capacitance to substrate of the 'toptypes' * tile for the area of the overlap, and create an overlap capacitance * between the two nodes based on 'capacitance'. When material in * 'shieldtypes' appears over any of this overlap area, however, we * only deduct the substrate capacitance; we don't create an overlap * capacitor. * * Sidewall coupling capacitance is specified by: * * sidewall intypes outtypes neartypes fartypes capacitance * * where 'intypes', 'outtypes', 'neartypes', and 'fartypes' are all comma- * separated lists of types, and 'capacitance' is an integer giving capacitance * in attofarads. All of the tiles in all four lists should be on the same * plane. * * Whenever an edge of the form i|j is seen, where 'i' is in intypes and * 'j' is in outtypes, we search on the 'j' side for a distance of * ExtCurStyle->exts_sideCoupleHalo for edges with 'neartypes' on the * close side and 'fartypes' on the far side. We create a capacitance * equal to the length of overlap, times capacitance, divided by the * separation between the edges (poor approximation, but better than * none). * * Sidewall overlap coupling capacitance is specified by: * * sideoverlap intypes outtypes ovtypes capacitance * * where 'intypes', 'outtypes', and 'ovtypes' are comma-separated lists * of types, and 'capacitance' is an integer giving capacitance in attofarads * per lambda. Both intypes and outtypes should be in the same plane, and * ovtypes should be in a different plane from intypes and outtypes. * * The next kind of line describes transistors: * * fet types terminals min-#terminals names substrate gscap gccap * * where 'types' and 'terminals' are comma-separated lists of tile types. * The meaning is that each type listed in 'types' is a transistor, whose * source and drain connect to any of the types listed in 'terminals'. * These transistors must have exactly min-#terminals terminals, in addition * to the gate (whose connectivity is specified in the system-wide connectivity * table in the "connect" section of the .tech file). Currently gscap and * gccap are unused, but refer to the gate-source (or gate-drain) capacitance * and the gate-channel capacitance in units of attofarads per lambda and * attofarads per square lambda respectively. * * The resistances of transistors is specified by: * * fetresist type region ohms * * where type is a type of tile that is a fet, region is a string ("linear" * is treated specially), and ohms is the resistance per square of the fet * type while operating in "region". The values of fets in the "linear" * region are stored in a separate table. * * Results: * Returns TRUE normally, or FALSE if the line from the * technology file is so malformed that Magic should abort. * Currently, we always return TRUE. * * Side effects: * Initializes the per-technology variables that appear at the * beginning of this file. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ bool ExtTechLine(sectionName, argc, argv) char *sectionName; int argc; char *argv[]; { int n, size, val, p1, p2, p3, nterm, pov, pshield, class; CapValue capVal, gscap, gccap; TileTypeBitMask types1, types2, near, far, ov, shield, subsTypes; char *subsName, *transName, *cp; register TileType s, t, r, o; struct keydesc *kp; bool isLinear; HashEntry *he; EdgeCap *cnew; ExtStyle *es; bool bad; if (argc < 1) { TechError("Each line must begin with a keyword\n"); return (TRUE); } n = LookupStruct(argv[0], (LookupTable *) keyTable, sizeof keyTable[0]); if (n < 0) { TechError("Illegal keyword. Legal keywords are:\n\t"); for (n = 0; keyTable[n].k_name; n++) TxError(" %s", keyTable[n].k_name); TxError("\n"); return (TRUE); } kp = &keyTable[n]; if (argc < kp->k_minargs || argc > kp->k_maxargs) goto usage; if (kp->k_key == STYLE) { ExtCurStyle = extTechStyleNew(argv[1]); if (ExtAllStyles == NULL) ExtAllStyles = ExtCurStyle; else { /* Append to end of style list */ for (es = ExtAllStyles; es->exts_next; es = es->exts_next) /* Nothing */; es->exts_next = ExtCurStyle; } return (TRUE); } if (ExtCurStyle == NULL) { TechError( "No extraction style declared: starting new style \"default\".\n"); ExtCurStyle = extTechStyleNew("default"); ExtAllStyles = ExtCurStyle; } switch (kp->k_key) { case AREAC: case CONTACT: case FET: case FETRESIST: case OVERC: case PERIMC: case RESIST: case SIDEWALL: case SIDEOVERLAP: DBTechNoisyNameMask(argv[1], &types1); break; case PLANEORDER: case NOPLANEORDER: default: break; } switch (kp->k_key) { case AREAC: capVal = aToCap(argv[2]); for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) if (TTMaskHasType(&types1, t)) ExtCurStyle->exts_areaCap[t] = capVal; break; case CONTACT: if (!StrIsInt(argv[2])) { TechError("Contact minimum size %s must be numeric\n", argv[2]); break; } if (!StrIsInt(argv[3])) { TechError("Contact resistivity %s must be numeric\n", argv[3]); break; } size = atoi(argv[2]); val = atoi(argv[3]); for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) if (TTMaskHasType(&types1, t)) { ExtCurStyle->exts_viaSize[t] = size; ExtCurStyle->exts_viaResist[t] = val; } break; case CSCALE: ExtCurStyle->exts_capScale = atoi(argv[1]); break; case FET: DBTechNoisyNameMask(argv[2], &types2); nterm = atoi(argv[3]); transName = argv[4]; subsName = argv[5]; cp = index(subsName, '!'); if (cp == NULL || cp[1] != '\0') { TechError("Fet substrate node %s is not a global name\n", subsName); } subsTypes = DBZeroTypeBits; if (sscanf(argv[6], "%lf", &capVal) != 1) { DBTechNoisyNameMask(argv[6], &subsTypes); gscap = aToCap(argv[7]); gccap = (argc > 8) ? aToCap(argv[8]) : (CapValue) 0; } else { gscap = aToCap(argv[6]); gccap = (argc > 7) ? aToCap(argv[7]) : (CapValue) 0; } TTMaskSetMask(&ExtCurStyle->exts_transMask, &types1); for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) if (TTMaskHasType(&types1, t)) { TTMaskSetMask(ExtCurStyle->exts_transConn+t,&types1); ExtCurStyle->exts_transSDTypes[t] = types2; ExtCurStyle->exts_transSDCount[t] = nterm; ExtCurStyle->exts_transSDCap[t] = gscap; ExtCurStyle->exts_transGateCap[t] = gccap; ExtCurStyle->exts_transName[t] = StrDup((char **) NULL, transName); ExtCurStyle->exts_transSubstrateName[t] = StrDup((char **) NULL, subsName); ExtCurStyle->exts_transSubstrateTypes[t] = subsTypes; { int z; for (z= TT_TECHDEPBASE; z < DBNumTypes;z++) { if (TTMaskHasType(&subsTypes,z)) TTMaskSetType(&ExtCurStyle->exts_subsTransistorTypes[z],t); } } } break; case FETRESIST: if (!StrIsInt(argv[3])) { TechError("Fet resistivity %s must be numeric\n", argv[3]); break; } val = atoi(argv[3]); isLinear = (strcmp(argv[2], "linear") == 0); for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) if (TTMaskHasType(&types1, t)) { he = HashFind(&ExtCurStyle->exts_transResist[t], argv[2]); HashSetValue(he, val); if (isLinear) ExtCurStyle->exts_linearResist[t] = val; } break; case LAMBDA: ExtCurStyle->exts_unitsPerLambda = atoi(argv[1]); break; case OVERC: DBTechNoisyNameMask(argv[2], &types2); capVal = aToCap(argv[3]); bad = FALSE; shield = DBZeroTypeBits; if (argc > 4) DBTechNoisyNameMask(argv[4], &shield); for (s = TT_TECHDEPBASE; s < DBNumTypes; s++) { if (!TTMaskHasType(&types1, s)) continue; for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) { if (!TTMaskHasType(&types2, t)) continue; if (s == t) { TechError( "Can't have overlap capacitance between tiles of the same type (%s)\n", DBTypeLongName(s)); bad = TRUE; continue; } p1 = DBPlane(s), p2 = DBPlane(t); if (p1 == p2) { TechError( "Can't have overlap capacitance between tiles on the same plane (%s, %s)\n", DBTypeLongName(s), DBTypeLongName(t)); bad = TRUE; continue; } if ((ExtCurStyle->exts_overlapCap[s][t]) != (CapValue) 0) { TechError( "Only one of \"overlap %s %s\" or \"overlap %s %s\" allowed\n", DBTypeLongName(s), DBTypeLongName(t), DBTypeLongName(t), DBTypeLongName(s)); bad = TRUE; continue; } ExtCurStyle->exts_overlapCap[s][t] = capVal; ExtCurStyle->exts_overlapPlanes |= PlaneNumToMaskBit(p1); ExtCurStyle->exts_overlapOtherPlanes[s] |= PlaneNumToMaskBit(p2); TTMaskSetType(&ExtCurStyle->exts_overlapTypes[p1], s); TTMaskSetType(&ExtCurStyle->exts_overlapOtherTypes[s], t); if (argc == 4) continue; /* Shielding */ pshield = 0; for (r = TT_TECHDEPBASE; r < DBNumTypes; r++) { if (TTMaskHasType(&shield, r)) { p3 = DBPlane(r); if (p3 == p1 || p3 == p2) { TechError( "Shielding type (%s) must be on a different plane from shielded types.\n", DBTypeLongName(r)); bad = TRUE; continue; } pshield |= PlaneNumToMaskBit(p3); } } ExtCurStyle->exts_overlapShieldPlanes[s][t] = pshield; ExtCurStyle->exts_overlapShieldTypes[s][t] = shield; } } if (bad) return (TRUE); break; case SIDEOVERLAP: bad = FALSE; DBTechNoisyNameMask(argv[2], &types2); DBTechNoisyNameMask(argv[3], &ov); pov = extTechTypesToPlanes(&ov); capVal = aToCap(argv[4]); shield = DBZeroTypeBits; if (argc == 6) DBTechNoisyNameMask(argv[5], &shield); p3 = -1; if (TTMaskHasType(&types1, TT_SPACE)) TechError("Can't have space on inside of edge [ignored]\n"); /* It's ok to have the overlap be to space as long as a plane is */ /* specified. */ if (TTMaskHasType(&ov, TT_SPACE)) { if ((cp = index(argv[3],'/')) == NULL) { TechError("Must specify plane for sideoverlap to space\n"); } cp++; p3 = (int) dbTechNameLookup(cp, &dbPlaneNameLists); if (p3 < 0) { TechError("Unknown overlap plane %s\n",argv[3]); } } for (s = TT_TECHDEPBASE; s < DBNumTypes; s++) { if (!TTMaskHasType(&types1, s)) continue; p1 = DBPlane(s); if (PlaneMaskHasPlane(pov, p1)) goto diffplane; ExtCurStyle->exts_sidePlanes |= PlaneNumToMaskBit(p1); TTMaskSetType(&ExtCurStyle->exts_sideTypes[p1], s); TTMaskSetMask(&ExtCurStyle->exts_sideEdges[s], &types2); for (t = 0; t < DBNumTypes; t++) { if (!TTMaskHasType(&types2, t)) continue; p2 = DBPlane(t); if (t != TT_SPACE && PlaneMaskHasPlane(pov, p2)) goto diffplane; TTMaskSetMask(&ExtCurStyle->exts_sideOverlapOtherTypes[s][t], &ov); ExtCurStyle->exts_sideOverlapOtherPlanes[s][t] |= pov; MALLOC(EdgeCap *, cnew, sizeof (EdgeCap)); cnew->ec_cap = capVal; cnew->ec_far = shield; /* Really types that shield */ cnew->ec_near = ov; /* Really types we create cap with */ cnew->ec_plane = p3; cnew->ec_next = ExtCurStyle->exts_sideOverlapCap[s][t]; ExtCurStyle->exts_sideOverlapCap[s][t] = cnew; /* Shielding */ pshield = 0; for (r = TT_TECHDEPBASE; r < DBNumTypes; r++) { if (TTMaskHasType(&shield, r)) { p3 = DBPlane(r); if (p3 == p1 || p3 == p2) { TechError( "Shielding type (%s) must be on a different plane from shielded types.\n", DBTypeLongName(r)); bad = TRUE; continue; } pshield |= PlaneNumToMaskBit(p3); } } for (o = TT_TECHDEPBASE; o < DBNumTypes; o++) { if (TTMaskHasType(&ov, o)) { ExtCurStyle->exts_sideOverlapShieldPlanes[s][o] |= pshield; } } } } if (bad) return (TRUE); break; case SIDEWALL: DBTechNoisyNameMask(argv[2], &types2); DBTechNoisyNameMask(argv[3], &near); DBTechNoisyNameMask(argv[4], &far); if (TTMaskHasType(&types1, TT_SPACE)) TechError("Can't have space on inside of edge [ignored]\n"); capVal = aToCap(argv[5]); for (s = TT_TECHDEPBASE; s < DBNumTypes; s++) { if (!TTMaskHasType(&types1, s)) continue; ExtCurStyle->exts_sidePlanes |= PlaneNumToMaskBit(DBPlane(s)); TTMaskSetType(&ExtCurStyle->exts_sideTypes[DBPlane(s)], s); TTMaskSetMask(&ExtCurStyle->exts_sideEdges[s], &types2); for (t = 0; t < DBNumTypes; t++) { if (!TTMaskHasType(&types2, t)) continue; TTMaskSetMask(&ExtCurStyle->exts_sideCoupleOtherEdges[s][t], &far); MALLOC(EdgeCap *, cnew, sizeof (EdgeCap)); cnew->ec_cap = capVal; cnew->ec_near = near; cnew->ec_far = far; cnew->ec_next = ExtCurStyle->exts_sideCoupleCap[s][t]; cnew->ec_plane = -1; ExtCurStyle->exts_sideCoupleCap[s][t] = cnew; } } break; case SIDEHALO: ExtCurStyle->exts_sideCoupleHalo = atoi(argv[1]); break; case PERIMC: DBTechNoisyNameMask(argv[2], &types2); capVal = aToCap(argv[3]); if (capVal == (CapValue) 0) break; for (s = TT_TECHDEPBASE; s < DBNumTypes; s++) for (t = 0; t < DBNumTypes; t++) if (TTMaskHasType(&types1, s) && TTMaskHasType(&types2, t)) { ExtCurStyle->exts_perimCap[s][t] = capVal; TTMaskSetType(&ExtCurStyle->exts_perimCapMask[s], t); } break; case RESIST: val = atoi(argv[2]); class = ExtCurStyle->exts_numResistClasses++; for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) if (TTMaskHasType(&types1, t)) { ExtCurStyle->exts_sheetResist[t] = val; ExtCurStyle->exts_typeToResistClass[t] = class; } ExtCurStyle->exts_resistByResistClass[class] = val; ExtCurStyle->exts_typesByResistClass[class] = types1; break; case RSCALE: ExtCurStyle->exts_resistScale = atoi(argv[1]); break; case STEP: val = atoi(argv[1]); if (val <= 0) { TechError("Hierarchical interaction step size must be > 0\n"); return (FALSE); } ExtCurStyle->exts_stepSize = val; break; case NOPLANEORDER: { if ( ExtCurStyle->exts_planeOrderStatus == seenPlaneOrder ) TechError("\"noplaneordering\" specified after \"planeorder\".\n"); else ExtCurStyle->exts_planeOrderStatus = noPlaneOrder ; } break ; case PLANEORDER: { int pnum = (int) dbTechNameLookup(argv[1], &dbPlaneNameLists); int pos = atoi(argv[2]); if ( ExtCurStyle->exts_planeOrderStatus == noPlaneOrder ) { TechError("\"planeorder\" specified after \"noplaneordering\".\n"); } ExtCurStyle->exts_planeOrderStatus = seenPlaneOrder ; if (pnum < 0) TechError("Unknown planeorder plane %s\n", argv[1]); else if (pos < 0 || pos >= DBNumPlanes-PL_TECHDEPBASE) TechError("Planeorder index must be [0..%d]\n", DBNumPlanes-PL_TECHDEPBASE-1); else ExtCurStyle->exts_planeOrder[pnum] = pos; } break; } return (TRUE); usage: TechError("Malformed line for keyword %s. Correct usage:\n\t%s %s\n", kp->k_name, kp->k_name, kp->k_usage); return (TRUE); diffplane: TechError("Overlapped types in \"sideoverlap\" rule must be on\n\ \tdifferent plane from intypes and outtypes.\n"); return (TRUE); } /* * ---------------------------------------------------------------------------- * * extTechTypesToPlanes -- * * Like DBTechTypesToPlanes, but makes sure that TT_SPACE is turned off in * its argument mask. * * Results: * Returns a mask of the planes occupied by the types in the * mask pointed to by 'm'. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ extTechTypesToPlanes(m) TileTypeBitMask *m; { TileTypeBitMask mnew; mnew = *m; TTMaskClearType(&mnew, TT_SPACE); return (DBTechTypesToPlanes(&mnew)); } /* * ---------------------------------------------------------------------------- * * ExtTechFinal -- * * Postprocess the technology specific information for extraction. * Builds the connectivity tables exts_nodeConn[], exts_resistConn[], * and exts_transConn[]. * * Results: * None. * * Side effects: * Initializes the tables mentioned above. * Leaves ExtCurStyle pointing to the first style in the list * ExtAllStyles. * * ---------------------------------------------------------------------------- */ Void ExtTechFinal() { ExtStyle *es; /* Create a "default" style if there isn't one */ if (ExtAllStyles == NULL) { ExtCurStyle = extTechStyleNew("default"); ExtAllStyles = ExtCurStyle; } /* Final cleanup for all styles */ for (es = ExtAllStyles; es; es = es->exts_next) extTechFinalStyle(es); /* The current style is initially the first style in the list */ ExtCurStyle = ExtAllStyles; TxPrintf("\n"); TxFlush(); } Void extTechFinalStyle(style) ExtStyle *style; { TileTypeBitMask maskBits; register TileType r, s, t; int p1, missing, conflict; int indicis[NP]; for (r = TT_TECHDEPBASE; r < DBNumTypes; r++) { maskBits = style->exts_nodeConn[r] = DBConnectTbl[r]; if (!TTMaskHasType(&style->exts_transMask, r)) { TTMaskZero(&style->exts_transConn[r]); } for (s = TT_TECHDEPBASE; s < DBNumTypes; s++) { if (TTMaskHasType(&maskBits, s)) if (style->exts_typeToResistClass[s] != style->exts_typeToResistClass[r]) TTMaskClearType(&maskBits, s); } style->exts_resistConn[r] = maskBits; } /* r ranges over types, s over resistance entries */ for (r = TT_TECHDEPBASE; r < DBNumTypes; r++) { s = style->exts_typeToResistClass[r]; if( s > 0 ) { TTMaskClearMask(&style->exts_typesResistChanged[r], &style->exts_typesByResistClass[s]); } } /* * Consistency check: * If a type R shields S from T, make sure that R is listed as * being in the list of overlapped types for S, even if there * was no overlap capacitance explicitly specified for this * pair of types in an "overlap" line. This guarantees that * R will shield S from substrate even if there is no capacitance * associated with the overlap. */ for (s = TT_TECHDEPBASE; s < DBNumTypes; s++) for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) { if (style->exts_overlapShieldPlanes[s][t] == 0) continue; for (r = TT_TECHDEPBASE; r < DBNumTypes; r++) { if (!TTMaskHasType(&style->exts_overlapShieldTypes[s][t], r)) continue; p1 = DBPlane(s); style->exts_overlapPlanes |= PlaneNumToMaskBit(p1); style->exts_overlapOtherPlanes[s] |= PlaneNumToMaskBit(DBPlane(r)); TTMaskSetType(&style->exts_overlapTypes[p1], s); TTMaskSetType(&style->exts_overlapOtherTypes[s], r); } } if ( style->exts_planeOrderStatus == noPlaneOrder ) return /* no need to check */ ; /* Else Check to make sure the plane order is a permutation of the numbers 0..DBNumPlanes-DBNumPlanes-1 */ for (p1 = PL_TECHDEPBASE; p1 < DBNumPlanes; p1++) { indicis[p1] = 0; } for (p1 = PL_TECHDEPBASE; p1 < DBNumPlanes; p1++) { int pn = style->exts_planeOrder[p1]+PL_TECHDEPBASE; if (pn >= PL_TECHDEPBASE && pn < DBNumPlanes) indicis[pn]++; } conflict = FALSE; missing = FALSE; for (p1 = PL_TECHDEPBASE; p1 < DBNumPlanes; p1++) { if (indicis[p1] > 1) conflict = TRUE ; if (indicis[p1] < 1) missing = TRUE ; } if (!conflict && !missing) return /* Everything was ok */ ; TxError ("\nWarning: Extraction Style %s\n", style -> exts_name); if (conflict) { TxError (" Conflicting planeorder for plane(s):\n "); for (p1 = PL_TECHDEPBASE; p1 < DBNumPlanes; p1++) { if (indicis[p1] > 1) TxError (" %s,", DBPlaneLongNameTbl[p1]); } TxError("\n"); } if (missing) { TxError (" Missing planeorder for plane(s):\n "); for (p1 = PL_TECHDEPBASE; p1 < DBNumPlanes; p1++) { if (indicis[p1] < 1) TxError (" %s,", DBPlaneLongNameTbl[p1]); } TxError("\n"); } TxError( " Magic will use the default planeorder for this style:\n "); for (p1 = PL_TECHDEPBASE; p1 < DBNumPlanes; p1++) { style->exts_planeOrder[p1] = p1 - PL_TECHDEPBASE ; TxError(" %s=%d,",DBPlaneLongNameTbl[p1], style->exts_planeOrder[p1]); } }