2017-04-25 14:41:48 +02:00
|
|
|
/* DBtimestamp.c --
|
|
|
|
|
*
|
|
|
|
|
* Provides routines to help manage the timestamps stored in
|
|
|
|
|
* cell definitions.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * 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. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#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;
|
|
|
|
|
|
2023-04-15 16:44:50 +02:00
|
|
|
typedef struct _celllist {
|
|
|
|
|
CellDef *cl_cell;
|
|
|
|
|
struct _celllist *cl_next;
|
|
|
|
|
} CellList;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* 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;
|
2023-04-15 16:44:50 +02:00
|
|
|
CellList *cl = NULL, *clnew;
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
2023-04-15 16:44:50 +02:00
|
|
|
TxPrintf("Processing timestamp mismatches.\n");
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
|
|
|
|
freeMagic((char *) mismatch);
|
|
|
|
|
mismatch = mismatch->mm_next;
|
|
|
|
|
if (cellDef->cd_flags & CDPROCESSED) continue;
|
|
|
|
|
|
2023-04-18 17:01:58 +02:00
|
|
|
(void) DBCellRead(cellDef, TRUE, TRUE, NULL);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
cellDef->cd_bbox.r_xtop = cellDef->cd_bbox.r_xbot - 1;
|
|
|
|
|
cellDef->cd_extended.r_xtop = cellDef->cd_extended.r_xbot - 1;
|
|
|
|
|
DBReComputeBbox(cellDef);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* 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;
|
2023-04-15 16:44:50 +02:00
|
|
|
clnew = (CellList *)mallocMagic(sizeof(CellList));
|
|
|
|
|
clnew->cl_cell = cellDef;
|
|
|
|
|
clnew->cl_next = cl;
|
|
|
|
|
cl = clnew;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
SigEnableInterrupts();
|
2023-04-15 16:44:50 +02:00
|
|
|
TxPrintf("Timestamp mismatches found in these cells: ");
|
|
|
|
|
while (cl != NULL)
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("%s", cl->cl_cell->cd_name);
|
|
|
|
|
if (cl->cl_next != NULL) TxPrintf(", ");
|
|
|
|
|
freeMagic(cl);
|
|
|
|
|
cl = cl->cl_next;
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
TxPrintf(".\n");
|
|
|
|
|
TxFlush();
|
|
|
|
|
if (redisplay) WindAreaChanged((MagWindow *) NULL, (Rect *) NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* 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
|
2022-01-22 04:17:54 +01:00
|
|
|
DBUpdateStamps(def)
|
|
|
|
|
CellDef *def;
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
extern int dbStampFunc();
|
|
|
|
|
extern time_t time();
|
|
|
|
|
|
|
|
|
|
DBFixMismatch();
|
2022-01-22 17:18:32 +01:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
timestamp = time((time_t *) 0);
|
2022-01-22 04:17:54 +01:00
|
|
|
if (def == NULL)
|
|
|
|
|
(void) DBCellSrDefs(CDGETNEWSTAMP, dbStampFunc, (ClientData) NULL);
|
2022-01-22 17:18:32 +01:00
|
|
|
|
2022-01-22 04:17:54 +01:00
|
|
|
else if (def->cd_flags & CDGETNEWSTAMP)
|
2022-01-22 17:18:32 +01:00
|
|
|
{
|
|
|
|
|
if (def->cd_flags & CDFIXEDSTAMP)
|
|
|
|
|
def->cd_flags &= ~CDGETNEWSTAMP;
|
|
|
|
|
else
|
|
|
|
|
dbStampFunc(def);
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
dbStampFunc(cellDef)
|
|
|
|
|
CellDef *cellDef;
|
|
|
|
|
{
|
|
|
|
|
CellUse *cu;
|
|
|
|
|
CellDef *cd;
|
|
|
|
|
|
|
|
|
|
/* The following check keeps us from making multiple recursive
|
|
|
|
|
* scans of any cell.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (cellDef->cd_timestamp == timestamp) return 0;
|
|
|
|
|
|
2022-01-22 17:18:32 +01:00
|
|
|
if (!(cellDef->cd_flags & CDFIXEDSTAMP))
|
|
|
|
|
cellDef->cd_timestamp = timestamp;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
cellDef->cd_flags &= ~CDGETNEWSTAMP;
|
|
|
|
|
|
2022-01-22 17:18:32 +01:00
|
|
|
// printf("Writing new timestamp %d for %s.\n", timestamp, cellDef->cd_name);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* DBStampMismatch --
|
2020-05-23 23:13:14 +02:00
|
|
|
*
|
2017-04-25 14:41:48 +02:00
|
|
|
* 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.
|
2019-08-02 20:50:32 +02:00
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
2017-04-25 14:41:48 +02:00
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
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;
|
2019-08-02 20:50:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
DBFlagMismatches(checkDef)
|
|
|
|
|
CellDef *checkDef;
|
|
|
|
|
{
|
|
|
|
|
CellUse *parentUse;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2019-08-02 20:50:32 +02:00
|
|
|
for (parentUse = checkDef->cd_parents; parentUse != NULL;
|
|
|
|
|
parentUse = parentUse->cu_nextuse)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
if (parentUse->cu_parent == NULL) continue;
|
|
|
|
|
parentUse->cu_parent->cd_flags |= CDSTAMPSCHANGED;
|
|
|
|
|
}
|
|
|
|
|
}
|