2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
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/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();
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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. */
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2021-04-10 01:40:54 +02:00
|
|
|
* ----------------------------------------------------------------------------
|
2017-04-25 14:41:48 +02:00
|
|
|
* 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().
|
2021-04-10 01:40:54 +02:00
|
|
|
* ----------------------------------------------------------------------------
|
2017-04-25 14:41:48 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
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;
|
2021-04-10 01:40:54 +02:00
|
|
|
int extHierSubsFunc();
|
|
|
|
|
int extHierSubConnectFunc();
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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);
|
2020-05-23 23:13:14 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-10 01:40:54 +02:00
|
|
|
/* Where the type connects to substrate, and the substrate region */
|
|
|
|
|
/* under the tile is the default (global) substrate, then the tile */
|
|
|
|
|
/* will connect to anything in cumDef that is also connected to the */
|
|
|
|
|
/* default substrate. This is where a "substrate halo" could be */
|
|
|
|
|
/* applied to restrict the distance at which a substrate region is */
|
|
|
|
|
/* considered to be connected (but would have to ignore identifier */
|
|
|
|
|
/* types like "pwell" that are part of the substrate itself). */
|
|
|
|
|
|
|
|
|
|
if ((ExtSubsPlane != NULL) &&
|
|
|
|
|
TTMaskHasType(&ExtCurStyle->exts_globSubstrateTypes, ha->hierType))
|
|
|
|
|
{
|
|
|
|
|
Region *region, *saveRegion;
|
|
|
|
|
TileTypeBitMask subMaskNonSpace;
|
|
|
|
|
|
|
|
|
|
TTMaskZero(&subMaskNonSpace);
|
|
|
|
|
TTMaskSetMask(&subMaskNonSpace, &ExtCurStyle->exts_globSubstrateTypes);
|
|
|
|
|
TTMaskClearType(&subMaskNonSpace, TT_SPACE);
|
|
|
|
|
|
|
|
|
|
if (DBSrPaintArea((Tile *)NULL, ExtSubsPlane, &r, &subMaskNonSpace,
|
|
|
|
|
extHierSubsFunc, (ClientData)®ion) == 0)
|
|
|
|
|
region = ExtSubsRegionList[0];
|
|
|
|
|
|
|
|
|
|
/* This tile connects to a substrate region, so search */
|
|
|
|
|
/* cumDef for any tile also connected to the same region. */
|
|
|
|
|
|
|
|
|
|
saveRegion = ha->ha_parentReg;
|
|
|
|
|
ha->ha_parentReg = region;
|
|
|
|
|
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
|
|
|
|
|
{
|
|
|
|
|
ha->hierPNumBelow = i;
|
|
|
|
|
TTMaskAndMask3(&mask, connected, &DBPlaneTypes[i]);
|
|
|
|
|
if (!TTMaskIsZero(&mask))
|
|
|
|
|
DBSrPaintArea((Tile *) NULL, cumDef->cd_planes[i],
|
|
|
|
|
&TiPlaneRect, &subMaskNonSpace,
|
|
|
|
|
extHierSubConnectFunc, (ClientData)ha);
|
|
|
|
|
}
|
|
|
|
|
ha->ha_parentReg = saveRegion;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* 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. */
|
|
|
|
|
|
|
|
|
|
// 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)
|
2020-07-19 23:08:51 +02:00
|
|
|
{
|
2020-07-18 21:49:20 +02:00
|
|
|
// 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))
|
2017-04-25 14:41:48 +02:00
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* 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;
|
|
|
|
|
freeMagic((char *) node2);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-19 23:08:51 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2021-04-10 01:40:54 +02:00
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* extHierSubsFunc --
|
|
|
|
|
*
|
|
|
|
|
* Callback function to find a non-space tile in ExtSubsPlane. If found,
|
|
|
|
|
* get the region associated with the tile by lookup in the list
|
|
|
|
|
* ExtSubsRegionList.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Return 1 to stop the search.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Fills the Region * value pointed to by regionPtr
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
extHierSubsFunc(tile, regionPtr)
|
|
|
|
|
Tile *tile;
|
|
|
|
|
Region **regionPtr;
|
|
|
|
|
{
|
|
|
|
|
int regIdx = (int)tile->ti_client;
|
|
|
|
|
|
|
|
|
|
if (regIdx > ExtNumSubs) return 0; /* Invalid condition */
|
|
|
|
|
*regionPtr = ExtSubsRegionList[regIdx];
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
2017-04-25 14:41:48 +02:00
|
|
|
* 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.
|
2021-04-10 01:40:54 +02:00
|
|
|
* ----------------------------------------------------------------------------
|
2017-04-25 14:41:48 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
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;
|
2021-04-10 01:40:54 +02:00
|
|
|
char *name1, *name2;
|
2017-04-25 14:41:48 +02:00
|
|
|
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))
|
|
|
|
|
{
|
2021-04-10 01:40:54 +02:00
|
|
|
name1 = (*ha->ha_nodename)(cum, ha->hierPNumBelow, extHierCumFlat, ha, TRUE);
|
|
|
|
|
he = HashFind(table, name1);
|
2017-04-25 14:41:48 +02:00
|
|
|
nn = (NodeName *) HashGetValue(he);
|
|
|
|
|
node1 = nn ? nn->nn_node : extHierNewNode(he);
|
|
|
|
|
|
2021-04-10 01:40:54 +02:00
|
|
|
name2 = (*ha->ha_nodename)(ha->hierOneTile, ha->hierPNum, extHierOneFlat,
|
2017-04-25 14:41:48 +02:00
|
|
|
ha, TRUE);
|
2021-04-10 01:40:54 +02:00
|
|
|
he = HashFind(table, name2);
|
2017-04-25 14:41:48 +02:00
|
|
|
nn = (NodeName *) HashGetValue(he);
|
|
|
|
|
node2 = nn ? nn->nn_node : extHierNewNode(he);
|
|
|
|
|
|
|
|
|
|
if (node1 != node2)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* 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;
|
|
|
|
|
freeMagic((char *) node2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (r.r_xtop > r.r_xbot && r.r_ytop > r.r_ybot)
|
|
|
|
|
{
|
|
|
|
|
extNumFatal++;
|
|
|
|
|
if (!DebugIsSet(extDebugID, extDebNoFeedback))
|
|
|
|
|
DBWFeedbackAdd(&r, "Illegal overlap (types do not connect)",
|
|
|
|
|
ha->ha_parentUse->cu_def, 1, STYLE_MEDIUMHIGHLIGHTS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2021-04-10 01:40:54 +02:00
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
2017-04-25 14:41:48 +02:00
|
|
|
* 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).
|
2021-04-10 01:40:54 +02:00
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
2017-04-25 14:41:48 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
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;
|
2020-05-23 23:13:14 +02:00
|
|
|
Label *lab = (Label *)(ha->hierOneTile); /* Lazy recasting */
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* 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;
|
|
|
|
|
freeMagic((char *) node2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (r.r_xtop > r.r_xbot && r.r_ytop > r.r_ybot)
|
|
|
|
|
{
|
|
|
|
|
extNumFatal++;
|
|
|
|
|
if (!DebugIsSet(extDebugID, extDebNoFeedback))
|
|
|
|
|
DBWFeedbackAdd(&r, "Illegal overlap (types do not connect)",
|
|
|
|
|
ha->ha_parentUse->cu_def, 1, STYLE_MEDIUMHIGHLIGHTS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
2021-04-10 01:40:54 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* extHierSubConnectFunc --
|
|
|
|
|
*
|
|
|
|
|
* Called for all tiles 'cum' in extHierCumFlat->et_use->cu_def
|
|
|
|
|
* that connect to substrate types. Checks if the tile is marked
|
|
|
|
|
* with the substrate region that has been saved in the
|
|
|
|
|
* ha->ha_parentReg record. If so, then processes the connection.
|
|
|
|
|
* Only one such connection needs to be processed, so return 1 to
|
|
|
|
|
* stop the search.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns 1 always to stop the search, as only one tile
|
|
|
|
|
* with the substrate region needs to be processed.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* Makes a connection between the nodes of the two tiles
|
|
|
|
|
* if the types of ha->hierOneTile and 'cum' connect.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
extHierSubConnectFunc(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 *name1, *name2;
|
|
|
|
|
|
|
|
|
|
/* If Tile "cum" is not marked with the global substrate region, */
|
|
|
|
|
/* then ignore it (return 0 to keep the search going) */
|
|
|
|
|
|
|
|
|
|
if ((NodeRegion *)cum->ti_client != ha->ha_parentReg) return 0;
|
|
|
|
|
|
|
|
|
|
ttype = TiGetTypeExact(cum);
|
|
|
|
|
|
|
|
|
|
if (IsSplit(cum))
|
|
|
|
|
ttype = (ttype & TT_SIDE) ? SplitRightType(cum) : SplitLeftType(cum);
|
|
|
|
|
|
|
|
|
|
name1 = (*ha->ha_nodename)(cum, ha->hierPNumBelow, extHierCumFlat, ha, TRUE);
|
|
|
|
|
he = HashFind(table, name1);
|
|
|
|
|
nn = (NodeName *) HashGetValue(he);
|
|
|
|
|
node1 = nn ? nn->nn_node : extHierNewNode(he);
|
|
|
|
|
|
|
|
|
|
name2 = (*ha->ha_nodename)(ha->hierOneTile, ha->hierPNum, extHierOneFlat,
|
|
|
|
|
ha, TRUE);
|
|
|
|
|
he = HashFind(table, name2);
|
|
|
|
|
nn = (NodeName *) HashGetValue(he);
|
|
|
|
|
node2 = nn ? nn->nn_node : extHierNewNode(he);
|
|
|
|
|
|
|
|
|
|
if (node1 != node2)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* 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;
|
|
|
|
|
freeMagic((char *) node2);
|
|
|
|
|
}
|
|
|
|
|
return 1; /* No need to process any other tiles */
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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 */
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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;
|
|
|
|
|
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);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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;
|
2021-04-10 01:40:54 +02:00
|
|
|
new->lreg_type = 0;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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;
|
|
|
|
|
}
|