1 /* DBtimestamp.c --
2  *
3  *	Provides routines to help manage the timestamps stored in
4  *	cell definitions.
5  *
6  *     *********************************************************************
7  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
8  *     * Permission to use, copy, modify, and distribute this              *
9  *     * software and its documentation for any purpose and without        *
10  *     * fee is hereby granted, provided that the above copyright          *
11  *     * notice appear in all copies.  The University of California        *
12  *     * makes no representations about the suitability of this            *
13  *     * software for any purpose.  It is provided "as is" without         *
14  *     * express or implied warranty.  Export of this software outside     *
15  *     * of the United States of America may require an export license.    *
16  *     *********************************************************************
17  */
18 
19 #ifndef lint
20 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 $";
21 #endif  /* not lint */
22 
23 #include <stdio.h>
24 #include <sys/types.h>
25 
26 #include "utils/magic.h"
27 #include "utils/geometry.h"
28 #include "tiles/tile.h"
29 #include "utils/hash.h"
30 #include "database/database.h"
31 #include "database/databaseInt.h"
32 #include "windows/windows.h"
33 #include "textio/textio.h"
34 #include "drc/drc.h"
35 #include "utils/signals.h"
36 #include "utils/malloc.h"
37 
38 /* Overall comments:
39  *
40  * Cell timestamps are kept around primarily for the benefit
41  * of the design rule checker.  In order for the hierarchical
42  * and continuous checker to work, we have to make sure that
43  * we know whenever cells have changed, even if a cell is
44  * edited out of context.  Thus, we record a timestamp value
45  * in every cell, which is the time when the cell was last
46  * modified.  The timestamp for a cell should always be at
47  * least as large as the latest timestamp for any of that
48  * cell's descendants (larger timestamps correspond to later
49  * times).  If a child is edited out of context, this condition
50  * may be violated, so each parent keeps an expected timestamp
51  * for each of its children.  If the actual child timestamp is
52  * ever found to be different, we must re-check interactions
53  * between that child and other pieces of the parent, and then
54  * update the parent's timestamp.  If a child changes, then
55  * timestamps must be changed in all parents of the child, their
56  * parents, and so on, so that we're guaranteed to see interactions
57  * coming even from several levels up the tree.
58  */
59 
60 /* The structure below is used to keep track of cells whose timestamps
61  * mismatched.  The DBStampMismatch routine creates this structure.
62  * at convenient times (between commands), the DBFixMismatch routine
63  * is called to process the entries.  It updates bounding boxes (the
64  * bounding box update cannot be done at arbitrary times, because it
65  * can reorganize tile planes that are pending in searches.  The
66  * indentation below is necessary to keep lintpick happy.
67  */
68 
69     typedef struct mm {
70 	CellDef *mm_cellDef;		/* CellDef whose stamp was wrong. */
71 	Rect mm_oldArea;		/* The old area that the cellDef used
72 					 * to occupy.
73 					 */
74 	struct mm *mm_next;		/* Next mismatch record in list. */
75     } Mismatch;
76 
77     Mismatch *mismatch = NULL;		/* List head. */
78 
79 
80 /* The time value below is passed to the dbStampFunct so it
81  * uses the same value everywhere, and doesn't have to call
82  * the system routine repeatedly.
83  */
84 
85 int timestamp;
86 
87 
88 /*
89  * ----------------------------------------------------------------------------
90  *	DBFixMismatch --
91  *
92  * 	This procedure is called when it safe to recompute bounding
93  *	boxes in order to fix timestamp mismatches.
94  *
95  * Results:
96  *	None.
97  *
98  * Side effects:
99  *	Bounding boxes get recomputed and information gets passed to
100  *	the DRC module.  The DRC module will recheck both the old and
101  *	new areas of the cell whose timestamp mismatched.
102  * ----------------------------------------------------------------------------
103  */
104 
105 void
DBFixMismatch()106 DBFixMismatch()
107 {
108     CellDef *cellDef;
109     CellUse *parentUse;
110     Rect oldArea, parentArea, tmp;
111     int redisplay;
112     int firstOne = TRUE;
113     Mismatch *tmpm;
114 
115     /* It's very important to disable interrupts during this section!
116      * Otherwise, we may not paint the recheck tiles properly.
117      */
118 
119     redisplay = FALSE;
120     if (mismatch == NULL) return;
121     TxPrintf("Processing timestamp mismatches:");
122     SigDisableInterrupts();
123 
124     for (tmpm = mismatch; tmpm; tmpm = tmpm->mm_next)
125 	tmpm->mm_cellDef->cd_flags &= (~CDPROCESSED);
126 
127     while (mismatch != NULL)
128     {
129 	bool dereference;
130 
131 	/* Be careful to remove the front element from the mismatch
132 	 * list before processing it, because while processing it we
133 	 * may add new elements to the list.
134 	 */
135 
136 	cellDef = mismatch->mm_cellDef;
137 	oldArea = mismatch->mm_oldArea;
138 	freeMagic((char *) mismatch);
139 	mismatch = mismatch->mm_next;
140 	if (cellDef->cd_flags & CDPROCESSED) continue;
141 
142 	dereference = (cellDef->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
143 	(void) DBCellRead(cellDef, (char *) NULL, TRUE, dereference, NULL);
144 
145 	/* Jimmy up the cell's current bounding box, so the following
146 	 * procedure call will absolutely and positively know that
147 	 * the bbox has changed.  This is necessary because not all
148 	 * the uses necessarily reflect the current def bounding box,
149 	 * and we want DBReComputeArea to be sure to update all of
150 	 * the uses.
151 	 */
152 
153 	cellDef->cd_bbox.r_xtop = cellDef->cd_bbox.r_xbot - 1;
154 	cellDef->cd_extended.r_xtop = cellDef->cd_extended.r_xbot - 1;
155 	DBReComputeBbox(cellDef);
156 
157 	/* Now, for each parent, recheck the parent in both the
158 	 * old area of the child and the new area.
159 	 */
160 
161 	for (parentUse = cellDef->cd_parents; parentUse != NULL;
162 	    parentUse = parentUse->cu_nextuse)
163 	{
164 	    if (parentUse->cu_parent == NULL) continue;
165 	    DBComputeArrayArea(&oldArea, parentUse, parentUse->cu_xlo,
166 		parentUse->cu_ylo, &parentArea);
167 	    DBComputeArrayArea(&oldArea, parentUse, parentUse->cu_xhi,
168 		parentUse->cu_yhi, &tmp);
169 	    (void) GeoInclude(&parentArea, &tmp);
170 	    GeoTransRect(&parentUse->cu_transform, &tmp, &parentArea);
171 	    DRCCheckThis(parentUse->cu_parent, TT_CHECKSUBCELL, &parentArea);
172 	    DRCCheckThis(parentUse->cu_parent, TT_CHECKSUBCELL,
173 		&(parentUse->cu_bbox));
174 	    redisplay = TRUE;
175 	}
176 	cellDef->cd_flags |= CDPROCESSED;
177 	if (firstOne)
178 	{
179 	    TxPrintf(" %s", cellDef->cd_name);
180 	    firstOne = FALSE;
181 	}
182 	else TxPrintf(", %s", cellDef->cd_name);
183 	TxFlush();	/* This is needed to prevent _doprnt screwups */
184     }
185     SigEnableInterrupts();
186     TxPrintf(".\n");
187     TxFlush();
188     if (redisplay) WindAreaChanged((MagWindow *) NULL, (Rect *) NULL);
189 }
190 
191 
192 /*
193  * ----------------------------------------------------------------------------
194  *	DBUpdateStamps --
195  *
196  * 	Updates all timestamps in all cells in the database.
197  *
198  * Results:
199  *	None.
200  *
201  * Side effects:
202  *	For every cell that has been modified, its timestamp and
203  *	the timestamps of all its parents, grandparents, etc. are
204  *	updated.  The result is that the timestamp in any given cell is
205  *	at least as great as the timestamps in any of its descendants.
206  * ----------------------------------------------------------------------------
207  */
208 
209 void
DBUpdateStamps()210 DBUpdateStamps()
211 {
212     extern int dbStampFunc();
213     extern time_t time();
214 
215     DBFixMismatch();
216     timestamp = time((time_t *) 0);
217     (void) DBCellSrDefs(CDGETNEWSTAMP, dbStampFunc, (ClientData) NULL);
218 }
219 
220 int
dbStampFunc(cellDef)221 dbStampFunc(cellDef)
222     CellDef *cellDef;
223 {
224     CellUse *cu;
225     CellDef *cd;
226 
227     /* The following check keeps us from making multiple recursive
228      * scans of any cell.
229      */
230 
231     if (cellDef->cd_timestamp == timestamp) return 0;
232 
233     cellDef->cd_timestamp = timestamp;
234     cellDef->cd_flags &= ~CDGETNEWSTAMP;
235 
236     /* printf("Writing new timestamp %d for %s.\n",
237 	timestamp, cellDef->cd_name); */
238 
239     /* If a child's stamp has changed, then the stamps must change
240      * in all its parents too.  When the hierarchical DRC becomes
241      * completely operational, this recursive update may be unnecessary
242      * since the DRC will have painted check tiles in all ancestors.
243      */
244 
245     for (cu = cellDef->cd_parents; cu != NULL; cu = cu->cu_nextuse)
246     {
247 	cd = cu->cu_parent;
248 	if (cd == NULL) continue;
249 	cd->cd_flags |= CDSTAMPSCHANGED;
250 	(void) dbStampFunc(cd);
251     }
252     return 0;
253 }
254 
255 
256 /*
257  * ----------------------------------------------------------------------------
258  *	DBStampMismatch --
259  *
260  * 	This routine is invoked when a mismatch is discovered for a
261  *	cell.  The parameter wrongArea tells what the cell's bounding
262  *	box used to be (but the timestamp mismatch means this was
263  *	probably wrong, so that area has to be re-design-rule-checked).
264  *
265  * Results:
266  *	None.
267  *
268  * Side effects:
269  *	We record the definition on a list of mismatches for later
270  *	processing.  When DBFixMismatch is called, it will notify
271  *	the design-rule checker to recheck both wrongArea, and
272  *	the cell's eventual correct area.
273  *
274  * This routine has been modified from a poor implementation.  Previously
275  * the parent def of all uses of the cell being checked would be marked
276  * for a stamp mismatch check.  However, when reading a cell with large
277  * numbers of instances, the list of instances would be parsed for every
278  * instance added, leading to an O(N^2) computation.  Routine DBStampMismatch()
279  * has been broken into two parts.  DBStampMismatch() only records the
280  * area to be checked.  DBFlagMismatches() looks at the parents of each
281  * celldef only once, after all instances have been read.
282  *
283  * ----------------------------------------------------------------------------
284  */
285 
286 void
DBStampMismatch(cellDef,wrongArea)287 DBStampMismatch(cellDef, wrongArea)
288     CellDef *cellDef;
289     Rect *wrongArea;			/* Guess of cell's bounding box that
290 					 * was wrong.
291 					 */
292 {
293     Mismatch *mm;
294 
295     mm = (Mismatch *) mallocMagic((unsigned) (sizeof (Mismatch)));
296     mm->mm_cellDef = cellDef;
297     mm->mm_oldArea = *wrongArea;
298     mm->mm_next = mismatch;
299     mismatch = mm;
300 }
301 
302 /*
303  * ----------------------------------------------------------------------------
304  * ----------------------------------------------------------------------------
305  */
306 
307 void
DBFlagMismatches(checkDef)308 DBFlagMismatches(checkDef)
309     CellDef *checkDef;
310 {
311     CellUse *parentUse;
312 
313     for (parentUse = checkDef->cd_parents; parentUse != NULL;
314 		    parentUse = parentUse->cu_nextuse)
315     {
316 	if (parentUse->cu_parent == NULL) continue;
317 	parentUse->cu_parent->cd_flags |= CDSTAMPSCHANGED;
318     }
319 }
320