2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ExtMain.c --
|
|
|
|
|
*
|
|
|
|
|
* Circuit extraction.
|
|
|
|
|
* Command interface.
|
|
|
|
|
*
|
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/extract/ExtMain.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "utils/styles.h"
|
|
|
|
|
#include "tiles/tile.h"
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
#include "database/database.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
#include "textio/textio.h"
|
|
|
|
|
#include "debug/debug.h"
|
|
|
|
|
#include "extract/extract.h"
|
|
|
|
|
#include "extract/extractInt.h"
|
|
|
|
|
#include "utils/signals.h"
|
|
|
|
|
#include "utils/stack.h"
|
|
|
|
|
#include "utils/utils.h"
|
|
|
|
|
#include "windows/windows.h"
|
|
|
|
|
#include "dbwind/dbwind.h"
|
|
|
|
|
#include "utils/main.h"
|
|
|
|
|
#include "utils/undo.h"
|
|
|
|
|
|
|
|
|
|
/* Imports from elsewhere in this module */
|
|
|
|
|
extern FILE *extFileOpen();
|
|
|
|
|
|
|
|
|
|
/* ------------------------ Exported variables ------------------------ */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* See extract.h for the bit flags that may be set in the following.
|
|
|
|
|
* If any are set, the corresponding warnings get generated, leaving
|
2020-11-24 21:30:49 +01:00
|
|
|
* feedback messages. If this word is zero, only errors are
|
2017-04-25 14:41:48 +02:00
|
|
|
* reported.
|
|
|
|
|
*/
|
|
|
|
|
int ExtDoWarn = EXTWARN_DUP|EXTWARN_FETS;
|
|
|
|
|
int ExtOptions = EXT_DOALL;
|
|
|
|
|
|
|
|
|
|
/* --------------------------- Global data ---------------------------- */
|
|
|
|
|
|
|
|
|
|
/* Cumulative yank buffer for hierarchical circuit extraction */
|
|
|
|
|
CellUse *extYuseCum = NULL;
|
|
|
|
|
CellDef *extYdefCum = NULL;
|
|
|
|
|
|
|
|
|
|
/* Identifier returned by the debug module for circuit extraction */
|
|
|
|
|
ClientData extDebugID;
|
|
|
|
|
|
|
|
|
|
/* Number of errors encountered during extraction */
|
|
|
|
|
int extNumFatal;
|
|
|
|
|
int extNumWarnings;
|
|
|
|
|
|
|
|
|
|
/* Dummy use pointing to def being extracted */
|
|
|
|
|
CellUse *extParentUse;
|
|
|
|
|
|
|
|
|
|
/* ------------------------ Data local to this file ------------------- */
|
|
|
|
|
|
|
|
|
|
/* Stack of defs pending extraction */
|
|
|
|
|
Stack *extDefStack;
|
|
|
|
|
|
|
|
|
|
/* Forward declarations */
|
|
|
|
|
int extDefInitFunc(), extDefPushFunc();
|
|
|
|
|
void extParents();
|
|
|
|
|
void extDefParentFunc();
|
|
|
|
|
void extDefParentAreaFunc();
|
|
|
|
|
void extExtractStack();
|
|
|
|
|
|
|
|
|
|
bool extContainsGeometry();
|
|
|
|
|
bool extContainsCellFunc();
|
|
|
|
|
bool extTimestampMisMatch();
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* ExtInit --
|
|
|
|
|
*
|
|
|
|
|
* Initialize the technology-independent part of the extraction module.
|
|
|
|
|
* This procedure should be called once, after the database module has
|
|
|
|
|
* been initialized.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Initializes the local variables of the extraction module.
|
|
|
|
|
* Registers the extractor with the debugging module.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ExtInit()
|
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
static struct
|
|
|
|
|
{
|
|
|
|
|
char *di_name;
|
|
|
|
|
int *di_id;
|
|
|
|
|
} debugFlags[] = {
|
|
|
|
|
"areaenum", &extDebAreaEnum,
|
|
|
|
|
"array", &extDebArray,
|
|
|
|
|
"hardway", &extDebHardWay,
|
|
|
|
|
"hiercap", &extDebHierCap,
|
|
|
|
|
"hierareacap", &extDebHierAreaCap,
|
|
|
|
|
"label", &extDebLabel,
|
|
|
|
|
"length", &extDebLength,
|
|
|
|
|
"neighbor", &extDebNeighbor,
|
|
|
|
|
"noarray", &extDebNoArray,
|
|
|
|
|
"nofeedback", &extDebNoFeedback,
|
|
|
|
|
"nohard", &extDebNoHard,
|
|
|
|
|
"nosubcell", &extDebNoSubcell,
|
|
|
|
|
"perimeter", &extDebPerim,
|
|
|
|
|
"resist", &extDebResist,
|
|
|
|
|
"visonly", &extDebVisOnly,
|
|
|
|
|
"yank", &extDebYank,
|
|
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Register ourselves with the debugging module */
|
|
|
|
|
extDebugID =
|
|
|
|
|
DebugAddClient("extract", sizeof debugFlags/sizeof debugFlags[0]);
|
|
|
|
|
for (n = 0; debugFlags[n].di_name; n++)
|
|
|
|
|
*(debugFlags[n].di_id) =
|
|
|
|
|
DebugAddFlag(extDebugID, debugFlags[n].di_name);
|
|
|
|
|
|
|
|
|
|
/* Create the yank buffer used for hierarchical extraction */
|
|
|
|
|
DBNewYank("__ext_cumulative", &extYuseCum, &extYdefCum);
|
|
|
|
|
|
|
|
|
|
/* Create the dummy use also used in hierarchical extraction */
|
|
|
|
|
extParentUse = DBCellNewUse(extYdefCum, (char *) NULL);
|
|
|
|
|
DBSetTrans(extParentUse, &GeoIdentityTransform);
|
|
|
|
|
|
|
|
|
|
/* Initialize the hash tables used in ExtLength.c */
|
|
|
|
|
extLengthInit();
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* ExtAll --
|
|
|
|
|
*
|
|
|
|
|
* Extract the subtree rooted at the CellDef 'rootUse->cu_def'.
|
|
|
|
|
* Each cell is extracted to a file in the current directory
|
|
|
|
|
* whose name consists of the last part of the cell's path,
|
|
|
|
|
* with a .ext suffix.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Creates a number of .ext files and writes to them.
|
|
|
|
|
* Adds feedback information where errors have occurred.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ExtAll(rootUse)
|
|
|
|
|
CellUse *rootUse;
|
|
|
|
|
{
|
|
|
|
|
/* Make sure the entire subtree is read in */
|
2021-01-14 21:21:39 +01:00
|
|
|
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
|
|
|
|
|
{
|
|
|
|
|
TxError("Failure to read entire subtree of cell.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* Fix up bounding boxes if they've changed */
|
|
|
|
|
DBFixMismatch();
|
|
|
|
|
|
|
|
|
|
/* Mark all defs as being unvisited */
|
|
|
|
|
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
|
|
|
|
|
|
|
|
|
|
/* Recursively visit all defs in the tree and push on stack */
|
|
|
|
|
extDefStack = StackNew(100);
|
|
|
|
|
(void) extDefPushFunc(rootUse);
|
|
|
|
|
|
|
|
|
|
/* Now extract all the cells we just found */
|
|
|
|
|
extExtractStack(extDefStack, TRUE, rootUse->cu_def);
|
|
|
|
|
StackFree(extDefStack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Function to initialize the client data field of all
|
|
|
|
|
* cell defs, in preparation for extracting a subtree
|
|
|
|
|
* rooted at a particular def.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
extDefInitFunc(def)
|
|
|
|
|
CellDef *def;
|
|
|
|
|
{
|
|
|
|
|
def->cd_client = (ClientData) 0;
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Function to push each cell def on extDefStack
|
|
|
|
|
* if it hasn't already been pushed, and then recurse
|
|
|
|
|
* on all that def's children.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
extDefPushFunc(use)
|
|
|
|
|
CellUse *use;
|
|
|
|
|
{
|
|
|
|
|
CellDef *def = use->cu_def;
|
|
|
|
|
|
|
|
|
|
if (def->cd_client || (def->cd_flags&CDINTERNAL))
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
def->cd_client = (ClientData) 1;
|
|
|
|
|
StackPush((ClientData) def, extDefStack);
|
|
|
|
|
(void) DBCellEnum(def, extDefPushFunc, (ClientData) 0);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* ExtUnique --
|
|
|
|
|
*
|
|
|
|
|
* For each cell in the subtree rooted at rootUse->cu_def, make
|
|
|
|
|
* sure that there are not two different nodes with the same label.
|
|
|
|
|
* If there are, we generate unique names by appending a numeric
|
|
|
|
|
* suffix to all but one of the offending labels.
|
|
|
|
|
* If "option" is 1 (tagged mode), then only labels ending in the
|
|
|
|
|
* character "#" are forced to be unique. If "option" is 2 (noports
|
|
|
|
|
* mode), then port labels are not forced to be unique. Finally,
|
|
|
|
|
* if the label has been changed and doesn't end in a '!', we leave
|
|
|
|
|
* feedback.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* May modify the label lists of some of the cells rooted
|
|
|
|
|
* at rootUse->cu_def, and mark the cells as CDMODIFIED.
|
|
|
|
|
* May also leave feedback.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ExtUnique(rootUse, option)
|
|
|
|
|
CellUse *rootUse;
|
|
|
|
|
int option;
|
|
|
|
|
{
|
|
|
|
|
CellDef *def;
|
|
|
|
|
int nwarn;
|
|
|
|
|
|
|
|
|
|
/* Make sure the entire subtree is read in */
|
2021-01-14 21:21:39 +01:00
|
|
|
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
|
|
|
|
|
{
|
|
|
|
|
TxError("Failure to read entire subtree of cell.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* Fix up bounding boxes if they've changed */
|
|
|
|
|
DBFixMismatch();
|
|
|
|
|
|
|
|
|
|
/* Mark all defs as being unvisited */
|
|
|
|
|
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
|
|
|
|
|
|
|
|
|
|
/* Recursively visit all defs in the tree and push on stack */
|
|
|
|
|
extDefStack = StackNew(100);
|
|
|
|
|
(void) extDefPushFunc(rootUse);
|
|
|
|
|
|
|
|
|
|
/* Now process all the cells we just found */
|
|
|
|
|
nwarn = 0;
|
|
|
|
|
while (def = (CellDef *) StackPop(extDefStack))
|
|
|
|
|
{
|
|
|
|
|
def->cd_client = (ClientData) 0;
|
|
|
|
|
if (!SigInterruptPending)
|
|
|
|
|
nwarn += extUniqueCell(def, option);
|
|
|
|
|
}
|
|
|
|
|
StackFree(extDefStack);
|
|
|
|
|
if (nwarn)
|
|
|
|
|
TxError("%d uncorrected errors (see the feedback info)\n", nwarn);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* ExtParents --
|
|
|
|
|
* ExtShowParents --
|
|
|
|
|
*
|
|
|
|
|
* ExtParents extracts the cell use->cu_def and all its parents.
|
|
|
|
|
* ExtShowParents merely finds and prints all the parents without
|
|
|
|
|
* extracting them.
|
|
|
|
|
*
|
|
|
|
|
* As in ExtAll, each cell is extracted to a file in the current
|
|
|
|
|
* directory whose name consists of the last part of the cell's path,
|
|
|
|
|
* with a .ext suffix.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Creates a number of .ext files and writes to them.
|
|
|
|
|
* Adds feedback information where errors have occurred.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ExtParents(use)
|
|
|
|
|
CellUse *use;
|
|
|
|
|
{
|
|
|
|
|
extParents(use, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ExtShowParents(use)
|
|
|
|
|
CellUse *use;
|
|
|
|
|
{
|
|
|
|
|
extParents(use, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
extParents(use, doExtract)
|
|
|
|
|
CellUse *use;
|
|
|
|
|
bool doExtract; /* If TRUE, we extract; if FALSE, we print */
|
|
|
|
|
{
|
|
|
|
|
/* Mark all defs as being unvisited */
|
|
|
|
|
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
|
|
|
|
|
|
|
|
|
|
/* Recursively visit all defs in the tree and push on stack */
|
|
|
|
|
extDefStack = StackNew(100);
|
|
|
|
|
extDefParentFunc(use->cu_def);
|
|
|
|
|
|
|
|
|
|
/* Now extract all the cells we just found */
|
|
|
|
|
extExtractStack(extDefStack, doExtract, (CellDef *) NULL);
|
|
|
|
|
StackFree(extDefStack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Function to visit all the parents of 'def' and push them on
|
|
|
|
|
* extDefStack. We only push a def if it is unmarked, ie, its
|
|
|
|
|
* cd_client field is 0. After pushing a def, we mark it by
|
|
|
|
|
* setting its cd_client field to 1.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
extDefParentFunc(def)
|
|
|
|
|
CellDef *def;
|
|
|
|
|
{
|
|
|
|
|
CellUse *parent;
|
|
|
|
|
|
|
|
|
|
if (def->cd_client || (def->cd_flags&CDINTERNAL))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
def->cd_client = (ClientData) 1;
|
|
|
|
|
StackPush((ClientData) def, extDefStack);
|
|
|
|
|
for (parent = def->cd_parents; parent; parent = parent->cu_nextuse)
|
|
|
|
|
if (parent->cu_parent)
|
|
|
|
|
extDefParentFunc(parent->cu_parent);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* ExtParentArea --
|
|
|
|
|
*
|
|
|
|
|
* ExtParentArea extracts the cell use->cu_def and each of its
|
|
|
|
|
* parents that contain geometry touching or overlapping the area
|
|
|
|
|
* of use->cu_def.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Creates one or more .ext files and writes to them.
|
|
|
|
|
* Adds feedback information where errors have occurred.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ExtParentArea(use, changedArea, doExtract)
|
|
|
|
|
CellUse *use; /* Use->cu_def changed; extract its affected parents */
|
|
|
|
|
Rect *changedArea; /* Area changed in use->cu_def coordinates */
|
|
|
|
|
bool doExtract; /* If TRUE, we extract; if FALSE, we just print names
|
|
|
|
|
* of the cells we would extract.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
Rect area;
|
|
|
|
|
|
|
|
|
|
/* Mark all defs as being unvisited */
|
|
|
|
|
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Recursively visit all defs in the tree
|
|
|
|
|
* and push on stack if they contain any geometry
|
|
|
|
|
* overlapping or touching the area 'changedArea'.
|
|
|
|
|
*/
|
|
|
|
|
area = *changedArea;
|
|
|
|
|
area.r_xbot--, area.r_ybot--;
|
|
|
|
|
area.r_xtop++, area.r_ytop++;
|
|
|
|
|
extDefStack = StackNew(100);
|
|
|
|
|
extDefParentAreaFunc(use->cu_def, use->cu_def, (CellUse *) NULL, &area);
|
|
|
|
|
|
|
|
|
|
/* Now extract all the cells we just found */
|
|
|
|
|
extExtractStack(extDefStack, doExtract, (CellDef *) NULL);
|
|
|
|
|
StackFree(extDefStack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Function to visit all the parents of 'def' and push them on
|
|
|
|
|
* extDefStack. We only push a def if it is unmarked, ie, its
|
|
|
|
|
* cd_client field is 0, and if it is either 'baseDef' or it
|
|
|
|
|
* contains geometry or other subcells in the area 'area'.
|
|
|
|
|
* We mark each def visited by setting cd_client to 1.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
extDefParentAreaFunc(def, baseDef, allButUse, area)
|
|
|
|
|
CellDef *def;
|
|
|
|
|
CellDef *baseDef;
|
|
|
|
|
CellUse *allButUse;
|
|
|
|
|
Rect *area;
|
|
|
|
|
{
|
|
|
|
|
int x, y, xoff, yoff;
|
|
|
|
|
CellUse *parent;
|
|
|
|
|
Transform t, t2;
|
|
|
|
|
Rect parArea;
|
|
|
|
|
|
|
|
|
|
if (def->cd_client || (def->cd_flags&CDINTERNAL))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (def == baseDef || extContainsGeometry(def, allButUse, area))
|
|
|
|
|
{
|
|
|
|
|
def->cd_client = (ClientData) 1;
|
|
|
|
|
StackPush((ClientData) def, extDefStack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (parent = def->cd_parents; parent; parent = parent->cu_nextuse)
|
|
|
|
|
{
|
|
|
|
|
if (parent->cu_parent)
|
|
|
|
|
{
|
|
|
|
|
for (x = parent->cu_xlo; x <= parent->cu_xhi; x++)
|
|
|
|
|
{
|
|
|
|
|
for (y = parent->cu_ylo; y <= parent->cu_yhi; y++)
|
|
|
|
|
{
|
|
|
|
|
xoff = (x - parent->cu_xlo) * parent->cu_xsep;
|
|
|
|
|
yoff = (y - parent->cu_ylo) * parent->cu_ysep;
|
|
|
|
|
GeoTranslateTrans(&GeoIdentityTransform, xoff, yoff, &t);
|
|
|
|
|
GeoTransTrans(&t, &parent->cu_transform, &t2);
|
|
|
|
|
GeoTransRect(&t2, area, &parArea);
|
|
|
|
|
extDefParentAreaFunc(parent->cu_parent, baseDef,
|
|
|
|
|
parent, &parArea);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
extContainsGeometry(def, allButUse, area)
|
|
|
|
|
CellDef *def;
|
|
|
|
|
CellUse *allButUse;
|
|
|
|
|
Rect *area;
|
|
|
|
|
{
|
|
|
|
|
int extContainsPaintFunc();
|
|
|
|
|
bool extContainsCellFunc();
|
|
|
|
|
int pNum;
|
|
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
if (DBSrCellPlaneArea(def->cd_cellPlane, area,
|
2017-04-25 14:41:48 +02:00
|
|
|
extContainsCellFunc, (ClientData) allButUse))
|
|
|
|
|
return (TRUE);
|
|
|
|
|
|
|
|
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
|
|
|
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
|
|
|
|
|
area, &DBAllButSpaceBits,
|
|
|
|
|
extContainsPaintFunc, (ClientData) NULL))
|
|
|
|
|
return (TRUE);
|
|
|
|
|
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2019-03-23 00:58:47 +01:00
|
|
|
extContainsCellFunc(use, allButUse)
|
|
|
|
|
CellUse *use;
|
2017-04-25 14:41:48 +02:00
|
|
|
CellUse *allButUse;
|
|
|
|
|
{
|
2019-03-23 00:58:47 +01:00
|
|
|
return (use != allButUse) ? TRUE : FALSE;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
extContainsPaintFunc()
|
|
|
|
|
{
|
|
|
|
|
return (1);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* ExtIncremental --
|
|
|
|
|
*
|
|
|
|
|
* Starting at 'rootUse', extract all cell defs that have changed.
|
|
|
|
|
* Right now, we forcibly read in the entire tree before doing the
|
|
|
|
|
* extraction.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Creates a number of .ext files and writes to them.
|
|
|
|
|
* Adds feedback information where errors have occurred.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ExtIncremental(rootUse)
|
|
|
|
|
CellUse *rootUse;
|
|
|
|
|
{
|
|
|
|
|
/* Make sure the entire subtree is read in */
|
2021-01-14 21:21:39 +01:00
|
|
|
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
|
|
|
|
|
{
|
|
|
|
|
TxError("Failure to read entire subtree of cell.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* Fix up bounding boxes if they've changed */
|
|
|
|
|
DBFixMismatch();
|
|
|
|
|
|
|
|
|
|
/* Update all timestamps */
|
|
|
|
|
DBUpdateStamps();
|
|
|
|
|
|
|
|
|
|
/* Mark all defs as being unvisited */
|
|
|
|
|
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Recursively visit all defs in the tree
|
|
|
|
|
* and push on stack if they need extraction.
|
|
|
|
|
*/
|
|
|
|
|
extDefStack = StackNew(100);
|
|
|
|
|
(void) extDefIncrementalFunc(rootUse);
|
|
|
|
|
|
|
|
|
|
/* Now extract all the cells we just found */
|
|
|
|
|
extExtractStack(extDefStack, TRUE, rootUse->cu_def);
|
|
|
|
|
StackFree(extDefStack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Function to push each cell def on extDefStack if it hasn't
|
|
|
|
|
* already been pushed and if it needs re-extraction, and then
|
|
|
|
|
* recurse on all that def's children.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
extDefIncrementalFunc(use)
|
|
|
|
|
CellUse *use;
|
|
|
|
|
{
|
|
|
|
|
CellDef *def = use->cu_def;
|
|
|
|
|
|
|
|
|
|
if (def->cd_client || (def->cd_flags&CDINTERNAL))
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
def->cd_client = (ClientData) 1;
|
|
|
|
|
if (extTimestampMisMatch(def))
|
|
|
|
|
StackPush((ClientData) def, extDefStack);
|
|
|
|
|
(void) DBCellEnum(def, extDefIncrementalFunc, (ClientData) 0);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Function returning TRUE if 'def' needs re-extraction.
|
|
|
|
|
* This will be the case if either the .ext file for 'def'
|
|
|
|
|
* does not exist, or if its timestamp fails to match that
|
|
|
|
|
* recorded in 'def'.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
extTimestampMisMatch(def)
|
|
|
|
|
CellDef *def;
|
|
|
|
|
{
|
|
|
|
|
char line[256];
|
|
|
|
|
FILE *extFile;
|
|
|
|
|
bool ret = TRUE;
|
|
|
|
|
int stamp;
|
2020-03-24 18:55:44 +01:00
|
|
|
bool doLocal;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2020-03-24 18:55:44 +01:00
|
|
|
doLocal = (ExtOptions & EXT_DOLOCAL) ? TRUE : FALSE;
|
|
|
|
|
|
|
|
|
|
extFile = extFileOpen(def, (char *) NULL, "r", doLocal, (char **) NULL);
|
2017-04-25 14:41:48 +02:00
|
|
|
if (extFile == NULL)
|
|
|
|
|
return (TRUE);
|
|
|
|
|
|
|
|
|
|
if (fgets(line, sizeof line, extFile) == NULL) goto closeit;
|
|
|
|
|
if (sscanf(line, "timestamp %d", &stamp) != 1) goto closeit;
|
|
|
|
|
if (def->cd_timestamp != stamp) goto closeit;
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
|
|
|
|
|
closeit:
|
|
|
|
|
(void) fclose(extFile);
|
|
|
|
|
return (ret);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2021-04-05 22:03:54 +02:00
|
|
|
/* Linked list structure to use to store the substrate plane from each */
|
|
|
|
|
/* extracted CellDef so that they can be returned to the original after */
|
|
|
|
|
/* extraction. */
|
|
|
|
|
|
|
|
|
|
struct saveList {
|
|
|
|
|
Plane *sl_plane;
|
|
|
|
|
CellDef *sl_def;
|
|
|
|
|
struct saveList *sl_next;
|
|
|
|
|
};
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* extExtractStack --
|
|
|
|
|
*
|
|
|
|
|
* If 'doExtract' is TRUE, call ExtCell for each def on the stack 'stack';
|
|
|
|
|
* otherwise, print the name of each def on the stack 'stack'.
|
|
|
|
|
* The root cell of the tree being processed is 'rootDef'; we only
|
|
|
|
|
* extract pathlength information for this cell.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Leaves 'stack' empty.
|
|
|
|
|
* Calls ExtCell on each def on the stack if 'doExtract' is TRUE.
|
|
|
|
|
* Resets cd_client to 0 for each def on the stack.
|
|
|
|
|
* Prints the total number of errors and warnings.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
extExtractStack(stack, doExtract, rootDef)
|
|
|
|
|
Stack *stack;
|
|
|
|
|
CellDef *rootDef;
|
|
|
|
|
{
|
|
|
|
|
int fatal = 0, warnings = 0;
|
|
|
|
|
bool first = TRUE;
|
2021-04-05 22:03:54 +02:00
|
|
|
Plane *savePlane;
|
2017-04-25 14:41:48 +02:00
|
|
|
CellDef *def;
|
2021-04-05 22:03:54 +02:00
|
|
|
struct saveList *newsl, *sl = (struct saveList *)NULL;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
while (def = (CellDef *) StackPop(stack))
|
|
|
|
|
{
|
|
|
|
|
def->cd_client = (ClientData) 0;
|
|
|
|
|
if (!SigInterruptPending)
|
|
|
|
|
{
|
|
|
|
|
if (doExtract)
|
|
|
|
|
{
|
2021-04-05 22:03:54 +02:00
|
|
|
savePlane = ExtCell(def, (char *) NULL, (def == rootDef));
|
|
|
|
|
if (savePlane != NULL)
|
|
|
|
|
{
|
|
|
|
|
newsl = (struct saveList *)mallocMagic(sizeof(struct saveList));
|
|
|
|
|
newsl->sl_plane = savePlane;
|
|
|
|
|
newsl->sl_def = def;
|
|
|
|
|
newsl->sl_next = sl;
|
|
|
|
|
sl = newsl;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
fatal += extNumFatal;
|
|
|
|
|
warnings += extNumWarnings;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!first) TxPrintf(", ");
|
|
|
|
|
TxPrintf("%s", def->cd_name);
|
|
|
|
|
TxFlush();
|
|
|
|
|
first = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-05 22:03:54 +02:00
|
|
|
/* Replace any modified substrate planes */
|
|
|
|
|
for (; sl; sl = sl->sl_next)
|
|
|
|
|
{
|
2021-04-06 16:15:15 +02:00
|
|
|
ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
|
|
|
|
|
// DBFreePaintPlane(sl->sl_plane);
|
|
|
|
|
// TiFreePlane(sl->sl_plane);
|
2021-04-06 16:13:36 +02:00
|
|
|
|
2021-04-05 22:03:54 +02:00
|
|
|
freeMagic(sl);
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (!doExtract)
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("\n");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (fatal > 0)
|
2020-11-24 21:30:49 +01:00
|
|
|
TxError("Total of %d error%s (check feedback entries).\n",
|
2017-04-25 14:41:48 +02:00
|
|
|
fatal, fatal != 1 ? "s" : "");
|
|
|
|
|
if (warnings > 0)
|
|
|
|
|
TxError("Total of %d warning%s.\n",
|
|
|
|
|
warnings, warnings != 1 ? "s" : "");
|
|
|
|
|
}
|
|
|
|
|
}
|