/* * ExtUnique.c -- * * Circuit extraction. * Generation of unique names. * * ********************************************************************* * * 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/extract/ExtUnique.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $"; #endif /* not lint */ #include #include #include #include #include "utils/magic.h" #include "utils/geometry.h" #include "utils/styles.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "utils/malloc.h" #include "textio/textio.h" #include "debug/debug.h" #include "extract/extract.h" #include "extract/extractInt.h" #include "utils/signals.h" #include "utils/stack.h" #include "utils/utils.h" #include "windows/windows.h" #include "dbwind/dbwind.h" #include "utils/main.h" #include "utils/undo.h" /* * ---------------------------------------------------------------------------- * * extUniqueCell -- * * For the cell 'def', look for the same label appearing in two or more * distinct nodes. For each such label found: * * If option is EXT_UNIQ_ALL, then generate unique names for all * but one of the nodes by appending a unique numeric * suffix to the offending labels. * If option is EXT_UNIQ_TAGGED, then generate unique names only * if the label ends in '#'. Leave feedback for all other * names that don't end in '!'. * If option is EXT_UNIQ_NOPORTS, then generate unique names as for * option 0 only if the label is not a port. * * Results: * Returns the number of warnings generated. * * Side effects: * May modify the label list of def, and mark def as CDMODIFIED. * May also leave feedback. * * ---------------------------------------------------------------------------- */ int extUniqueCell(def, option) CellDef *def; int option; { NodeRegion *nodeList; LabRegion *lregList, *lastreg, processedLabel; LabRegion *lp; LabelList *ll; HashEntry *he; HashTable labelHash; Label *lab; char *text; int nwarn; bool isabstract; NodeRegion *extFindNodes(); /* Forward reference */ nwarn = 0; /* Check for "LEFview", as we do not care about unique names in abstract views */ DBPropGet(def, "LEFview", &isabstract); if (isabstract) return nwarn; HashInit(&labelHash, 32, HT_STRINGKEYS); TxPrintf("Processing %s\n", def->cd_name); TxFlush(); /* Find and mark the substrate node. This prevents "soft connections" */ /* through the substrate from being separated into unique names. */ nodeList = extFindNodes(def, (Rect *)NULL, TRUE); /* Build up a list of nodes and assign them to tiles */ lregList = (LabRegion *) ExtFindRegions(def, &TiPlaneRect, &ExtCurStyle->exts_activeTypes, ExtCurStyle->exts_nodeConn, extUnInit, extHierLabFirst, (int (*)()) NULL); /* Assign the labels to their associated regions */ ExtLabelRegions(def, ExtCurStyle->exts_nodeConn, &lregList, &TiPlaneRect); /* * First pass: * Place all node labels in the cell in the hash table. */ for (lab = def->cd_labels; lab; lab = lab->lab_next) if (extLabType(lab->lab_text, LABTYPE_NAME)) (void) HashFind(&labelHash, lab->lab_text); /* Fix up labels as necessary */ for (lp = lregList; lp; lp = lp->lreg_next) { for (ll = lp->lreg_labels; ll; ll = ll->ll_next) { /* * We might have set ll->ll_label to NULL if we changed it * to make it unique. Also ignore if the label is not a * node label type (e.g, it is an attribute). */ if (ll->ll_label == (Label *) NULL) continue; text = ll->ll_label->lab_text; if (!extLabType(text, LABTYPE_NAME)) continue; /* * See if this label has been seen before in this cell. * If not, remember the current LabRegion as the first * one seen with this label. If it has been seen, but * with this same region, or it has already been made * unique (lastreg == &processedLabel), skip it. */ he = HashFind(&labelHash, text); lastreg = (LabRegion *) HashGetValue(he); if (lastreg == (LabRegion *) NULL) { HashSetValue(he, (ClientData) lp); continue; } if (lastreg != lp && lastreg != &processedLabel) { LabelList *lltest = NULL; /* If the last label is a port and this label is not, then * run extMakeUnique on the port (since extMakeUnique() causes * all other nodes to be made unique). This preserves the port * name whenever a port name disagrees with an internal name. */ if (!(ll->ll_label->lab_flags & PORT_DIR_MASK)) for (lltest = lastreg->lreg_labels; lltest; lltest = lltest->ll_next) if ((lltest->ll_label != NULL) && (!strcmp(lltest->ll_label->lab_text, text))) if (lltest->ll_label->lab_flags & PORT_DIR_MASK) break; if (lltest != NULL) { nwarn += extMakeUnique(def, lltest, lastreg, lregList, &labelHash, option); } else { nwarn += extMakeUnique(def, ll, lp, lregList, &labelHash, option); HashSetValue(he, (ClientData) &processedLabel); } } } } HashKill(&labelHash); ExtFreeLabRegions((LabRegion *) lregList); if (nodeList) freeMagic(nodeList); ExtResetTiles(def, extUnInit); if (nwarn) TxError("%s: %d warnings\n", def->cd_name, nwarn); return (nwarn); } int extMakeUnique(def, ll, lreg, lregList, labelHash, option) CellDef *def; LabelList *ll; LabRegion *lreg, *lregList; HashTable *labelHash; int option; { static char *badmesg = "Non-global label \"%s\" attached to more than one unconnected node: %s"; char *cpend, *text, name[1024], name2[1024+32], message[1024]; LabRegion *lp2; LabelList *ll2; int nsuffix, nwarn; Label saveLab, *lab; Rect r; unsigned short flags; int portno; /* * Make a pass through all labels for all nodes. * Replace labels as appropriate. This loop * sets ll_label pointers to NULL whenever it * changes a label to make it unique. */ text = ll->ll_label->lab_text; if (option == EXT_UNIQ_ALL) goto makeUnique; else if ((option == EXT_UNIQ_NOPORTS || option == EXT_UNIQ_NOTOPPORTS) && !(ll->ll_label->lab_flags & PORT_DIR_MASK)) goto makeUnique; cpend = strchr(text, '\0'); if (cpend > text) cpend--; if (*cpend == '#') goto makeUnique; if (*cpend == '!') return 0; /* Don't generate warnings about ports when given the "noports" or * "notopports" options. */ if (((option == EXT_UNIQ_NOPORTS) || (option == EXT_UNIQ_NOTOPPORTS)) && (ll->ll_label->lab_flags & PORT_DIR_MASK)) return 0; /* Generate a warning for each occurrence of this label */ nwarn = 0; for (lp2 = lregList; lp2; lp2 = lp2->lreg_next) { for (ll2 = lp2->lreg_labels; ll2; ll2 = ll2->ll_next) { if (ll2->ll_label && strcmp(ll2->ll_label->lab_text, text) == 0) { nwarn++; r.r_ll = r.r_ur = ll2->ll_label->lab_rect.r_ll; GEO_EXPAND(&r, 1, &r); extMakeNodeNumPrint(name, lp2); (void) sprintf(message, badmesg, text, name); DBWFeedbackAdd(&r, message, def, 1, STYLE_MEDIUMHIGHLIGHTS); } } } return nwarn; /* * For each occurrence of this label in all nodes but lreg, * replace the label by one with a unique suffix. If the * label is replaced, we mark it in the label list of the * node by NULLing-out the ll_label field of the LabelList * pointing to it. */ makeUnique: nsuffix = 0; (void) strcpy(name, text); for (lp2 = lregList; lp2; lp2 = lp2->lreg_next) { /* Skip lreg -- its labels will be unchanged */ if (lp2 == lreg) continue; lab = (Label *) NULL; for (ll2 = lp2->lreg_labels; ll2; ll2 = ll2->ll_next) { if (ll2->ll_label == (Label *) NULL) continue; if (strcmp(ll2->ll_label->lab_text, name)) continue; /* * Keep looking for a name not already in this cell. * This is a bit conservative, since names that might not have * been attached to nodes were also added to the table in * extUniqueCell() above, but we ensure that we don't generate * a name that might conflict with an existing one (e.g, turning * Phi into Phi1 when there's already a Phi1 in the cell). * It's not necessary to add the final name to labelHash * because nsuffix increases monotonically -- we can never * generate a label identical to one previously generated. */ for (;;) { (void) sprintf(name2, "%s_uq%d", name, nsuffix); if (HashLookOnly(labelHash, name2) == NULL) break; nsuffix++; } /* If the label is a port, then the port needs a unique ID */ /* for the unique name. */ flags = ll2->ll_label->lab_flags; if (flags & PORT_DIR_MASK) { int idx; portno = -1; /* Find the last port index used in the cell def */ for (lab = def->cd_labels; lab != NULL; lab = lab->lab_next) { idx = lab->lab_port; if (idx > portno) portno = idx; } portno++; } else portno = 0; lab = ll2->ll_label; saveLab = *lab; DBRemoveLabel(def, lab); (void) DBPutFontLabel(def, &saveLab.lab_rect, saveLab.lab_font, saveLab.lab_size, saveLab.lab_rotate, &saveLab.lab_offset, saveLab.lab_just, name2, saveLab.lab_type, flags, (unsigned int)portno); ll2->ll_label = (Label *) NULL; } /* Bump the suffix if we replaced any labels */ if (lab) nsuffix++; } return 0; }