magic/database/DBtimestmp.c

363 lines
12 KiB
C
Raw Normal View History

/* DBtimestamp.c --
*
* Provides routines to help manage the timestamps stored in
* cell definitions.
*
* *********************************************************************
* * 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/DBtimestmp.c,v 1.2 2009/05/30 03:13:59 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <sys/types.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "windows/windows.h"
#include "textio/textio.h"
#include "drc/drc.h"
#include "utils/signals.h"
#include "utils/malloc.h"
/* Overall comments:
*
* Cell timestamps are kept around primarily for the benefit
* of the design rule checker. In order for the hierarchical
* and continuous checker to work, we have to make sure that
* we know whenever cells have changed, even if a cell is
* edited out of context. Thus, we record a timestamp value
* in every cell, which is the time when the cell was last
* modified. The timestamp for a cell should always be at
* least as large as the latest timestamp for any of that
* cell's descendants (larger timestamps correspond to later
* times). If a child is edited out of context, this condition
* may be violated, so each parent keeps an expected timestamp
* for each of its children. If the actual child timestamp is
* ever found to be different, we must re-check interactions
* between that child and other pieces of the parent, and then
* update the parent's timestamp. If a child changes, then
* timestamps must be changed in all parents of the child, their
* parents, and so on, so that we're guaranteed to see interactions
* coming even from several levels up the tree.
*/
/* The structure below is used to keep track of cells whose timestamps
* mismatched. The DBStampMismatch routine creates this structure.
* at convenient times (between commands), the DBFixMismatch routine
* is called to process the entries. It updates bounding boxes (the
* bounding box update cannot be done at arbitrary times, because it
* can reorganize tile planes that are pending in searches. The
* indentation below is necessary to keep lintpick happy.
*/
typedef struct mm {
CellDef *mm_cellDef; /* CellDef whose stamp was wrong. */
Rect mm_oldArea; /* The old area that the cellDef used
* to occupy.
*/
struct mm *mm_next; /* Next mismatch record in list. */
} Mismatch;
Mismatch *mismatch = NULL; /* List head. */
/* The time value below is passed to the dbStampFunct so it
* uses the same value everywhere, and doesn't have to call
* the system routine repeatedly.
*/
int timestamp;
typedef struct _celllist {
CellDef *cl_cell;
struct _celllist *cl_next;
} CellList;
/*
* ----------------------------------------------------------------------------
* DBFixMismatch --
*
* This procedure is called when it safe to recompute bounding
* boxes in order to fix timestamp mismatches.
*
* Results:
* None.
*
* Side effects:
* Bounding boxes get recomputed and information gets passed to
* the DRC module. The DRC module will recheck both the old and
* new areas of the cell whose timestamp mismatched.
* ----------------------------------------------------------------------------
*/
void
DBFixMismatch()
{
CellDef *cellDef;
CellUse *parentUse;
CellList *cl = NULL, *clnew;
Rect oldArea, parentArea, tmp;
int redisplay;
Mismatch *tmpm;
/* It's very important to disable interrupts during this section!
* Otherwise, we may not paint the recheck tiles properly.
*/
redisplay = FALSE;
if (mismatch == NULL) return;
TxPrintf("Processing timestamp mismatches.\n");
SigDisableInterrupts();
for (tmpm = mismatch; tmpm; tmpm = tmpm->mm_next)
tmpm->mm_cellDef->cd_flags &= (~CDPROCESSED);
while (mismatch != NULL)
{
/* Be careful to remove the front element from the mismatch
* list before processing it, because while processing it we
* may add new elements to the list.
*/
cellDef = mismatch->mm_cellDef;
oldArea = mismatch->mm_oldArea;
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, (char *) mismatch);
mismatch = mismatch->mm_next;
freeMagic1_end(&mm1);
if (cellDef->cd_flags & CDPROCESSED) continue;
(void) DBCellRead(cellDef, TRUE, TRUE, NULL);
/* Jimmy up the cell's current bounding box, so the following
* procedure call will absolutely and positively know that
* the bbox has changed. This is necessary because not all
* the uses necessarily reflect the current def bounding box,
* and we want DBReComputeArea to be sure to update all of
* the uses.
*/
cellDef->cd_bbox.r_xtop = cellDef->cd_bbox.r_xbot - 1;
cellDef->cd_extended.r_xtop = cellDef->cd_extended.r_xbot - 1;
DBReComputeBbox(cellDef);
/* Now, for each parent, recheck the parent in both the
* old area of the child and the new area.
*/
for (parentUse = cellDef->cd_parents; parentUse != NULL;
parentUse = parentUse->cu_nextuse)
{
if (parentUse->cu_parent == NULL) continue;
DBComputeArrayArea(&oldArea, parentUse, parentUse->cu_xlo,
parentUse->cu_ylo, &parentArea);
DBComputeArrayArea(&oldArea, parentUse, parentUse->cu_xhi,
parentUse->cu_yhi, &tmp);
(void) GeoInclude(&parentArea, &tmp);
GeoTransRect(&parentUse->cu_transform, &tmp, &parentArea);
DRCCheckThis(parentUse->cu_parent, TT_CHECKSUBCELL, &parentArea);
DRCCheckThis(parentUse->cu_parent, TT_CHECKSUBCELL,
&(parentUse->cu_bbox));
redisplay = TRUE;
}
cellDef->cd_flags |= CDPROCESSED;
clnew = (CellList *)mallocMagic(sizeof(CellList));
clnew->cl_cell = cellDef;
clnew->cl_next = cl;
cl = clnew;
}
SigEnableInterrupts();
TxPrintf("Timestamp mismatches found in these cells: ");
free_magic1_t mm1 = freeMagic1_init();
while (cl != NULL)
{
TxPrintf("%s", cl->cl_cell->cd_name);
if (cl->cl_next != NULL) TxPrintf(", ");
freeMagic1(&mm1, cl);
cl = cl->cl_next;
}
freeMagic1_end(&mm1);
TxPrintf(".\n");
TxFlush();
if (redisplay) WindAreaChanged((MagWindow *) NULL, (Rect *) NULL);
}
/*
* ----------------------------------------------------------------------------
* DBUpdateStamps --
*
* Updates all timestamps in all cells in the database.
*
* Results:
* None.
*
* Side effects:
* For every cell that has been modified, its timestamp and
* the timestamps of all its parents, grandparents, etc. are
* updated. The result is that the timestamp in any given cell is
* at least as great as the timestamps in any of its descendants.
* ----------------------------------------------------------------------------
*/
void
DBUpdateStamps(def)
CellDef *def;
{
extern int dbStampFunc();
extern time_t time();
DBFixMismatch();
timestamp = time((time_t *) 0);
if (def == NULL)
(void) DBCellSrDefs(CDGETNEWSTAMP, dbStampFunc, (ClientData) NULL);
else if (def->cd_flags & CDGETNEWSTAMP)
{
if (def->cd_flags & (CDNOEDIT | CDFIXEDSTAMP))
def->cd_flags &= ~CDGETNEWSTAMP;
else
dbStampFunc(def);
}
}
int
Add ClientData parameter to indirect-call callbacks for WASM WASM call_indirect enforces an exact type match between the caller and the callee. Many Magic callbacks had K&R-style () forward declarations and a single-argument definition, but were passed to iterators that always push a trailing ClientData argument. Native builds tolerated the mismatch via loose prototypes; WASM traps with "indirect call signature mismatch". Added the missing ClientData (or, where the concrete type is known, FindRegion *) parameter to: * calma/CalmaRead.c, calma/CalmaWrite.c, calma/CalmaWriteZ.c — calmaWriteInitFunc * cif/CIFwrite.c — cifWriteInitFunc * commands/CmdSubrs.c — cmdWindSet * database/DBtimestmp.c — dbStampFunc * dbwind/DBWelement.c — dbwElementAlways1 * dbwind/DBWfdback.c — dbwfbWindFunc * dbwind/DBWhlights.c — DBWHLRedrawWind * ext2spice/ext2hier.c — spcnodeHierVisit * extract/ExtBasic.c — extSDTileFunc, extTransPerimFunc, extAnnularTileFunc, extResistorTileFunc * extract/ExtMain.c — extDefInitFunc * extract/ExtTimes.c — extTimesInitFunc Also adjusted commands/CmdE.c and commands/CmdTZ.c: SelectExpand was being called with four arguments (the legacy surroundFlag), but its real signature has been three arguments for years (the surround mode is encoded in the expandType bit). The fourth argument was redundant (DB_EXPAND_SURROUND in arg 2 is the source of truth) and rejected by WASM. Native behavior is unchanged. The added parameters are unused in the function bodies; they exist only to satisfy the indirect-call signature.
2026-05-04 13:29:11 +02:00
dbStampFunc(cellDef, cdata)
CellDef *cellDef;
Add ClientData parameter to indirect-call callbacks for WASM WASM call_indirect enforces an exact type match between the caller and the callee. Many Magic callbacks had K&R-style () forward declarations and a single-argument definition, but were passed to iterators that always push a trailing ClientData argument. Native builds tolerated the mismatch via loose prototypes; WASM traps with "indirect call signature mismatch". Added the missing ClientData (or, where the concrete type is known, FindRegion *) parameter to: * calma/CalmaRead.c, calma/CalmaWrite.c, calma/CalmaWriteZ.c — calmaWriteInitFunc * cif/CIFwrite.c — cifWriteInitFunc * commands/CmdSubrs.c — cmdWindSet * database/DBtimestmp.c — dbStampFunc * dbwind/DBWelement.c — dbwElementAlways1 * dbwind/DBWfdback.c — dbwfbWindFunc * dbwind/DBWhlights.c — DBWHLRedrawWind * ext2spice/ext2hier.c — spcnodeHierVisit * extract/ExtBasic.c — extSDTileFunc, extTransPerimFunc, extAnnularTileFunc, extResistorTileFunc * extract/ExtMain.c — extDefInitFunc * extract/ExtTimes.c — extTimesInitFunc Also adjusted commands/CmdE.c and commands/CmdTZ.c: SelectExpand was being called with four arguments (the legacy surroundFlag), but its real signature has been three arguments for years (the surround mode is encoded in the expandType bit). The fourth argument was redundant (DB_EXPAND_SURROUND in arg 2 is the source of truth) and rejected by WASM. Native behavior is unchanged. The added parameters are unused in the function bodies; they exist only to satisfy the indirect-call signature.
2026-05-04 13:29:11 +02:00
ClientData cdata;
{
CellUse *cu;
CellDef *cd;
/* The following check keeps us from making multiple recursive
* scans of any cell.
*/
if (cellDef->cd_timestamp == timestamp) return 0;
/* Non-editable cells should not try to update timestamps, as the
* new timestamp cannot be written back to the file. This is
* basically a hack solution for the problem that running DRC on
* all cells causes all cells, including non-editable ones, to be
* marked as modified, even if there were no DRC changes in the
* cell. It is possible to get into trouble this way by modifying
* a cell and then marking it as non-editable
*/
if (cellDef->cd_flags & CDNOEDIT)
{
cellDef->cd_flags &= ~CDGETNEWSTAMP;
return 0;
}
/*
* Do not force a non-edit cell or a cell with a fixed timestamp
* to update its timestamp, as it cannot or should not. Just clear
* any flag suggesting that it needs a new timestamp.
*/
if (!(cellDef->cd_flags & CDFIXEDSTAMP))
cellDef->cd_timestamp = timestamp;
cellDef->cd_flags &= ~CDGETNEWSTAMP;
// printf("Writing new timestamp %d for %s.\n", timestamp, cellDef->cd_name);
/* If a child's stamp has changed, then the stamps must change
* in all its parents too. When the hierarchical DRC becomes
* completely operational, this recursive update may be unnecessary
* since the DRC will have painted check tiles in all ancestors.
*/
for (cu = cellDef->cd_parents; cu != NULL; cu = cu->cu_nextuse)
{
cd = cu->cu_parent;
if (cd == NULL) continue;
cd->cd_flags |= CDSTAMPSCHANGED;
(void) dbStampFunc(cd);
}
return 0;
}
/*
* ----------------------------------------------------------------------------
* DBStampMismatch --
*
* This routine is invoked when a mismatch is discovered for a
* cell. The parameter wrongArea tells what the cell's bounding
* box used to be (but the timestamp mismatch means this was
* probably wrong, so that area has to be re-design-rule-checked).
*
* Results:
* None.
*
* Side effects:
* We record the definition on a list of mismatches for later
* processing. When DBFixMismatch is called, it will notify
* the design-rule checker to recheck both wrongArea, and
* the cell's eventual correct area.
*
* This routine has been modified from a poor implementation. Previously
* the parent def of all uses of the cell being checked would be marked
* for a stamp mismatch check. However, when reading a cell with large
* numbers of instances, the list of instances would be parsed for every
* instance added, leading to an O(N^2) computation. Routine DBStampMismatch()
* has been broken into two parts. DBStampMismatch() only records the
* area to be checked. DBFlagMismatches() looks at the parents of each
* celldef only once, after all instances have been read.
*
* ----------------------------------------------------------------------------
*/
void
DBStampMismatch(cellDef, wrongArea)
CellDef *cellDef;
Rect *wrongArea; /* Guess of cell's bounding box that
* was wrong.
*/
{
Mismatch *mm;
mm = (Mismatch *) mallocMagic((unsigned) (sizeof (Mismatch)));
mm->mm_cellDef = cellDef;
mm->mm_oldArea = *wrongArea;
mm->mm_next = mismatch;
mismatch = mm;
}
/*
* ----------------------------------------------------------------------------
* ----------------------------------------------------------------------------
*/
void
DBFlagMismatches(checkDef)
CellDef *checkDef;
{
CellUse *parentUse;
for (parentUse = checkDef->cd_parents; parentUse != NULL;
parentUse = parentUse->cu_nextuse)
{
if (parentUse->cu_parent == NULL) continue;
parentUse->cu_parent->cd_flags |= CDSTAMPSCHANGED;
}
}