Files
magic/extract/ExtMain.c
T
Tim Edwards 02f42e7260 Corrections to the extresist code. Some of the changes are just
text formatting.  Made one critical correction to ResGetDevice() to
pass the device type;  otherwise, devices on different planes (e.g.,
MiM caps) with the same coordinate will always return the device on
the lowest plane, leading to incorrect results and an eventual crash
when the device record is free'd twice.
2021-09-12 17:20:22 -04:00

725 lines
19 KiB
C

/*
* ExtMain.c --
*
* Circuit extraction.
* Command interface.
*
* *********************************************************************
* * 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/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
* feedback messages. If this word is zero, only errors are
* 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();
/*
* ----------------------------------------------------------------------------
*
* 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();
}
/*
* ----------------------------------------------------------------------------
*
* 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 */
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
{
TxError("Failure to read entire subtree of cell.\n");
return;
}
/* 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);
}
/*
* ----------------------------------------------------------------------------
*
* 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. If "option"
* is 3 ("notopports" mode), then port labels on the top level 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;
int locoption;
/* Make sure the entire subtree is read in */
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
{
TxError("Failure to read entire subtree of cell.\n");
return;
}
/* 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))
{
/* EXT_UNIQ_NOTOPPORTS: Use EXT_UNIQ_ALL on all cells other than the top */
if ((option == EXT_UNIQ_NOTOPPORTS) &&
(StackLook(extDefStack) != (ClientData)NULL))
locoption = EXT_UNIQ_ALL;
else
locoption = option;
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);
}
/*
* ----------------------------------------------------------------------------
*
* 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);
}
/*
* ----------------------------------------------------------------------------
*
* 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;
if (DBSrCellPlaneArea(def->cd_cellPlane, area,
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
extContainsCellFunc(use, allButUse)
CellUse *use;
CellUse *allButUse;
{
return (use != allButUse) ? TRUE : FALSE;
}
int
extContainsPaintFunc()
{
return (1);
}
/*
* ----------------------------------------------------------------------------
*
* 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 */
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
{
TxError("Failure to read entire subtree of cell.\n");
return;
}
/* 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;
bool doLocal;
doLocal = (ExtOptions & EXT_DOLOCAL) ? TRUE : FALSE;
extFile = extFileOpen(def, (char *) NULL, "r", doLocal, (char **) NULL);
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);
}
/* 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;
};
/*
* ----------------------------------------------------------------------------
*
* 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;
Plane *savePlane;
CellDef *def;
struct saveList *newsl, *sl = (struct saveList *)NULL;
while (def = (CellDef *) StackPop(stack))
{
def->cd_client = (ClientData) 0;
if (!SigInterruptPending)
{
if (doExtract)
{
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;
}
fatal += extNumFatal;
warnings += extNumWarnings;
}
else
{
if (!first) TxPrintf(", ");
TxPrintf("%s", def->cd_name);
TxFlush();
first = FALSE;
}
}
}
/* Replace any modified substrate planes */
for (; sl; sl = sl->sl_next)
{
ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
// DBFreePaintPlane(sl->sl_plane);
// TiFreePlane(sl->sl_plane);
freeMagic(sl);
}
if (!doExtract)
{
TxPrintf("\n");
}
else
{
if (fatal > 0)
TxError("Total of %d error%s (check feedback entries).\n",
fatal, fatal != 1 ? "s" : "");
if (warnings > 0)
TxError("Total of %d warning%s.\n",
warnings, warnings != 1 ? "s" : "");
}
}