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