After a discussion about "cifinput" rules, realized that there is

no way to implement boolean operators on labels, so any "label"
statement in the section can apply only to one magic layer.  This
is regularly violated in most (all?) techfiles (due mainly to lack
of explanation and guidance).  The addition of the "no-reconnect-
labels" option for cifinput made it worse, as it can cause a label
to be attached to the wrong layer and be stuck that way.  Even
without the option, an attachment to a non-connecting type is a
problem;  DIFF cannot simultaneously have a connection to both
ndiff and pdiff, so it will be one or the other, and the one not
connected can easily get labels moved to other nets.  To avoid
this:  (1) removed the "no-reconnect-labels" option, and (2) made
the automatic label reconnection smarter, as well as splitting it
into two different behaviors based on whether a label is being
created or manipulated from the command line (more or less the
original behavior) vs. being read from GDS or LEF.  The new rules
assume that labels attached to a GDS type will all map to the
same plane in magic.  To avoid excessive error messages from
existing tech files, a warning is issued only if "labels" changes
the plane of the target layer (a realistic solution rather than
the preferred one).  Also:  Fixed an error that causes a crash on
the "wizard" command "*watch" if the cell being observed is
read-only (see github issue #271).
This commit is contained in:
Tim Edwards 2023-10-17 15:54:38 -04:00
parent 5b29870fce
commit fdcc178bcd
8 changed files with 212 additions and 133 deletions

View File

@ -1 +1 @@
8.3.439 8.3.440

View File

@ -610,8 +610,12 @@ calmaParseStructure(filename)
(locPolygonCount < CalmaPolygonCount)) (locPolygonCount < CalmaPolygonCount))
DBCellEnum(cifReadCellDef, calmaFlattenPolygonFunc, (ClientData)cifReadCellDef); DBCellEnum(cifReadCellDef, calmaFlattenPolygonFunc, (ClientData)cifReadCellDef);
DBAdjustLabelsNew(cifReadCellDef, &TiPlaneRect, /* Because the "label" statement can only match one GDS layer to one magic
(cifCurReadStyle->crs_flags & CRF_NO_RECONNECT_LABELS) ? 1 : 0); * layer, then all labels are subject to adjustment to attach them to
* something meaningful in the layout. The "no-reconnect-labels" option
* is not useful and has been deprecated.
*/
DBAdjustLabelsNew(cifReadCellDef, &TiPlaneRect);
DBReComputeBbox(cifReadCellDef); DBReComputeBbox(cifReadCellDef);
/* Don't bother to register with DRC if we're going to delete the */ /* Don't bother to register with DRC if we're going to delete the */

View File

@ -1002,8 +1002,6 @@ calmaElementText()
flags = 0; flags = 0;
else if (cifnum >= 0 && (cifCurReadStyle->crs_labelSticky[cifnum] != LABEL_TYPE_NONE)) else if (cifnum >= 0 && (cifCurReadStyle->crs_labelSticky[cifnum] != LABEL_TYPE_NONE))
flags = LABEL_STICKY; flags = LABEL_STICKY;
else if (cifCurReadStyle->crs_flags & CRF_NO_RECONNECT_LABELS)
flags = LABEL_STICKY;
else else
flags = 0; flags = 0;

View File

@ -877,14 +877,27 @@ CIFReadTechLine(sectionName, argc, argv)
if (TTMaskHasType(&mask, i)) if (TTMaskHasType(&mask, i))
{ {
/* Only one magic type can be assigned to a GDS layer, so /* Only one magic type can be assigned to a GDS layer, so
* multiple assignments should be flagged as errors. * multiple assignments should be flagged as errors. BUT,
* this is a common historic error. Since reattachments
* should be handled rationally (by code added 10/17/2023
* to DBlabel.c), there is no urgent need to flag an issue
* unless the new layer does not exist on the same plane
* as the old one.
*/ */
if (cifCurReadStyle->crs_labelLayer[i] != TT_SPACE) if (cifCurReadStyle->crs_labelLayer[i] != TT_SPACE)
TechError("Labels on layer \"%s\" attached to \"%s\" supersedes " {
"prior attachment to \"%s\".\n", int p1, p2;
p1 = DBPlane(cifCurReadLayer->crl_magicType);
p2 = DBPlane(cifCurReadStyle->crs_labelLayer[i]);
if (!DBTypeOnPlane(cifCurReadLayer->crl_magicType, p2) &&
!DBTypeOnPlane(cifCurReadStyle->crs_labelLayer[i], p1))
TechError("Labels on layer \"%s\" attached to \"%s\" "
"supersedes prior attachment to \"%s\".\n",
cifReadLayers[i], cifReadLayers[i],
DBTypeLongNameTbl[cifCurReadLayer->crl_magicType], DBTypeLongNameTbl[cifCurReadLayer->crl_magicType],
DBTypeLongNameTbl[cifCurReadStyle->crs_labelLayer[i]]); DBTypeLongNameTbl[cifCurReadStyle->crs_labelLayer[i]]);
}
cifCurReadStyle->crs_labelLayer[i] cifCurReadStyle->crs_labelLayer[i]
= cifCurReadLayer->crl_magicType; = cifCurReadLayer->crl_magicType;
@ -926,14 +939,15 @@ CIFReadTechLine(sectionName, argc, argv)
/* miscellaneous cif-reading boolean options */ /* miscellaneous cif-reading boolean options */
if(strcmp(argv[0], "options") == 0) { if (strcmp(argv[0], "options") == 0) {
int i; int i;
if (argc < 2) goto wrongNumArgs; if (argc < 2) goto wrongNumArgs;
for(i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
if(strcmp(argv[i], "ignore-unknown-layer-labels") == 0) if (strcmp(argv[i], "ignore-unknown-layer-labels") == 0)
cifCurReadStyle->crs_flags |= CRF_IGNORE_UNKNOWNLAYER_LABELS; cifCurReadStyle->crs_flags |= CRF_IGNORE_UNKNOWNLAYER_LABELS;
if(strcmp(argv[i], "no-reconnect-labels") == 0) /* Allow "no-reconnect-labels", although it has been deprecated */
cifCurReadStyle->crs_flags |= CRF_NO_RECONNECT_LABELS; else if (strcmp(argv[i], "no-reconnect-labels") != 0)
TechError("Unknown cifinput option \"%s\".\n", argv[i]);
} }
return TRUE; return TRUE;
} }

View File

@ -115,7 +115,6 @@ typedef struct cifrstyle
/* option bitmasks used in crs_flags */ /* option bitmasks used in crs_flags */
#define CRF_IGNORE_UNKNOWNLAYER_LABELS 1 #define CRF_IGNORE_UNKNOWNLAYER_LABELS 1
#define CRF_NO_RECONNECT_LABELS 2
/* Methods to deal with fractional results of conversion from CIF to magic */ /* Methods to deal with fractional results of conversion from CIF to magic */
/* units (see routine CIFScaleCoord() for details). */ /* units (see routine CIFScaleCoord() for details). */

View File

@ -1052,8 +1052,16 @@ CmdWatch(w, cmd)
}; };
return; return;
} }
crec->dbw_watchDef = EditCellUse->cu_def; if (EditCellUse != NULL)
crec->dbw_watchTrans = EditToRootTransform; {
crec->dbw_watchDef = EditCellUse->cu_def;
crec->dbw_watchTrans = EditToRootTransform;
}
else
{
crec->dbw_watchDef = ((CellUse *)w->w_surfaceID)->cu_def;
crec->dbw_watchTrans = ((CellUse *)w->w_surfaceID)->cu_transform;
}
} }
crec->dbw_watchPlane = pNum; crec->dbw_watchPlane = pNum;

