From 59bfa6ce86f403ad1fa3adcd63fb0c738e379a5e Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 16 Mar 2021 22:46:46 -0400 Subject: [PATCH] Found no fewer than three separate places that cause a pop-up prompt for saving on a cell which is completely unmodified. One of these was due to the BPlane implementation, which forces an instance to be deleted and re-placed on a bounding box recomputation, which should not, in that case, be considered a modification. Another always runs DRC on a subcell upon reading rather than relying on any checkplane entries in the file itself; and the last one marking the timestamp as modified stemming from an attempt to correct an O(N^2) check to O(N). All three cases have now been corrected. --- database/DBcell.c | 73 ++++++++++++++++++++++++++++++++++++++++++ database/DBcellbox.c | 4 +-- database/DBio.c | 9 ++++-- database/database.h.in | 2 ++ 4 files changed, 83 insertions(+), 5 deletions(-) diff --git a/database/DBcell.c b/database/DBcell.c index 2ff4777c..e5c5bcbb 100644 --- a/database/DBcell.c +++ b/database/DBcell.c @@ -118,6 +118,7 @@ DBCellFindDup(use, parent) * ---------------------------------------------------------------------------- * * DBPlaceCell -- + * DBPlaceCellNoModify -- * * Add a CellUse to the subcell tile plane of a CellDef. * Assumes prior check that the new CellUse is not an exact duplicate @@ -162,11 +163,47 @@ DBPlaceCell (use, def) SigEnableInterrupts(); } +/* Like DBPlaceCell(), but don't change the flags of the parent cell. */ +/* This is needed by the bounding box recalculation routine, which may */ +/* cause the cell to be deleted and replaced for the purpose of */ +/* capturing the bounding box information in the BPlane structure, but */ +/* this does not mean that anything in the parent cell has changed. */ + +void +DBPlaceCellNoModify (use, def) + CellUse * use; /* new celluse to add to subcell tile plane */ + CellDef * def; /* parent cell's definition */ +{ + Rect rect; /* argument to DBSrCellPlaneArea(), placeCellFunc() */ + BPlane *bplane; /* argument to DBSrCellPlaneArea(), placeCellFunc() */ + struct searchArg arg; /* argument to placeCellFunc() */ + + ASSERT(use != (CellUse *) NULL, "DBPlaceCell"); + ASSERT(def, "DBPlaceCell"); + + /* To do: Check non-duplicate placement, check non-duplicate ID */ + + use->cu_parent = def; + + /* Be careful not to permit interrupts during this, or the + * database could be left in a trashed state. + */ + + SigDisableInterrupts(); + BPAdd(def->cd_cellPlane, use); + if (UndoIsEnabled()) + DBUndoCellUse(use, UNDO_CELL_PLACE); + SigEnableInterrupts(); +} + /* * ---------------------------------------------------------------------------- * DBDeleteCell -- * * Remove a CellUse from the subcell tile plane of a CellDef. + * If "nomodify" is TRUE, then don't set the parent cell's CDMODIFIED flag. + * This is needed when recomputing the bounding box, which should not by + * itself change the modified state. * * Results: * None. @@ -197,3 +234,39 @@ DBDeleteCell (use) SigEnableInterrupts(); } +/* + * ---------------------------------------------------------------------------- + * DBDeleteCellNoModify -- + * + * Remove a CellUse from the subcell tile plane of a CellDef, as above, + * but don't set the parent cell's CDMODIFIED flag. This is needed when + * recomputing the bounding box, which should not by itself change the + * modified state. + * + * Results: + * None. + * + * Side effects: + * Modifies the subcell tile plane of the CellDef, sets the + * parent pointer of the deleted CellUse to NULL. + * ---------------------------------------------------------------------------- + */ + +void +DBDeleteCellNoModify (use) + CellUse * use; +{ + ASSERT(use != (CellUse *) NULL, "DBDeleteCell"); + + /* It's important that this code run with interrupts disabled, + * or else we could leave the subcell tile plane in a weird + * state. + */ + + SigDisableInterrupts(); + dbInstanceUnplace(use); + if (UndoIsEnabled()) + DBUndoCellUse(use, UNDO_CELL_DELETE); + use->cu_parent = (CellDef *) NULL; + SigEnableInterrupts(); +} diff --git a/database/DBcellbox.c b/database/DBcellbox.c index e3d17408..55b8f327 100644 --- a/database/DBcellbox.c +++ b/database/DBcellbox.c @@ -723,7 +723,7 @@ dbReComputeBboxFunc(cellDef, boundProc, recurseProc) */ parent = use->cu_parent; - DBDeleteCell(use); + DBDeleteCellNoModify(use); use->cu_parent = parent; } @@ -751,7 +751,7 @@ dbReComputeBboxFunc(cellDef, boundProc, recurseProc) if ((parent = use->cu_parent) != (CellDef *) NULL) { parent->cd_flags |= CDBOXESCHANGED; - DBPlaceCell(use, parent); + DBPlaceCellNoModify(use, parent); if (last != parent) { if (last != NULL) (*recurseProc)(last); diff --git a/database/DBio.c b/database/DBio.c index e9026ef8..2b4747bd 100644 --- a/database/DBio.c +++ b/database/DBio.c @@ -411,7 +411,7 @@ dbCellReadDef(f, cellDef, name, ignoreTech, dereference) int cellStamp = 0, rectCount = 0, rectReport = 10000; char line[2048], tech[50], layername[50]; PaintResultType *ptable; - bool result = TRUE, scaleLimit = FALSE; + bool result = TRUE, scaleLimit = FALSE, has_mismatch; Rect *rp; int c; TileType type, rtype, loctype; @@ -844,6 +844,7 @@ done: * timestamp, then force the cell to be written out with a * correct timestamp. */ + has_mismatch = FALSE; if ((cellDef->cd_timestamp != cellStamp) || (cellStamp == 0)) { CellUse *cu; @@ -852,12 +853,13 @@ done: if (cu->cu_parent != NULL) { DBStampMismatch(cellDef, &cellDef->cd_bbox); + has_mismatch = TRUE; break; } } } /* Update timestamp flags */ - DBFlagMismatches(cellDef); + if (has_mismatch) DBFlagMismatches(cellDef); cellDef->cd_timestamp = cellStamp; if (cellStamp == 0) @@ -869,7 +871,8 @@ done: } UndoEnable(); - DRCCheckThis(cellDef, TT_CHECKPAINT, (Rect *) NULL); + /* Disabled 3/16/2021. Let <> in file force a DRC check */ + /* DRCCheckThis(cellDef, TT_CHECKPAINT, (Rect *) NULL); */ SigEnableInterrupts(); return (result); diff --git a/database/database.h.in b/database/database.h.in index 18ed836d..a8c88e57 100644 --- a/database/database.h.in +++ b/database/database.h.in @@ -790,7 +790,9 @@ extern CellUse *DBFindUse(); /* Insertion/deletion of cell uses into the cell tile plane of a parent */ extern void DBPlaceCell(); +extern void DBPlaceCellNoModify(); extern void DBDeleteCell(); +extern void DBDeleteCellNoModify(); extern void DBClearCellPlane(); /* Insertion/deletion of cell uses into the name space of a parent */