magic/extract/ExtHier.c

1056 lines
31 KiB
C
Raw Normal View History

/*
* ExtHier.c --
*
* Circuit extraction.
* Lower-level procedures common both to ordinary subtree extraction,
* and to array extraction.
* The procedures in this file are not re-entrant.
*
* *********************************************************************
* * 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/ExtHier.c,v 1.3 2010/06/24 12:37:17 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/geofast.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "utils/malloc.h"
#include "textio/textio.h"
#include "utils/styles.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "debug/debug.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
/* Local data */
/* Passed to search functions by extHierConnections */
ExtTree *extHierCumFlat; /* Cum buffer */
ExtTree *extHierOneFlat; /* Subtree being compared with extHierCumFlat */
/* List of free cells around for use in yanking subtrees */
ExtTree *extHierFreeOneList = (ExtTree *) NULL;
/* Appended to the name of each new CellDef created by extHierNewOne() */
int extHierOneNameSuffix = 0;
/* Forward declarations */
int extHierConnectFunc1();
int extHierConnectFunc2();
int extHierConnectFunc3();
Node *extHierNewNode();
/*----------------------------------------------------------------------*/
/* extHierSubShieldFunc -- */
/* */
/* Simple callback function for extHierSubstrate() that halts the */
/* search if any substrate shield type is found in the search area */
/* */
/*----------------------------------------------------------------------*/
int
extHierSubShieldFunc(tile)
Tile *tile;
{
return 1;
}
/*----------------------------------------------------------------------*/
/* extHierSubstrate -- */
/* */
/* Find the substrate node of a child cell and make a connection */
/* between parent and child substrates. If either of the */
/* substrate nodes is already in the hash table, then the table */
/* will be updated as necessary. */
/* */
/* This function also determines if a child cell's substrate is */
/* isolated by a substrate shield type, in which case no merge is */
/* done. */
/* */
/*----------------------------------------------------------------------*/
void
extHierSubstrate(ha, use, x, y)
HierExtractArg *ha; // Contains parent def and hash table
CellUse *use; // Child use
int x, y; // Array subscripts, or -1 if not an array
{
NodeRegion *nodeList;
HashTable *table = &ha->ha_connHash;
HashEntry *he;
NodeName *nn;
Node *node1, *node2;
char *name1, *name2, *childname;
CellDef *def;
Rect subArea;
int pNum;
NodeRegion *extFindNodes();
/* Backwards compatibility with tech files that don't */
/* define a substrate plane or substrate connections. */
if (glob_subsnode == NULL) return;
/* If the substrate has already been extracted for this use */
/* then there is no need to do it again. */
if (use->cu_flags & CU_SUB_EXTRACTED) return;
/* Don't extract anything from cells marked "don't use". */
if (use->cu_def->cd_flags & CDDONTUSE) return;
def = (CellDef *)ha->ha_parentUse->cu_def;
/* Register the name of the parent's substrate */
/* The parent def's substrate node is in glob_subsnode */
name1 = extNodeName(glob_subsnode);
he = HashFind(table, name1);
nn = (NodeName *) HashGetValue(he);
node1 = nn ? nn->nn_node : extHierNewNode(he);
/* Find the child's substrate node */
nodeList = extFindNodes(use->cu_def, (Rect *) NULL, TRUE);
if (nodeList == NULL)
{
ExtResetTiles(use->cu_def, extUnInit);
return;
}
/* Check if the child's substrate node is covered by any substrate */
/* shield type (e.g., deep nwell). This is a stupid-simple check */
/* on the node's lower left point. This will fail if (1) only */
/* space exists on the substrate plane in the child cell, or (2) if */
/* some but not all devices in the child are covered by a shield */
/* type. Item (1) is handled by checking if the region point is */
/* outside the cell bound and using the cell bound as the search */
/* area if so. However, it really should look for a device in the */
/* subcell that connects to the substrate. Item (2) is up to the */
/* designer to avoid (but should be flagged as an extraction */
/* error). */
if (GEO_ENCLOSE(&nodeList->nreg_ll, &use->cu_def->cd_bbox))
{
GeoTransPoint(&use->cu_transform, &nodeList->nreg_ll, &subArea.r_ll);
subArea.r_ur.p_x = subArea.r_ll.p_x + 1;
subArea.r_ur.p_y = subArea.r_ll.p_y + 1;
}
else
{
/* Check area under all of the subcircuit (not just the part */
/* in the current interaction area). */
GeoTransRect(&use->cu_transform, &use->cu_def->cd_bbox, &subArea);
}
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
if (TTMaskIntersect(&DBPlaneTypes[pNum],
&ExtCurStyle->exts_globSubstrateShieldTypes))
{
if (DBSrPaintArea((Tile *) NULL,
def->cd_planes[pNum], &subArea,
&ExtCurStyle->exts_globSubstrateShieldTypes,
extHierSubShieldFunc, (ClientData)NULL) != 0)
{
freeMagic(nodeList);
ExtResetTiles(use->cu_def, extUnInit);
return;
}
}
}
/* Make sure substrate labels are represented */
ExtLabelRegions(use->cu_def, ExtCurStyle->exts_nodeConn, &nodeList,
&TiPlaneRect);
ExtResetTiles(use->cu_def, extUnInit);
name2 = extNodeName(temp_subsnode);
if (x >= 0 && y >= 0)
{
/* Process array information */
childname = mallocMagic(strlen(name2) + strlen(use->cu_id) + 14);
sprintf(childname, "%s[%d,%d]/%s", use->cu_id, y, x, name2);
}
else if (x >= 0 || y >= 0)
{
childname = mallocMagic(strlen(name2) + strlen(use->cu_id) + 9);
sprintf(childname, "%s[%d]/%s", use->cu_id, ((x >= 0) ? x : y),
name2);
}
else
{
childname = mallocMagic(strlen(name2) + strlen(use->cu_id) + 2);
sprintf(childname, "%s/%s", use->cu_id, name2);
}
he = HashFind(table, childname);
nn = (NodeName *) HashGetValue(he);
node2 = nn ? nn->nn_node : extHierNewNode(he);
freeMagic(childname);
if (node1 != node2)
{
if (node1->node_len < node2->node_len)
{
/*
* Both sets of names will now point to node2.
*/
for (nn = node1->node_names; nn->nn_next; nn = nn->nn_next)
nn->nn_node = node2;
nn->nn_node = node2;
nn->nn_next = node2->node_names->nn_next;
node2->node_names->nn_next = node1->node_names;
node2->node_len += node1->node_len;
freeMagic((char *)node1);
}
else
{
/*
* Both sets of names will now point to node1.
*/
for (nn = node2->node_names; nn->nn_next; nn = nn->nn_next)
nn->nn_node = node1;
nn->nn_node = node1;
nn->nn_next = node1->node_names;
node1->node_names = node2->node_names;
node1->node_len += node2->node_len;
freeMagic((char *)node2);
}
}
freeMagic(nodeList);
}
/*
* ----------------------------------------------------------------------------
*
* extHierConnections --
*
* Process connections between the two ExtTrees 'oneFlat' and 'cumFlat'.
* This consists of detecting overlaps or abutments between connecting
* tiles (maybe on different planes), and recording the connection in the hash
* table ha->ha_connHash.
*
* Results:
* None.
*
* Side effects:
* Adds connections to ha->ha_connHash.
* Doesn't change resistance or capacitance of the connected
* nodes; that is the job of extHierAdjustments().
*
* ----------------------------------------------------------------------------
*/
void
extHierConnections(ha, cumFlat, oneFlat)
HierExtractArg *ha;
ExtTree *cumFlat, *oneFlat;
{
int pNum;
CellDef *sourceDef = oneFlat->et_use->cu_def;
Label *lab;
extHierCumFlat = cumFlat;
extHierOneFlat = oneFlat;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
ha->hierPNum = pNum;
(void) DBSrPaintArea((Tile *) NULL,
sourceDef->cd_planes[pNum], &ha->ha_subArea,
&DBAllButSpaceBits, extHierConnectFunc1, (ClientData) ha);
}
/* Look for sticky labels in the child cell that are not */
/* connected to any geometry. */
if (!(ExtOptions & EXT_DOLABELCHECK)) return;
for (lab = sourceDef->cd_labels; lab; lab = lab->lab_next)
{
CellDef *cumDef = cumFlat->et_use->cu_def;
Rect r = lab->lab_rect;
TileTypeBitMask *connected = &DBConnectTbl[lab->lab_type];
int i = DBPlane(lab->lab_type);
ha->hierOneTile = (Tile *)lab; /* Blatant hack recasting */
ha->hierType = lab->lab_type;
ha->hierPNumBelow = i;
GEOCLIP(&r, &ha->ha_subArea);
if (lab->lab_flags & LABEL_STICKY)
DBSrPaintArea((Tile *) NULL,
cumFlat->et_use->cu_def->cd_planes[i], &r,
connected, extHierConnectFunc3, (ClientData) ha);
}
}
/*
* extHierConnectFunc1 --
*
* Called for each tile 'oneTile' in the ExtTree 'oneFlat' above
* that lies in the area ha->ha_subArea.
*
* Results:
* Returns 0 always.
*
* Side effects:
* None here, but see extHierConnectFunc2().
*/
int
extHierConnectFunc1(oneTile, ha)
Tile *oneTile; /* Comes from 'oneFlat' in extHierConnections */
HierExtractArg *ha; /* Extraction context */
{
CellDef *cumDef = extHierCumFlat->et_use->cu_def;
Rect r;
TileTypeBitMask mask, *connected;
TileType rtype;
Label *lab, *newlab;
int i;
unsigned n;
/*
* Find all tiles that connect to 'srcTile', but in the
* yank buffer cumDef. Adjust connectivity for each tile found.
* Widen the rectangle to detect connectivity by abutment.
*/
ha->hierOneTile = oneTile;
ha->hierType = TiGetTypeExact(oneTile);
if (IsSplit(oneTile))
{
rtype = ha->hierType;
ha->hierType = (rtype & TT_SIDE) ? SplitRightType(oneTile) :
SplitLeftType(oneTile);
}
connected = &(ExtCurStyle->exts_nodeConn[ha->hierType]);
TITORECT(oneTile, &r);
GEOCLIP(&r, &ha->ha_subArea);
r.r_xbot--, r.r_ybot--, r.r_xtop++, r.r_ytop++;
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
{
ha->hierPNumBelow = i;
TTMaskAndMask3(&mask, connected, &DBPlaneTypes[i]);
if (!TTMaskIsZero(&mask))
{
if (IsSplit(oneTile))
DBSrPaintNMArea((Tile *) NULL, cumDef->cd_planes[i],
rtype, &r,
((i == ha->hierPNum) ? &ExtCurStyle->exts_activeTypes
: connected), extHierConnectFunc2, (ClientData) ha);
else
DBSrPaintArea((Tile *) NULL, cumDef->cd_planes[i], &r,
((i == ha->hierPNum) ? &ExtCurStyle->exts_activeTypes
: connected), extHierConnectFunc2, (ClientData) ha);
}
}
/* Where labels have been saved from the parent cell, look for any */
/* that are inside the cell boundary and would connect to the tile. */
/* This allows the extractor to catch "sticky" labels that are not */
/* attached to a physical layer in the parent cell. */
if (!(ExtOptions & EXT_DOLABELCHECK)) return 0;
// NOTE by Tim, 9/10/2014: This generates phantom nodes when the
// labels are created by the "hard" node search; I think this code
// should be restricted to sticky labels only. But not certain.
// Definitely this causes problems in arrays, because the array node
// name may refer to a range of array elements, and the generated
// node only describes a single point.
for (lab = cumDef->cd_labels; lab; lab = lab->lab_next)
{
// All sticky labels are at the front of the list in cumDef, so
// stop when we see the first non-sticky label.
if (!(lab->lab_flags & LABEL_STICKY)) break;
if (GEO_TOUCH(&r, &lab->lab_rect))
if (TTMaskHasType(connected, lab->lab_type))
{
HashTable *table = &ha->ha_connHash;
HashEntry *he;
NodeName *nn;
Node *node1, *node2;
char *name;
/* Register the name, like is done in extHierConnectFunc2 */
he = HashFind(table, lab->lab_text);
nn = (NodeName *) HashGetValue(he);
node1 = nn ? nn->nn_node : extHierNewNode(he);
name = (*ha->ha_nodename)(ha->hierOneTile, ha->hierPNum,
extHierOneFlat, ha, TRUE);
he = HashFind(table, name);
nn = (NodeName *) HashGetValue(he);
node2 = nn ? nn->nn_node : extHierNewNode(he);
if (node1 != node2)
{
if (node1->node_len < node2->node_len)
{
/*
* Both sets of names will now point to node2.
* We don't need to update node_cap since it
* hasn't been computed yet.
*/
for (nn = node1->node_names; nn->nn_next; nn = nn->nn_next)
nn->nn_node = node2;
nn->nn_node = node2;
nn->nn_next = node2->node_names->nn_next;
node2->node_names->nn_next = node1->node_names;
node2->node_len += node1->node_len;
freeMagic((char *) node1);
}
else
{
/*
* Both sets of names will now point to node1.
* We don't need to update node_cap since it
* hasn't been computed yet.
*/
for (nn = node2->node_names; nn->nn_next; nn = nn->nn_next)
nn->nn_node = node1;
nn->nn_node = node1;
nn->nn_next = node1->node_names;
node1->node_names = node2->node_names;
node1->node_len += node2->node_len;
freeMagic((char *) node2);
}
}
}
}
return (0);
}
/*
* extHierConnectFunc2 --
*
* Called once for each tile 'cum' in extHierCumFlat->et_use->cu_def
* on the same plane as ha->hierOneTile that also overlaps or abuts
* the intersection of ha->hierOneTile with ha->ha_subArea, and for tiles
* in other planes that may connect.
*
* Results:
* Returns 0 always.
*
* Side effects:
* Makes a connection between the nodes of the two tiles
* if the types of ha->hierOneTile and 'cum' connect.
* Otherwise, if the tiles actually overlap (as opposed
* to merely abut), mark it with feedback as an error.
*/
int
extHierConnectFunc2(cum, ha)
Tile *cum; /* Comes from extHierCumFlat->et_use->cu_def */
HierExtractArg *ha; /* Extraction context */
{
HashTable *table = &ha->ha_connHash;
Node *node1, *node2;
TileType ttype;
HashEntry *he;
NodeName *nn;
char *name;
Rect r;
/* Compute the overlap area */
r.r_xbot = MAX(LEFT(ha->hierOneTile), LEFT(cum));
r.r_xtop = MIN(RIGHT(ha->hierOneTile), RIGHT(cum));
r.r_ybot = MAX(BOTTOM(ha->hierOneTile), BOTTOM(cum));
r.r_ytop = MIN(TOP(ha->hierOneTile), TOP(cum));
/* If the tiles don't even touch, they don't connect */
if (r.r_xtop < r.r_xbot || r.r_ytop < r.r_ybot
|| (r.r_xtop == r.r_xbot && r.r_ytop == r.r_ybot))
return (0);
/*
* Only make a connection if the types of 'ha->hierOneTile' and 'cum'
* connect. If they overlap and don't connect, it is an error.
* If they do connect, mark their nodes as connected.
*/
ttype = TiGetTypeExact(cum);
if (IsSplit(cum))
ttype = (ttype & TT_SIDE) ? SplitRightType(cum) : SplitLeftType(cum);
if (extConnectsTo(ha->hierType, ttype, ExtCurStyle->exts_nodeConn))
{
name = (*ha->ha_nodename)(cum, ha->hierPNumBelow, extHierCumFlat, ha, TRUE);
he = HashFind(table, name);
nn = (NodeName *) HashGetValue(he);
node1 = nn ? nn->nn_node : extHierNewNode(he);
name = (*ha->ha_nodename)(ha->hierOneTile, ha->hierPNum, extHierOneFlat,
ha, TRUE);
he = HashFind(table, name);
nn = (NodeName *) HashGetValue(he);
node2 = nn ? nn->nn_node : extHierNewNode(he);
if (node1 != node2)
{
if (node1->node_len < node2->node_len)
{
/*
* Both sets of names will now point to node2.
* We don't need to update node_cap since it
* hasn't been computed yet.
*/
for (nn = node1->node_names; nn->nn_next; nn = nn->nn_next)
nn->nn_node = node2;
nn->nn_node = node2;
nn->nn_next = node2->node_names->nn_next;
node2->node_names->nn_next = node1->node_names;
node2->node_len += node1->node_len;
freeMagic((char *) node1);
}
else
{
/*
* Both sets of names will now point to node1.
* We don't need to update node_cap since it
* hasn't been computed yet.
*/
for (nn = node2->node_names; nn->nn_next; nn = nn->nn_next)
nn->nn_node = node1;
nn->nn_node = node1;
nn->nn_next = node1->node_names;
node1->node_names = node2->node_names;
node1->node_len += node2->node_len;
freeMagic((char *) node2);
}
}
}
else if (r.r_xtop > r.r_xbot && r.r_ytop > r.r_ybot)
{
char message[1024];
snprintf(message, sizeof(message),
"Illegal overlap between %s and %s (types do not connect)",
DBTypeLongNameTbl[ha->hierType], DBTypeLongNameTbl[ttype]);
extNumErrors++;
if (!DebugIsSet(extDebugID, extDebNoFeedback))
DBWFeedbackAdd(&r, message,
ha->ha_parentUse->cu_def, 1, STYLE_MEDIUMHIGHLIGHTS);
}
return (0);
}
/*
* extHierConnectFunc3 --
*
* Called once for each tile 'cum' in extHierCumFlat->et_use->cu_def
* Similar to extHierConnectFunc2, but is called for a label in the
* parent cell that does not necessarily have associated geometry.
* Value passed in ha_oneTile is the label (recast for convenience;
* need to use a union type in HierExtractArg).
*/
int
extHierConnectFunc3(cum, ha)
Tile *cum; /* Comes from extHierCumFlat->et_use->cu_def */
HierExtractArg *ha; /* Extraction context */
{
HashTable *table = &ha->ha_connHash;
Node *node1, *node2;
TileType ttype;
HashEntry *he;
NodeName *nn;
char *name;
Rect r;
Label *lab = (Label *)(ha->hierOneTile); /* Lazy recasting */
/* Compute the overlap area */
r.r_xbot = MAX(lab->lab_rect.r_xbot, LEFT(cum));
r.r_xtop = MIN(lab->lab_rect.r_xtop, RIGHT(cum));
r.r_ybot = MAX(lab->lab_rect.r_ybot, BOTTOM(cum));
r.r_ytop = MIN(lab->lab_rect.r_ytop, TOP(cum));
/* If the tiles don't even touch, they don't connect */
if (r.r_xtop < r.r_xbot || r.r_ytop < r.r_ybot)
return (0);
/*
* Only make a connection if the types of 'ha->hierOneTile' and 'cum'
* connect. If they overlap and don't connect, it is an error.
* If they do connect, mark their nodes as connected.
*/
ttype = TiGetTypeExact(cum);
if (IsSplit(cum))
ttype = (ttype & TT_SIDE) ? SplitRightType(cum) : SplitLeftType(cum);
if (extConnectsTo(ha->hierType, ttype, ExtCurStyle->exts_nodeConn))
{
name = (*ha->ha_nodename)(cum, ha->hierPNumBelow, extHierCumFlat, ha, TRUE);
he = HashFind(table, name);
nn = (NodeName *) HashGetValue(he);
node1 = nn ? nn->nn_node : extHierNewNode(he);
name = lab->lab_text;
he = HashFind(table, name);
nn = (NodeName *) HashGetValue(he);
node2 = nn ? nn->nn_node : extHierNewNode(he);
if (node1 != node2)
{
if (node1->node_len < node2->node_len)
{
/*
* Both sets of names will now point to node2.
* We don't need to update node_cap since it
* hasn't been computed yet.
*/
for (nn = node1->node_names; nn->nn_next; nn = nn->nn_next)
nn->nn_node = node2;
nn->nn_node = node2;
nn->nn_next = node2->node_names->nn_next;
node2->node_names->nn_next = node1->node_names;
node2->node_len += node1->node_len;
freeMagic((char *) node1);
}
else
{
/*
* Both sets of names will now point to node1.
* We don't need to update node_cap since it
* hasn't been computed yet.
*/
for (nn = node2->node_names; nn->nn_next; nn = nn->nn_next)
nn->nn_node = node1;
nn->nn_node = node1;
nn->nn_next = node1->node_names;
node1->node_names = node2->node_names;
node1->node_len += node2->node_len;
freeMagic((char *) node2);
}
}
}
else if (r.r_xtop > r.r_xbot && r.r_ytop > r.r_ybot)
{
char message[1024];
snprintf(message, sizeof(message),
"Illegal overlap between %s and %s (types do not connect)",
DBTypeLongNameTbl[ha->hierType], DBTypeLongNameTbl[ttype]);
extNumErrors++;
if (!DebugIsSet(extDebugID, extDebNoFeedback))
DBWFeedbackAdd(&r, message,
ha->ha_parentUse->cu_def, 1, STYLE_MEDIUMHIGHLIGHTS);
}
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extHierAdjustments --
*
* Process adjustments to substrate capacitance, coupling capacitance,
* node perimeter, and node area between the subtree 'oneFlat' and the
* cumulative yank buffer 'cumFlat'. The subtree 'lookFlat' is used
* for looking up node names when handling capacitance/perimeter/area
* adjustment.
*
* Results:
* None.
*
* Side effects:
* Updates capacitance in the table cumFlat->et_coupleHash.
* Updates capacitance, perimeter, and area recorded in the
* nodes of 'cumFlat'.
*
* Algorithm:
* For each capacitor recorded in oneFlat->et_coupleHash, find
* the corresponding nodes in 'cumFlat' and subtract the
* capacitance from the entry indexed by these nodes in the
* table cumFlat->et_coupleHash.
*
* For each node in oneFlat->et_nodes, find the corresponding
* node in 'lookFlat'. Look for the Node with this name in
* the table ha->ha_connHash, and subtract the oneFlat node's
* capacitance, perimeter, and area from it. If no Node is
* found in this table, don't do anything since the oneFlat
* node must not participate in any connections.
*
* The node in 'cumFlat' corresponding to one in 'oneFlat'
* is the one containing some point in 'oneFlat', since 'oneFlat'
* is a strict subset of 'cumFlat'.
*
* ----------------------------------------------------------------------------
*/
void
extHierAdjustments(ha, cumFlat, oneFlat, lookFlat)
HierExtractArg *ha;
ExtTree *cumFlat, *oneFlat, *lookFlat;
{
HashEntry *he, *heCum;
int n;
CoupleKey *ckpOne, ckCum;
NodeRegion *np;
HashSearch hs;
NodeName *nn;
Tile *tp;
char *name;
/* Update all coupling capacitors */
if (ExtOptions & EXT_DOCOUPLING)
{
HashStartSearch(&hs);
while (he = HashNext(&oneFlat->et_coupleHash, &hs))
{
ckpOne = ((CoupleKey *) he->h_key.h_words);
/* Find nodes in cumFlat->et_coupleHash */
NODETONODE(ckpOne->ck_1, cumFlat, ckCum.ck_1);
NODETONODE(ckpOne->ck_2, cumFlat, ckCum.ck_2);
if (ckCum.ck_1 == NULL || ckCum.ck_2 == NULL) continue;
/* Skip if the same; reverse to make smaller node pointer first */
if (ckCum.ck_1 == ckCum.ck_2) continue;
if (ckCum.ck_2 < ckCum.ck_1)
np = ckCum.ck_1, ckCum.ck_1 = ckCum.ck_2, ckCum.ck_2 = np;
/* Update the capacitor record in cumFlat->et_coupleHash */
heCum = HashFind(&cumFlat->et_coupleHash, (char *) &ckCum);
extSetCapValue(heCum, extGetCapValue(heCum) - extGetCapValue(he));
}
}
/*
* Update all node values.
* Find the corresponding tile in the ExtTree lookFlat, then look
* for its name. If this name appear in the connection hash table,
* update the capacitance, perimeter, and area stored there; otherwise
* ignore it.
*
* The FALSE argument to (*ha->ha_nodename)() means that we don't bother
* looking for node names the hard way; if we didn't already have a valid
* node name then it couldn't appear in the table ha->ha_connHash in the
* first place.
*/
for (np = oneFlat->et_nodes; np; np = np->nreg_next)
{
/* Ignore orphaned nodes (non-Manhattan shards outside the clip box) */
if (np->nreg_pnum == DBNumPlanes) continue;
tp = extNodeToTile(np, lookFlat);
/* Ignore regions that do not participate in extraction */
if (!extHasRegion(tp, extUnInit)) continue;
/* Ignore substrate nodes (failsafe: should not happen) */
if (TiGetTypeExact(tp) == TT_SPACE) continue;
if (tp && (name = (*ha->ha_nodename)(tp, np->nreg_pnum, lookFlat, ha, FALSE))
&& (he = HashLookOnly(&ha->ha_connHash, name))
&& (nn = (NodeName *) HashGetValue(he)))
{
/* Adjust the capacitance and resistance on the node */
nn->nn_node->node_cap -= np->nreg_cap;
for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
{
nn->nn_node->node_pa[n].pa_perim -= np->nreg_pa[n].pa_perim;
nn->nn_node->node_pa[n].pa_area -= np->nreg_pa[n].pa_area;
}
}
}
}
/*
* ----------------------------------------------------------------------------
*
* extOutputConns --
*
* Dump the contents of the hash table 'table' of connectivity and
* node R, C adjustments to the output file outf.
*
* Results:
* None.
*
* Side effects:
* Outputs a number of "merge" records to the file 'outf'.
*
* ----------------------------------------------------------------------------
*/
void
extOutputConns(table, outf)
HashTable *table;
FILE *outf;
{
CapValue c; /* cap value */
NodeName *nn, *nnext;
Node *node;
int n;
NodeName *nfirst;
HashSearch hs;
HashEntry *he;
HashStartSearch(&hs);
while (he = HashNext(table, &hs))
{
nfirst = (NodeName *) HashGetValue(he);
/*
* If nfirst->nn_node == NULL, the name for this hash entry
* had been output previously as a member of the merge list
* for a node appearing earlier in the table. If so, we need
* only free the NodeName without any further processing.
*/
if (node = nfirst->nn_node)
{
/*
* If there are N names for this node, output N-1 merge lines.
* Only the first merge line will contain the C, perimeter,
* and area updates.
*/
/* Note 3/1/2017: Cap value no longer used */
c = (node->node_cap) / ExtCurStyle->exts_capScale;
nn = node->node_names;
if (nnext = nn->nn_next)
{
/* First merge */
fprintf(outf, "merge \"%s\" \"%s\" %lg",
nn->nn_name, nnext->nn_name, c);
for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
fprintf(outf, " %d %d",
node->node_pa[n].pa_area,
node->node_pa[n].pa_perim);
fprintf(outf, "\n");
nn->nn_node = (Node *) NULL; /* Processed */
/* Subsequent merges */
for (nn = nnext; nnext = nn->nn_next; nn = nnext)
{
fprintf(outf, "merge \"%s\" \"%s\"\n",
nn->nn_name, nnext->nn_name);
nn->nn_node = (Node *) NULL; /* Processed */
}
}
nn->nn_node = (Node *) NULL;
freeMagic((char *) node);
}
freeMagic((char *) nfirst);
}
}
/*
* ----------------------------------------------------------------------------
*
* extHierNewNode --
*
* Create a new NodeName and Node to go with the HashEntry supplied.
* The NodeName will point to the new Node, which will point back to the
* NodeName.
*
* Results:
* Returns a pointer to the newly created Node.
*
* Side effects:
* Allocates memory.
* Sets (via HashSetValue) the value of HashEntry 'he' to the
* newly created NodeName.
*
* ----------------------------------------------------------------------------
*/
Node *
extHierNewNode(he)
HashEntry *he;
{
int n, nclasses;
NodeName *nn;
Node *node;
nclasses = ExtCurStyle->exts_numResistClasses;
n = (nclasses - 1) * sizeof (PerimArea) + sizeof (Node);
nn = (NodeName *) mallocMagic((unsigned) (sizeof (NodeName)));
node = (Node *) mallocMagic((unsigned) n);
nn->nn_node = node;
nn->nn_next = (NodeName *) NULL;
nn->nn_name = he->h_key.h_name;
node->node_names = nn;
node->node_cap = (CapValue) 0;
node->node_len = 1;
for (n = 0; n < nclasses; n++)
node->node_pa[n].pa_perim = node->node_pa[n].pa_area = 0;
HashSetValue(he, (char *) nn);
return (node);
}
/*
* ----------------------------------------------------------------------------
*
* extHierLabFirst --
* extHierLabEach --
*
* Filter functions passed to ExtFindRegions when tracing out labelled
* regions as part of a hierarchical circuit extraction.
*
* Results:
* extHierLabFirst returns a pointer to a new LabRegion.
* extHierLabEach returns 0 always.
*
* Side effects:
* Memory is allocated by extHierLabFirst(); it conses the newly
* allocated region onto the front of the existing region list.
* The node-naming info (reg_ll, reg_pnum) is updated by
* extHierLabEach().
*
* ----------------------------------------------------------------------------
*/
/*ARGSUSED*/
Region *
extHierLabFirst(tile, arg)
Tile *tile;
FindRegion *arg;
{
LabRegion *new;
new = (LabRegion *) mallocMagic((unsigned) (sizeof (LabRegion)));
new->lreg_next = (LabRegion *) NULL;
new->lreg_labels = (LabelList *) NULL;
new->lreg_pnum = DBNumPlanes;
/* Prepend it to the region list */
new->lreg_next = (LabRegion *) arg->fra_region;
arg->fra_region = (Region *) new;
return ((Region *) new);
}
/*ARGSUSED*/
int
extHierLabEach(tile, pNum, arg)
Tile *tile;
int pNum;
FindRegion *arg;
{
LabRegion *reg;
reg = (LabRegion *) arg->fra_region;
extSetNodeNum(reg, pNum, tile);
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extHierNewOne --
*
* Allocate a new ExtTree for use in hierarchical extraction.
* This ExtTree will be used to hold an entire flattened subtree.
* We try to return one from our free list if one exists; if none
* are left, we create a new CellDef and CellUse and allocate a
* new ExtTree. The new CellDef has a name of the form __EXTTREEn__,
* where 'n' is a small integer.
*
* The HashTable et_coupleHash will be initialized but empty.
* The node list et_nodes, the next pointer et_next, and the CellDef
* pointer et_lookNames will all be set to NULL.
*
* Results:
* Returns a pointer to a new ExtTree.
*
* Side effects:
* See above.
*
* ----------------------------------------------------------------------------
*/
ExtTree *
extHierNewOne()
{
char defname[128];
CellDef *dummy;
ExtTree *et;
if (extHierFreeOneList)
{
et = extHierFreeOneList;
extHierFreeOneList = et->et_next;
}
else
{
et = (ExtTree *) mallocMagic((unsigned)(sizeof (ExtTree)));
(void) sprintf(defname, "__EXTTREE%d__", extHierOneNameSuffix++);
DBNewYank(defname, &et->et_use, &dummy);
}
et->et_next = (ExtTree *) NULL;
et->et_lookNames = (CellDef *) NULL;
et->et_nodes = (NodeRegion *) NULL;
if (ExtOptions & EXT_DOCOUPLING)
HashInit(&et->et_coupleHash, 32, HashSize(sizeof (CoupleKey)));
return (et);
}
/*
* ----------------------------------------------------------------------------
*
* extHierFreeOne --
*
* Return an ExtTree allocated via extHierNewOne() above to the
* free list. Frees the HashTable et->et_coupleHash, any NodeRegions
* on the list et->et_nodes, any labels on the label list and any
* paint in the cell et->et_use->cu_def.
*
* Results:
* None.
*
* Side effects:
* See above.
* The caller should NOT use et->et_next after this procedure
* has returned.
*
* ----------------------------------------------------------------------------
*/
void
extHierFreeOne(et)
ExtTree *et;
{
if (ExtOptions & EXT_DOCOUPLING)
extCapHashKill(&et->et_coupleHash);
if (et->et_nodes) ExtFreeLabRegions((LabRegion *) et->et_nodes);
extHierFreeLabels(et->et_use->cu_def);
DBCellClearDef(et->et_use->cu_def);
et->et_next = extHierFreeOneList;
extHierFreeOneList = et;
}