/* * DBtechtype.c -- * * Creation of tile and plane types and their names. * Lookup procedures are in DBtechname.c * * ********************************************************************* * * 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 rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBtechtype.c,v 1.2 2008/09/05 13:56:25 tim Exp $"; #endif /* not lint */ #include #include #include #include "utils/magic.h" #include "utils/geometry.h" #include "utils/utils.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "database/databaseInt.h" #include "utils/tech.h" #include "textio/textio.h" #include "utils/malloc.h" /* Types and their names */ int DBNumTypes; char *DBTypeLongNameTbl[NT]; int DBTypePlaneTbl[NT]; /* Normally accessed as macro "DBPlane(x)" */ NameList dbTypeNameLists = {NULL, NULL, NULL, (ClientData)0, FALSE}; HashTable DBTypeAliasTable; /* Planes and their names */ int DBNumPlanes; char *DBPlaneLongNameTbl[PL_MAXTYPES]; NameList dbPlaneNameLists = {NULL, NULL, NULL, (ClientData)0, FALSE}; /* * Sets of types. * These are generated after the "types" section of the * technology file has been read, but before any automatically * generated types (contact images) are created. */ int DBNumUserLayers; TileTypeBitMask DBZeroTypeBits; TileTypeBitMask DBAllTypeBits; TileTypeBitMask DBBuiltinLayerBits; TileTypeBitMask DBAllButSpaceBits; TileTypeBitMask DBAllButSpaceAndDRCBits; TileTypeBitMask DBSpaceBits; TileTypeBitMask DBUserLayerBits; TileTypeBitMask DBActiveLayerBits; /* Layers that are locked */ TileTypeBitMask DBTechActiveLayerBits; /* Layers marked locked in the techfile */ /* Table of default, builtin planes */ DefaultPlane dbTechDefaultPlanes[] = { {PL_ROUTER, "router"}, {PL_DRC_ERROR, "designRuleError"}, {PL_DRC_CHECK, "designRuleCheck"}, {PL_M_HINT, "mhint"}, {PL_F_HINT, "fhint"}, {PL_R_HINT, "rhint"}, {0, NULL} }; /* Table of default, builtin types */ DefaultType dbTechDefaultTypes[] = { {TT_SPACE, -1, "space", FALSE}, {TT_CHECKPAINT, PL_DRC_CHECK, "checkpaint,CP", FALSE}, {TT_CHECKSUBCELL, PL_DRC_CHECK, "checksubcell,CS", FALSE}, {TT_ERROR_P, PL_DRC_ERROR, "error_p,EP", FALSE}, {TT_ERROR_S, PL_DRC_ERROR, "error_s,ES", FALSE}, {TT_ERROR_PS, PL_DRC_ERROR, "error_ps,EPS", FALSE}, {TT_MAGNET, PL_M_HINT, "magnet,mag", TRUE}, {TT_FENCE, PL_F_HINT, "fence,f", TRUE}, {TT_ROTATE, PL_R_HINT, "rotate,r", TRUE}, {0, 0, NULL, 0} }; /* Forward declarations */ char *dbTechNameAdd(); NameList *dbTechNameAddOne(); /* * ---------------------------------------------------------------------------- * * DBTechInitPlane -- * * Initialize the default plane information. * * Results: * None. * * Side effects: * Initializes DBNumPlanes to PL_TECHDEPBASE. * Initializes DBPlaneLongNameTbl[] for builtin planes. * * ---------------------------------------------------------------------------- */ void DBTechInitPlane() { DefaultPlane *dpp; char *cp; /* Clear out any old information */ if (dbPlaneNameLists.sn_next != NULL) { NameList *tbl; for (tbl = dbPlaneNameLists.sn_next; tbl != &dbPlaneNameLists; tbl = tbl->sn_next) { freeMagic(tbl->sn_name); freeMagic(tbl); } } /* Tables of short names */ dbPlaneNameLists.sn_next = &dbPlaneNameLists; dbPlaneNameLists.sn_prev = &dbPlaneNameLists; for (dpp = dbTechDefaultPlanes; dpp->dp_names; dpp++) { cp = dbTechNameAdd(dpp->dp_names, INT2CD(dpp->dp_plane), &dbPlaneNameLists, FALSE); if (cp == NULL) { TxError("DBTechInit: can't add plane names %s\n", dpp->dp_names); niceabort(); } DBPlaneLongNameTbl[dpp->dp_plane] = cp; } DBNumPlanes = PL_TECHDEPBASE; } /* * ---------------------------------------------------------------------------- * * DBTypeInit -- * * Initialization routine for the types database on startup (runs only * once). * * Results: * None. * * Side effects: * Hash table initialization. * * ---------------------------------------------------------------------------- */ void DBTypeInit() { HashInit(&DBTypeAliasTable, 8, HT_STRINGKEYS); } /* * ---------------------------------------------------------------------------- * * DBTechInitType -- * * Add the names and planes of the builtin types. * * Results: * None. * * Side effects: * See above. * Initializes DBNumTypes to TT_TECHDEPBASE. * * ---------------------------------------------------------------------------- */ void DBTechInitType() { DefaultType *dtp; char *cp; /* Clear out any old information */ if (dbTypeNameLists.sn_next != NULL) { NameList *tbl; for (tbl = dbTypeNameLists.sn_next; tbl != &dbTypeNameLists; tbl = tbl->sn_next) { freeMagic(tbl->sn_name); freeMagic(tbl); } } /* Tables of short names */ dbTypeNameLists.sn_next = &dbTypeNameLists; dbTypeNameLists.sn_prev = &dbTypeNameLists; /* * Add the type names to the list of known names, and set * the default plane for each type. */ for (dtp = dbTechDefaultTypes; dtp->dt_names; dtp++) { cp = dbTechNameAdd(dtp->dt_names, INT2CD(dtp->dt_type), &dbTypeNameLists, FALSE); if (cp == NULL) { TxError("DBTechInit: can't add type names %s\n", dtp->dt_names); niceabort(); } DBTypeLongNameTbl[dtp->dt_type] = cp; DBPlane(dtp->dt_type) = dtp->dt_plane; TTMaskSetOnlyType(&DBLayerTypeMaskTbl[dtp->dt_type], dtp->dt_type); } /* Zero the active layers (this mask is inverted later) */ TTMaskZero(&DBActiveLayerBits); /* Hash table of layer aliases, free'ing the allocated type masks */ HashFreeKill(&DBTypeAliasTable); HashInit(&DBTypeAliasTable, 8, HT_STRINGKEYS); DBNumTypes = TT_TECHDEPBASE; } /* * ---------------------------------------------------------------------------- * * DBTechAddPlane -- * * Define a tile plane type for the new technology. * * Results: * TRUE if successful, FALSE on error * * Side effects: * Updates the database technology variables. * In particular, updates the number of known tile planes. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ bool DBTechAddPlane(sectionName, argc, argv) char *sectionName; int argc; char *argv[]; { char *cp; if (DBNumPlanes >= PL_MAXTYPES) { TechError("Too many tile planes (max=%d)\n", PL_MAXTYPES); return FALSE; } if (argc != 1) { TechError("Line must contain names for plane\n"); return FALSE; } cp = dbTechNameAdd(argv[0], INT2CD(DBNumPlanes), &dbPlaneNameLists, FALSE); if (cp == NULL) return FALSE; DBPlaneLongNameTbl[DBNumPlanes++] = cp; return TRUE; } /* * ---------------------------------------------------------------------------- * * DBTechAddNameToType -- * * Add a new name (alias) to an existing tile type. * * Results: * None. * * Side Effects: * Adds "newname" to dbTypeNameLists. May change the primary name * of the type stored in the pointer array DBTypeLongNameTbl[]. * * ---------------------------------------------------------------------------- */ void DBTechAddNameToType(newname, ttype, canonical) char *newname; TileType ttype; bool canonical; { char *cp; cp = dbTechNameAdd(newname, INT2CD(ttype), &dbTypeNameLists, TRUE); if (canonical) DBTypeLongNameTbl[ttype] = cp; } /* * ---------------------------------------------------------------------------- * * DBTechAddAlias -- * * Define an alias representing a mask of one or more tiletypes * * Results: * TRUE if successful, FALSE on error. Returns TRUE on some * errors that may not necessarily be fatal. * * Side effects: * Updates the database technology variables. * In particular, updates the alias hash table. * * ---------------------------------------------------------------------------- */ bool DBTechAddAlias(sectionName, argc, argv) char *sectionName; int argc; char *argv[]; { char *cp; int pNum; HashEntry *he; TileType atype; TileTypeBitMask *amask, tmask; if (argc < 2) { TechError("Line must contain at least 2 fields\n"); return TRUE; } /* First check that the alias name does not shadow an existing type */ if (DBTechNameTypeExact(argv[0]) >= 0) { TechError("Type alias \"%s\" shadows a defined type\n", argv[0]); return TRUE; } /* Next, check the type list. If there is only one type, then */ /* add the name to the type's names as usual, instead of adding */ /* it to the alias hash table, which is meant for names that */ /* map to multiple types. */ DBTechNoisyNameMask(argv[1], &tmask); if ((atype = DBTechNameType(argv[1])) >= 0) if (TTMaskEqual(&DBLayerTypeMaskTbl[atype], &tmask)) { DBTechAddNameToType(argv[0], atype, FALSE); return TRUE; } he = HashFind(&DBTypeAliasTable, argv[0]); amask = (TileTypeBitMask *)HashGetValue(he); if (amask == NULL) { amask = (TileTypeBitMask *)mallocMagic(sizeof(TileTypeBitMask)); TTMaskZero(amask); TTMaskSetMask(amask, &tmask); HashSetValue(he, amask); } else { TechError("Type \"%s\" is already defined and cannot be an alias\n", argv[0]); return TRUE; } return TRUE; } /* * ---------------------------------------------------------------------------- * * DBTechAddType -- * * Define a tile type for the new technology. * * Results: * TRUE if successful, FALSE on error. Returns TRUE on some * errors that may not necessarily be fatal. * * Side effects: * Updates the database technology variables. * In particular, updates the number of known tile types. * * ---------------------------------------------------------------------------- */ /*ARGSUSED*/ bool DBTechAddType(sectionName, argc, argv) char *sectionName; int argc; char *argv[]; { char *cp; int pNum; if (DBNumTypes >= TT_MAXTYPES-TT_RESERVEDTYPES) { TechError("Too many tile types (max=%d)\n", TT_MAXTYPES-TT_RESERVEDTYPES); return FALSE; } if (argc < 2) { TechError("Line must contain at least 2 fields\n"); return TRUE; } if (!strcmp(argv[0], "alias")) { /* Check that we have not used "*" in the alias list, since if */ /* we define aliases in the "types" section (which is allowed */ /* for backwards compatibility), the contacts have not yet been */ /* defined. */ if (strchr(argv[2], '*') != NULL) { TechError("Type alias \"%s\" contains the wildcard character " "\"*\" (alias ignored).\n" "Perhaps you want to define aliases in " "the \"alias\" section?\n", argv[2]); return TRUE; } return (DBTechAddAlias(sectionName, argc - 1, argv + 1)); } else { cp = dbTechNameAdd(argv[1], INT2CD(DBNumTypes), &dbTypeNameLists, FALSE); if (cp == NULL) return FALSE; /* Set the lock layer bit if the plane name begins with '-' */ if (*argv[0] == LOCKLAYERCHAR) { TTMaskSetType(&DBActiveLayerBits, DBNumTypes); argv[0]++; } pNum = DBTechNoisyNamePlane(argv[0]); if (pNum < 0) return FALSE; DBTypeLongNameTbl[DBNumTypes] = cp; DBPlane(DBNumTypes) = pNum; TTMaskSetOnlyType(&DBLayerTypeMaskTbl[DBNumTypes], DBNumTypes); DBNumTypes++; } return TRUE; } /* * ---------------------------------------------------------------------------- * dbTechNewStackedType -- * * Generate a new tiletype for a stacked layer (generally speaking, * a stacked contact). Return the new tile type for the stacked * contact type. * * Results: * The new tile type * * Side effects: * Updates the name tables with the new type name. Note that other * tables, such as the home plane table, are not affected by this * routine. * ---------------------------------------------------------------------------- */ TileType dbTechNewStackedType(type1, type2) TileType type1, type2; { char buf[1024], *cp; if (DBNumTypes >= TT_MAXTYPES - TT_RESERVEDTYPES) { TechError("Too many types to generate a new contact. Maximum=%d\n", TT_MAXTYPES - TT_RESERVEDTYPES); return (TileType) -1; } sprintf(buf, "%s+%s", DBTypeShortName(type1), DBTypeShortName(type2)); cp = dbTechNameAdd(buf, INT2CD(DBNumTypes), &dbTypeNameLists, FALSE); if (cp == NULL) { TechError("Couldn't generate new stacking type %s\n", buf); return (TileType) -1; } DBTypeLongNameTbl[DBNumTypes] = cp; return DBNumTypes++; } /* * ---------------------------------------------------------------------------- * * DBTechFinalType -- * * After processing the types and planes sections, compute the * various derived type and plane masks and tables. * * Results: * None. * * Side effects: * Initializes DBNumUserLayers to be DBNumTypes at the time * this procedure is called, since none of the automatically * generated plane images have yet been created. * Initializes the following bit masks: * DBAllTypeBits * DBSpaceBits * DBBuiltinLayerBits * DBAllButSpaceBits * DBAllButSpaceAndDRCBits * DBUserLayerBits * * ---------------------------------------------------------------------------- */ void DBTechFinalType() { TileType i; int pNum; DBNumUserLayers = DBNumTypes; for (i = 0; i < TT_MAXTYPES; i++) { if (i >= TT_SELECTBASE) TTMaskSetType(&DBAllButSpaceAndDRCBits, i); if (i < TT_TECHDEPBASE) TTMaskSetType(&DBBuiltinLayerBits, i); else if (i < DBNumUserLayers) TTMaskSetType(&DBUserLayerBits, i); } TTMaskCom2(&DBAllTypeBits, &DBZeroTypeBits); TTMaskSetOnlyType(&DBSpaceBits, TT_SPACE); TTMaskCom2(&DBAllButSpaceBits, &DBSpaceBits); /* UserLayerBits includes space */ TTMaskSetType(&DBUserLayerBits, TT_SPACE); /* Set locked layer bitmask */ TTMaskCom(&DBActiveLayerBits); TTMaskAndMask(&DBActiveLayerBits, &DBAllButSpaceAndDRCBits); /* Save this mask for later reference */ TTMaskZero(&DBTechActiveLayerBits); TTMaskSetMask(&DBTechActiveLayerBits, &DBActiveLayerBits); /* Space is visible on all planes except the router */ TTMaskZero(&DBPlaneTypes[PL_ROUTER]); for (pNum = PL_PAINTBASE; pNum < PL_MAXTYPES; pNum++) TTMaskSetOnlyType(&DBPlaneTypes[pNum], TT_SPACE); } /* * ---------------------------------------------------------------------------- * * dbTechNameLookupExact -- * * Lookup a type or plane name. * Case is significant. * * Results: * Returns the ClientData associated with the given name. * If the name was not found, we return -2. Unlike dbTechNameLookup, * this routine requires an exact name match, and never returns -1 * (which indicates ambiguity in dbTechNameLookup()). * * Side effects: * None. * * ---------------------------------------------------------------------------- */ ClientData dbTechNameLookupExact(str, table) char *str; /* The name to be looked up */ NameList *table; /* Table of names to search */ { NameList *top; top = table; while ((top = top->sn_next) != table) if (!strcmp(top->sn_name, str)) return (top->sn_value); return ((ClientData) -2); } /* * ---------------------------------------------------------------------------- * * dbTechNameLookup -- * * Lookup a type or plane name. * Case is significant. * * Results: * Returns the ClientData associated with the given name. * If the name was not found, we return -2; if it was ambiguous, * we return -1. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ ClientData dbTechNameLookup(str, table) char *str; /* The name to be looked up */ NameList *table; /* Table of names to search */ { /* * The search is carried out by using two pointers, one which moves * forward through list from its start, and one which moves backward * through table from its end. The two pointers mark the range of * strings that match the portion of str that we have scanned. When * all of the characters of str have been scanned, then the two * pointers better be identical, or one of the strings in the range * between the two pointers better match 'str' exactly. */ NameList *bot, *top; char currentchar; int indx; bot = table->sn_next; top = table->sn_prev; if (top == bot) return ((ClientData) -2); for (indx = 0; ; indx++) { /* Check for the end of string */ currentchar = str[indx]; if (currentchar == '\0') { if (bot == top) return (bot->sn_value); /* * Several entries match this one up to the last character * of the string. If one is an exact match, we allow it; * otherwise, we claim the string was ambiguous. */ for ( ; bot != top; bot = bot->sn_next) if (bot->sn_name[indx] == '\0') return (bot->sn_value); return ((ClientData) -1); } /* * Move bot up until the string it points to matches str in the * indx'th position. Make match refer to the indx of bot in table. */ while (bot->sn_name[indx] != currentchar) { if (bot == top) return((ClientData) -2); bot = bot->sn_next; } /* Move top down until it matches */ while (top->sn_name[indx] != currentchar) { if (bot == top) return((ClientData) -2); top = top->sn_prev; } } /*NOTREACHED*/ } /* * ---------------------------------------------------------------------------- * * dbTechNameAdd -- * * Add several names to a name table. * The shortest name is marked as the standard "short" name * for this cdata value. * * Results: * Returns a pointer to the first name added if successful, * or NULL if not. In this latter case, we print error messages. * * Side effects: * Adds new entries to the table pointed to by *ptable, and * modifies *ptable if necessary. * * ---------------------------------------------------------------------------- */ char * dbTechNameAdd(name, cdata, ptable, alias) char *name; /* Comma-separated list of names to be added */ ClientData cdata; /* Value to be stored with each name above */ NameList *ptable; /* Table to which we will add names */ int alias; /* 1 if this is an alias (never make primary) */ { char *cp; char onename[BUFSIZ]; char *first; int shortestLength, length; NameList *primary, *current; if (name == NULL) return (NULL); first = NULL; shortestLength = INFINITY; primary = NULL; while (*name) { if (*name == ',') { name++; continue; } for (cp = onename; *name && *name != ','; *cp++ = *name++) /* Nothing */; *cp = '\0'; if (*(cp = onename)) { if ((current = dbTechNameAddOne(cp, cdata, FALSE, alias, ptable)) == NULL) return (NULL); if (first == NULL) first = current->sn_name; length = strlen(onename); if (length < shortestLength) shortestLength = length, primary = current; } } if (primary && (alias == 0)) primary->sn_primary = TRUE; return (first); } /* * ---------------------------------------------------------------------------- * * dbTechNameAddOne -- * * Add a single name to the table. * * Results: * Returns a pointer to the new entry if succesful, * or NULL if the name was already in the table. * * Side effects: * See above. * * ---------------------------------------------------------------------------- */ NameList * dbTechNameAddOne(name, cdata, isPrimary, isAlias, ptable) char *name; /* Name to be added */ ClientData cdata; /* Client value associated with this name */ bool isPrimary; /* TRUE if this is the primary abbreviation */ bool isAlias; /* TRUE if this name is an alias */ NameList *ptable; /* Table of names to which we're adding this */ { int cmp; NameList *tbl, *new; /* Sort the name into the existing list */ for (tbl = ptable->sn_next ;tbl != ptable; tbl = tbl->sn_next) if ((cmp = strcmp(name, tbl->sn_name)) == 0) { TechError("Duplicate name: %s\n", name); return (NULL); } else if (cmp < 0) break; /* Create a new name */ new = (NameList *) mallocMagic((unsigned) (sizeof (NameList))); new->sn_name = StrDup((char **) NULL, name); new->sn_value = cdata; new->sn_primary = isPrimary; new->sn_alias = isAlias; /* Link this entry in to the list before 'tbl' */ new->sn_next = tbl; new->sn_prev = tbl->sn_prev; tbl->sn_prev->sn_next = new; tbl->sn_prev = new; return (new); }