View File

@ -36,12 +36,13 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "database/database.h" #include "database/database.h"
#include "database/fonts.h" #include "database/fonts.h"
#include "database/databaseInt.h" #include "database/databaseInt.h"
#include "extract/extractInt.h" /* for ExtCurStyle */
#include "windows/windows.h" #include "windows/windows.h"
#include "dbwind/dbwind.h" #include "dbwind/dbwind.h"
#include "commands/commands.h" #include "commands/commands.h"
#include "textio/textio.h" #include "textio/textio.h"
static TileType DBPickLabelLayer(/* CellDef *def, Label *lab, int noreconnect */); static TileType DBPickLabelLayer(/* CellDef *def, Label *lab, bool doCalma */);
/* Globally-accessible font information */ /* Globally-accessible font information */
@ -292,7 +293,7 @@ DBEraseGlobLabel(cellDef, area, mask, areaReturn, globmatch)
*/ */
if (!(lab->lab_type == TT_SPACE)) if (!(lab->lab_type == TT_SPACE))
{ {
newType = DBPickLabelLayer(cellDef, lab, 0); newType = DBPickLabelLayer(cellDef, lab, FALSE);
if (DBConnectsTo(newType, lab->lab_type)) goto nextLab; if (DBConnectsTo(newType, lab->lab_type)) goto nextLab;
} }
} }
@ -598,7 +599,7 @@ DBAdjustLabels(def, area)
for (lab = def->cd_labels; lab != NULL; lab = lab->lab_next) for (lab = def->cd_labels; lab != NULL; lab = lab->lab_next)
{ {
if (!GEO_TOUCH(&lab->lab_rect, area)) continue; if (!GEO_TOUCH(&lab->lab_rect, area)) continue;
newType = DBPickLabelLayer(def, lab, 0); newType = DBPickLabelLayer(def, lab, FALSE);
if (newType == lab->lab_type) continue; if (newType == lab->lab_type) continue;
if (lab->lab_flags & LABEL_STICKY) continue; if (lab->lab_flags & LABEL_STICKY) continue;
if ((DBVerbose >= DB_VERBOSE_ALL) && ((def->cd_flags & CDINTERNAL) == 0)) if ((DBVerbose >= DB_VERBOSE_ALL) && ((def->cd_flags & CDINTERNAL) == 0))
@ -618,17 +619,32 @@ DBAdjustLabels(def, area)
/* /*
* Extended version of DBAdjustLabels. If noreconnect == 0, *---------------------------------------------------------------
* this is supposed to be the same as DBAdjustlabels() above. *
* DBAdjustLabelsNew--
*
* Modified version of DBAdjustLabels, used with reading
* GDS and LEF files. Since those files use GDS layers and
* not magic layers, there is no exact relationship between
* the two. Instead, the cifinput rules are used to set an
* initial type only. The rules for label adjustment are
* different from DBAdjustLabels(), and so a different
* routine is called.
*
* Results:
* None.
*
* Side effects:
* The layer attachments of labels may change. For each
* such change, a message is output.
*
*---------------------------------------------------------------
*/ */
void void
DBAdjustLabelsNew(def, area, noreconnect) DBAdjustLabelsNew(def, area)
CellDef *def; /* Cell whose paint was changed. */ CellDef *def; /* Cell whose paint was changed. */
Rect *area; /* Area where paint was modified. */ Rect *area; /* Area where paint was modified. */
int noreconnect; /* if 1, don't move label to a type that doesn't
* connect to the original type, delete instead
*/
{ {
Label *lab, *labPrev; Label *lab, *labPrev;
TileType newType; TileType newType;
@ -642,35 +658,40 @@ DBAdjustLabelsNew(def, area, noreconnect)
lab = def->cd_labels; lab = def->cd_labels;
while (lab != NULL) while (lab != NULL)
{ {
int locnoreconnect = noreconnect; bool doCalma = TRUE;
if (!GEO_TOUCH(&lab->lab_rect, area)) if (!GEO_TOUCH(&lab->lab_rect, area)) goto nextLab;
{ if (lab->lab_type == TT_SPACE) doCalma = FALSE;
goto nextLab; newType = DBPickLabelLayer(def, lab, doCalma);
}
if (lab->lab_type == TT_SPACE) locnoreconnect = FALSE;
newType = DBPickLabelLayer(def, lab, locnoreconnect);
if (newType == lab->lab_type) if (newType == lab->lab_type)
{
goto nextLab; goto nextLab;
}
if (newType < 0 && !(lab->lab_flags & LABEL_STICKY)) if (((newType < 0) || (newType == TT_SPACE)) && !(lab->lab_flags & LABEL_STICKY))
{ {
TxPrintf("Deleting ambiguous-layer label \"%s\" from %s in cell %s.\n", if (lab->lab_type == TT_SPACE)
{
TxPrintf("Deleting unattached label \"%s\" in cell %s.\n",
lab->lab_text, def->cd_name);
if (labPrev == NULL)
def->cd_labels = lab->lab_next;
else
labPrev->lab_next = lab->lab_next;
if (def->cd_lastLabel == lab)
def->cd_lastLabel = labPrev;
DBUndoEraseLabel(def, lab);
DBWLabelChanged(def, lab, DBW_ALLWINDOWS);
freeMagic((char *) lab);
lab = lab->lab_next;
modified = TRUE;
continue;
}
else
{
TxPrintf("Making label \"%s\" on type %s in cell %s sticky.\n",
lab->lab_text, DBTypeLongName(lab->lab_type), lab->lab_text, DBTypeLongName(lab->lab_type),
def->cd_name); def->cd_name);
lab->lab_flags |= LABEL_STICKY;
if (labPrev == NULL) }
def->cd_labels = lab->lab_next;
else
labPrev->lab_next = lab->lab_next;
if (def->cd_lastLabel == lab)
def->cd_lastLabel = labPrev;
DBUndoEraseLabel(def, lab);
DBWLabelChanged(def, lab, DBW_ALLWINDOWS);
freeMagic((char *) lab);
lab = lab->lab_next;
modified = TRUE;
continue;
} }
else if (!(lab->lab_flags & LABEL_STICKY)) else if (!(lab->lab_flags & LABEL_STICKY))
{ {
@ -723,10 +744,10 @@ TileTypeBitMask *dbAdjustPlaneTypes; /* Mask of all types in current
* plane being searched. * plane being searched.
*/ */
TileType TileType
DBPickLabelLayer(def, lab, noreconnect) DBPickLabelLayer(def, lab, doCalma)
CellDef *def; /* Cell definition containing label. */ CellDef *def; /* Cell definition containing label. */
Label *lab; /* Label for which a home must be found. */ Label *lab; /* Label for which a home must be found. */
int noreconnect; /* if 1, return -1 if rule 5 or 6 would succeed */ bool doCalma; /* if TRUE, use rules for GDS and LEF */
{ {
TileTypeBitMask types[3], types2[3]; TileTypeBitMask types[3], types2[3];
Rect check1, check2; Rect check1, check2;
@ -827,112 +848,147 @@ DBPickLabelLayer(def, lab, noreconnect)
} }
/* If the label's layer covers the label's area, use it. /* If the label's layer covers the label's area, use it.
* Otherwise, look for a layer in the following order: * Otherwise, look for a layer in the following order
* 1. A layer on the same plane as the original layer and that * (Note: "covers" means covers the area of the label if the
* covers the label and connects to its original layer. * label has area or touches the entire label if it doesn't.):
* 2. A layer on the same plane as the original layer and that *
* is a component of material that covers the label and * If "doCalma" is TRUE, then:
* connects to its original layer. * 1. A layer on the same plane as the original layer and that
* 3. A layer that covers the label and connects to the * covers the label and is not a device type.
* old layer. * 2. A layer on the same plane as the original layer and that
* 4. A layer that is a component of material that covers * covers the label.
* the label and connects to the old layer. * 3. A layer on the same plane as the original layer and that
* 5. A layer that covers the label. * is a component of material that covers the label.
* 6. A layer that is a component of material that covers the label. * 4. -1
* 7. Space. *
* If "doCalma" is FALSE, then:
* 1. A layer on the same plane as the original layer and that
* covers the label and connects to its original layer.
* 2. A layer on the same plane as the original layer and that
* is a component of material that covers the label and
* connects to its original layer.
* 3. A layer that covers the label and connects to the old layer.
* 4. A layer that is a component of material that covers the
* label and connects to the old layer.
* 5. A layer that covers the label and is on the same plane as the
* label.
* 6. A layer that is a component of material that covers the label
* and is on the same plane as the label.
* 7. Space.
* *
* All searches are done from the lowest to highest plane, so that * All searches are done from the lowest to highest plane, so that
* the label connects to material on the highest plane that matches * the label connects to material on the highest plane that matches
* the criteria above. This avoids weirdnesses caused by declaring * the criteria above. This avoids weirdnesses caused by declaring
* types out of order in the techfile. * types out of order in the techfile.
*
* Note that when the "label" command is used with no type given,
* then lab_type is TT_SPACE and "same plane as the label" is all
* planes. This should never be true when called during GDS or
* LEF reads, so only needs to be checked when "doCalma" is FALSE.
*/ */
if (TTMaskHasType(&types[0], lab->lab_type)) return lab->lab_type; if (TTMaskHasType(&types[0], lab->lab_type)) return lab->lab_type;
plane = DBPlane(lab->lab_type); plane = DBPlane(lab->lab_type);
choice1 = choice2 = choice3 = choice4 = choice5 = choice6 = TT_SPACE;
for (j = PL_SELECTBASE; j < DBNumPlanes; j++) if (doCalma)
{ {
choice1 = choice2 = choice3 = -1;
for (i = TT_SELECTBASE; i < DBNumUserLayers; i += 1) for (i = TT_SELECTBASE; i < DBNumUserLayers; i += 1)
{ {
if (!TTMaskHasType(&DBPlaneTypes[j], i)) continue; if (!TTMaskHasType(&DBPlaneTypes[plane], i)) continue;
if (DBConnectsTo(i, lab->lab_type)) if (TTMaskHasType(&types[0], i) && (ExtCurStyle != NULL))
{ {
if (DBPlane(i) == plane) if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, i))
{ choice2 = i;
if (TTMaskHasType(&types[0], i))
{
choice1 = i;
continue;
}
else if (TTMaskHasType(&types[1], i))
{
choice2 = i;
continue;
}
}
if (TTMaskHasType(&types[0], i))
{
choice3 = i;
continue;
}
else if (TTMaskHasType(&types[1], i))
{
choice4 = i;
continue;
}
}
if (TTMaskHasType(&types[0], i))
{
/* A type that connects to more than itself is preferred */
if (choice5 == TT_SPACE)
choice5 = i;
else else
{ choice1 = i;
TileTypeBitMask ctest;
TTMaskZero(&ctest);
TTMaskSetMask(&ctest, &DBConnectTbl[i]);
TTMaskClearType(&ctest, i);
if (!TTMaskIsZero(&ctest))
choice5 = i;
else if (TTMaskHasType(&types[1], i))
choice6 = i;
}
continue; continue;
} }
else if (TTMaskHasType(&types[1], i)) else if (TTMaskHasType(&types[1], i))
{ {
choice6 = i; choice3 = i;
continue; continue;
} }
} }
}
if (choice1 != TT_SPACE) return choice1; if (choice1 != -1) return choice1;
else if (choice2 != TT_SPACE) return choice2; else if (choice2 != -1) return choice2;
else if (choice3 != TT_SPACE) return choice3; else return choice3;
else if (choice4 != TT_SPACE) return choice4; }
else if (noreconnect) { else
#ifdef notdef {
TxPrintf("DBPickLabelLayer \"%s\" (on %s at %d,%d) choice4=%s choice5=%s choice6=%s.\n", choice1 = choice2 = choice3 = choice4 = choice5 = choice6 = TT_SPACE;
lab->lab_text,
DBTypeLongName(lab->lab_type), for (j = PL_SELECTBASE; j < DBNumPlanes; j++)
lab->lab_rect.r_xbot, {
lab->lab_rect.r_ytop, for (i = TT_SELECTBASE; i < DBNumUserLayers; i += 1)
DBTypeLongName(choice4), {
DBTypeLongName(choice5), if (!TTMaskHasType(&DBPlaneTypes[j], i)) continue;
DBTypeLongName(choice6));
#endif if (DBConnectsTo(i, lab->lab_type))
/* If the flag is set, don't cause a netlist change by moving a {
the label. So unless there's only space here, delete the label */ if (DBPlane(i) == plane)
if(choice5 == TT_SPACE && choice6 == TT_SPACE) {
return TT_SPACE; if (TTMaskHasType(&types[0], i))
else {
return -1; choice1 = i;
continue;
}
else if (TTMaskHasType(&types[1], i))
{
choice2 = i;
continue;
}
}
if (TTMaskHasType(&types[0], i))
{
choice3 = i;
continue;
}
else if (TTMaskHasType(&types[1], i))
{
choice4 = i;
continue;
}
}
if ((DBPlane(i) == plane) || (lab->lab_type == TT_SPACE))
{
if (TTMaskHasType(&types[0], i))
{
/* A type that connects to more than itself is preferred */
if (choice5 == TT_SPACE)
choice5 = i;
else
{
TileTypeBitMask ctest;
TTMaskZero(&ctest);
TTMaskSetMask(&ctest, &DBConnectTbl[i]);
TTMaskClearType(&ctest, i);
if (!TTMaskIsZero(&ctest))
choice5 = i;
else if (TTMaskHasType(&types[1], i))
choice6 = i;
}
continue;
}
else if (TTMaskHasType(&types[1], i))
{
choice6 = i;
continue;
}
}
}
}
if (choice1 != TT_SPACE) return choice1;
else if (choice2 != TT_SPACE) return choice2;
else if (choice3 != TT_SPACE) return choice3;
else if (choice4 != TT_SPACE) return choice4;
else if (choice5 != TT_SPACE) return choice5;
else return choice6;
} }
else if (choice5 != TT_SPACE) return choice5;
else return choice6;
} }
/* Search function for DBPickLabelLayer: just OR in the type of /* Search function for DBPickLabelLayer: just OR in the type of

View File

@ -2310,7 +2310,7 @@ origin_error:
} }
else else
{ {
DBAdjustLabelsNew(lefMacro, &TiPlaneRect, 1); DBAdjustLabelsNew(lefMacro, &TiPlaneRect);
if (has_size) if (has_size)
{ {