mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-09-04 08:33:55 +02:00
(1) An incorrect use of ExtResetTiles() was found in "extresist"
which impacts performance, especially for small nets.
(2) Corrected units for resistance tolerance in extresist, and
handled output printing in fs when delay values get below ps
size.
(3) Added command option "extract do unique notopports" to be the
extraction option equivalent of the standalone command
"extract unique notopports".
(4) Changed the "extresist" default for "mindelay" to 1ps from 0,
in response to the observation that lumped resistance from
"extract" can be an extreme overestimate, and the extracted
time delay from "extesist" calculations should be used as a
better determination of whether a net should be output as a
resistor network or not.
(5) Added documentation for both "extract do unique notopports"
and the change to the "extresist" default values.
410 lines
12 KiB
C
410 lines
12 KiB
C
/*
|
|
* 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
|
|
#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.
|
|
* If option is EXT_UNIQ_TEMP, then generate unique names as for
|
|
* EXT_UNIQ_ALL, but also set the LABEL_UNIQUE flag for the
|
|
* label. This way, the unique label form can be used by the
|
|
* extraction code but labels (and port indexes) can be reverted
|
|
* afterward, and no permanent change is made to the circuit.
|
|
* Option EXT_UNIQ_TEMP_NOPORTS is a combination of EXT_UNIQ_TEMP and
|
|
* EXT_UNIQ_NOPORTS.
|
|
*
|
|
* 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,
|
|
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, CLIENTDEFAULT);
|
|
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 || option == EXT_UNIQ_TEMP)
|
|
goto makeUnique;
|
|
else if ((option == EXT_UNIQ_NOPORTS || option == EXT_UNIQ_NOTOPPORTS ||
|
|
option == EXT_UNIQ_TEMP_NOPORTS) &&
|
|
!(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;
|
|
|
|
/* Flag this label as having been modified */
|
|
if ((option == EXT_UNIQ_TEMP) || (option == EXT_UNIQ_TEMP_NOPORTS))
|
|
flags |= LABEL_UNIQUE;
|
|
|
|
DBRemoveLabel(def, lab);
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extRevertUniqueCell --
|
|
*
|
|
* For the cell 'def', look for labels marked with LABEL_UNIQUE and
|
|
* remove the unique suffix. If the label is a port, then revert
|
|
* the port index back to the original port number.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Changes the label records in the cell def.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
ExtRevertUniqueCell(CellDef *def)
|
|
{
|
|
Label *lab, *tlab;
|
|
char *uptr;
|
|
|
|
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
|
{
|
|
if (lab->lab_flags & LABEL_UNIQUE)
|
|
{
|
|
/* There is no need to regenerate the label. We are
|
|
* only reducing the string length, so just drop a null
|
|
* at the last underscore and leave it at that.
|
|
*/
|
|
|
|
lab->lab_flags &= ~LABEL_UNIQUE; /* Clear the flag */
|
|
|
|
/* Place a null at the last underscore */
|
|
uptr = strrchr(lab->lab_text, '_');
|
|
if (uptr != NULL) /* should always be true */
|
|
*uptr = '\0';
|
|
|
|
/* If the label is a port, then find the first unmodified
|
|
* version of the label and change the port back to its
|
|
* port number
|
|
*/
|
|
if (lab->lab_flags & PORT_DIR_MASK)
|
|
{
|
|
for (tlab = def->cd_labels; tlab; tlab = tlab->lab_next)
|
|
{
|
|
if (tlab == lab) continue;
|
|
else if (!strcmp(tlab->lab_text, lab->lab_text))
|
|
{
|
|
lab->lab_port = tlab->lab_port;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|