2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ExtRegion.c --
|
|
|
|
|
*
|
|
|
|
|
* Circuit extraction.
|
|
|
|
|
* This file contains the code to trace out connected Regions
|
|
|
|
|
* in a layout, and to build up or tear down lists of Regions.
|
|
|
|
|
*
|
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/ExtRegion.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.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"
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2026-01-09 17:58:35 +01:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* ExtGetRegion ---
|
|
|
|
|
*
|
|
|
|
|
* Get the region from the ClientData of a tile. Normally this is just the
|
|
|
|
|
* ClientData record recast as an ExtRegion pointer. However, if the tile
|
|
|
|
|
* is split and neither tile side is TT_SPACE, then the Tile will be given
|
|
|
|
|
* an ExtSplitRegion structure, and the returned region depends on the side
|
|
|
|
|
* specified by "dinfo" (bit TT_SIDE).
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns the tile's client data record cast to a region pointer.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Notes:
|
|
|
|
|
* This routine was previously implemented as an in-line definition
|
|
|
|
|
* "extGetRegion(Tile *tp)".
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
ExtRegion *
|
|
|
|
|
ExtGetRegion(Tile *tp, /* Tile to get region record from */
|
|
|
|
|
TileType dinfo) /* Split tile information, if relevant */
|
|
|
|
|
{
|
|
|
|
|
ExtSplitRegion *esr;
|
|
|
|
|
|
|
|
|
|
if (IsSplit(tp))
|
|
|
|
|
{
|
|
|
|
|
if ((TiGetLeftType(tp) == TT_SPACE) || (TiGetRightType(tp) == TT_SPACE))
|
|
|
|
|
return (ExtRegion *)tp->ti_client;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
esr = (ExtSplitRegion *)tp->ti_client;
|
2026-01-16 03:35:46 +01:00
|
|
|
|
|
|
|
|
/* If this tile has not been handled and no ExtSplitRegion has
|
|
|
|
|
* been created, then ti_client should be either CLIENTDEFAULT
|
|
|
|
|
* or VISITPENDING. It should not have any other values.
|
|
|
|
|
*/
|
|
|
|
|
if ((ClientData)esr == CLIENTDEFAULT)
|
|
|
|
|
return CD2PTR(CLIENTDEFAULT);
|
|
|
|
|
else if ((ClientData)esr == VISITPENDING)
|
|
|
|
|
return CD2PTR(VISITPENDING);
|
2026-01-09 17:58:35 +01:00
|
|
|
return (dinfo & TT_SIDE) ? esr->reg_right : esr->reg_left;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return (ExtRegion *)tp->ti_client;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* ExtFindRegions --
|
|
|
|
|
*
|
|
|
|
|
* Find all the connected geometrical regions in a given area of a CellDef
|
|
|
|
|
* that will correspond to nodes or devices in the extracted circuit.
|
|
|
|
|
* Two procedures are supplied by the caller, 'first' and 'each'.
|
|
|
|
|
*
|
|
|
|
|
* The function 'first' must be non-NULL. It is called for each tile
|
2023-02-24 03:27:08 +01:00
|
|
|
* tile found in the region. It must return a pointer to a ExtRegion
|
|
|
|
|
* struct (or one of the client forms of a ExtRegion struct; see the
|
2017-04-25 14:41:48 +02:00
|
|
|
* comments in extractInt.h).
|
|
|
|
|
*
|
2023-02-24 03:27:08 +01:00
|
|
|
* ExtRegion *
|
2017-04-25 14:41:48 +02:00
|
|
|
* (*first)(tile, arg)
|
|
|
|
|
* Tile *tile; /# Tile is on plane arg->fra_pNum #/
|
2026-01-03 02:12:37 +01:00
|
|
|
* TileType dinfo; /# Split tile information #/
|
2017-04-25 14:41:48 +02:00
|
|
|
* FindRegion *arg;
|
|
|
|
|
* {
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* If the function 'each' is non-NULL, it is applied once to each tile found
|
|
|
|
|
* in the region:
|
|
|
|
|
*
|
|
|
|
|
* (*each)(tile, planeNum, arg)
|
|
|
|
|
* Tile *tile;
|
2026-01-03 02:12:37 +01:00
|
|
|
* TileType dinfo; /# Split tile information #/
|
2017-04-25 14:41:48 +02:00
|
|
|
* int planeNum; /# May be different than arg->fra_pNum #/
|
|
|
|
|
* FindRegion *arg;
|
|
|
|
|
* {
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns a pointer to the first element in the linked list
|
2023-02-24 03:27:08 +01:00
|
|
|
* of ExtRegion structures for this CellDef. The ExtRegion structs
|
|
|
|
|
* may in fact contain more than the basic ExtRegion struct; this
|
2017-04-25 14:41:48 +02:00
|
|
|
* will depend on what the function 'first' allocates.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Each non-space tile has its ti_client field left pointing
|
2023-02-24 03:27:08 +01:00
|
|
|
* to a ExtRegion structure that describes the region that tile
|
2017-04-25 14:41:48 +02:00
|
|
|
* belongs to.
|
|
|
|
|
*
|
|
|
|
|
* Non-interruptible. It is the caller's responsibility to check
|
|
|
|
|
* for interrupts.
|
2020-05-23 23:13:14 +02:00
|
|
|
*
|
2017-04-25 14:41:48 +02:00
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
2023-02-24 03:27:08 +01:00
|
|
|
ExtRegion *
|
2026-01-09 17:58:35 +01:00
|
|
|
ExtFindRegions(def, area, mask, connectsTo, first, each)
|
2017-04-25 14:41:48 +02:00
|
|
|
CellDef *def; /* Cell definition being searched */
|
|
|
|
|
Rect *area; /* Area to search initially for tiles */
|
|
|
|
|
TileTypeBitMask *mask; /* In the initial area search, only visit
|
|
|
|
|
* tiles whose types are in this mask.
|
|
|
|
|
*/
|
|
|
|
|
TileTypeBitMask *connectsTo;/* Connectivity table for determining regions.
|
|
|
|
|
* If t1 and t2 are the types of adjacent
|
|
|
|
|
* tiles, then t1 and t2 belong to the same
|
|
|
|
|
* region iff:
|
|
|
|
|
* TTMaskHasType(&connectsTo[t1], t2)
|
|
|
|
|
*
|
|
|
|
|
* We assume that connectsTo[] is symmetric,
|
|
|
|
|
* so this is the same as:
|
|
|
|
|
* TTMaskHasType(&connectsTo[t2], t1)
|
|
|
|
|
*/
|
2023-02-24 03:27:08 +01:00
|
|
|
ExtRegion * (*first)(); /* Applied to first tile in region */
|
2017-04-25 14:41:48 +02:00
|
|
|
int (*each)(); /* Applied to each tile in region */
|
|
|
|
|
{
|
|
|
|
|
FindRegion arg;
|
|
|
|
|
int extRegionAreaFunc();
|
|
|
|
|
|
|
|
|
|
ASSERT(first != NULL, "ExtFindRegions");
|
|
|
|
|
arg.fra_connectsTo = connectsTo;
|
|
|
|
|
arg.fra_def = def;
|
2026-01-09 17:58:35 +01:00
|
|
|
arg.fra_uninit = CLIENTDEFAULT;
|
2017-04-25 14:41:48 +02:00
|
|
|
arg.fra_first = first;
|
|
|
|
|
arg.fra_each = each;
|
2023-02-24 03:27:08 +01:00
|
|
|
arg.fra_region = (ExtRegion *) NULL;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2022-04-05 03:16:03 +02:00
|
|
|
/* Make sure temp_subsnode is NULL */
|
|
|
|
|
temp_subsnode = NULL;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
SigDisableInterrupts();
|
|
|
|
|
for (arg.fra_pNum=PL_TECHDEPBASE; arg.fra_pNum<DBNumPlanes; arg.fra_pNum++)
|
|
|
|
|
(void) DBSrPaintClient((Tile *) NULL, def->cd_planes[arg.fra_pNum],
|
2026-01-09 17:58:35 +01:00
|
|
|
area, mask, CLIENTDEFAULT, extRegionAreaFunc, (ClientData) &arg);
|
2017-04-25 14:41:48 +02:00
|
|
|
SigEnableInterrupts();
|
|
|
|
|
|
|
|
|
|
return (arg.fra_region);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* extRegionAreaFunc --
|
|
|
|
|
*
|
|
|
|
|
* Filter function called for each tile found during the area enumeration
|
|
|
|
|
* in ExtFindRegions above. Only tiles whose ti_client is not already
|
|
|
|
|
* equal to arg->fra_uninit are visited.
|
|
|
|
|
*
|
|
|
|
|
* We call 'fra_first' to allocate a new region struct for it, and then
|
2023-02-24 03:27:08 +01:00
|
|
|
* prepend it to the ExtRegion list (ExtRegion *) arg->fra_clientData. We
|
2017-04-25 14:41:48 +02:00
|
|
|
* then call ExtFindNeighbors to trace out recursively all the remaining
|
|
|
|
|
* tiles in the region.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0, to cause DBSrPaintClient to continue its search.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
2023-02-24 03:27:08 +01:00
|
|
|
* Allocates a new ExtRegion struct if the tile has not yet been visited.
|
2017-04-25 14:41:48 +02:00
|
|
|
* See also the comments for ExtFindNeighbors.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2026-01-03 02:12:37 +01:00
|
|
|
extRegionAreaFunc(tile, dinfo, arg)
|
2017-04-25 14:41:48 +02:00
|
|
|
Tile *tile;
|
2026-01-03 02:12:37 +01:00
|
|
|
TileType dinfo;
|
2017-04-25 14:41:48 +02:00
|
|
|
FindRegion *arg;
|
|
|
|
|
{
|
|
|
|
|
/* Allocate a new region */
|
|
|
|
|
if (arg->fra_first)
|
2026-01-03 02:12:37 +01:00
|
|
|
(void) (*arg->fra_first)(tile, dinfo, arg);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
if (DebugIsSet(extDebugID, extDebAreaEnum))
|
|
|
|
|
extShowTile(tile, "area enum", 0);
|
|
|
|
|
|
|
|
|
|
/* Recursively visit all tiles surrounding this one that we connect to */
|
2026-01-03 02:12:37 +01:00
|
|
|
(void) ExtFindNeighbors(tile, dinfo, arg->fra_pNum, arg);
|
2017-04-25 14:41:48 +02:00
|
|
|
return (0);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* ExtLabelRegions --
|
|
|
|
|
*
|
|
|
|
|
* Given a CellDef whose tiles have been set to point to LabRegions
|
|
|
|
|
* by ExtFindRegions, walk down the label list and assign labels
|
|
|
|
|
* to regions. If the tile over which a label lies is still uninitialized
|
2026-01-09 17:58:35 +01:00
|
|
|
* ie, points to CLIENTDEFAULT, we skip the label.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* A label is attached to the LabRegion for a tile if the label's
|
|
|
|
|
* type and the tile's type are connected according to the table
|
|
|
|
|
* 'connTo'. This disambiguates the case where a label lies
|
|
|
|
|
* on the boundary between two tiles of different types.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
2022-02-26 23:39:36 +01:00
|
|
|
* When called with a NULL nodeList, any default substrate
|
|
|
|
|
* label found will be returned (in a pointer to a LabelList
|
|
|
|
|
* structure). This feature is used by extHardProc().
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Each LabRegion has labels added to its label list.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
2022-02-26 23:39:36 +01:00
|
|
|
LabelList *
|
2017-04-25 14:41:48 +02:00
|
|
|
ExtLabelRegions(def, connTo, nodeList, clipArea)
|
|
|
|
|
CellDef *def; /* Cell definition being labelled */
|
|
|
|
|
TileTypeBitMask *connTo; /* Connectivity table (see above) */
|
|
|
|
|
NodeRegion **nodeList; /* Node list to add to (or NULL) */
|
|
|
|
|
Rect *clipArea; /* Area to search for sticky labels */
|
|
|
|
|
{
|
|
|
|
|
static Point offsets[] = { { 0, 0 }, { 0, -1 }, { -1, -1 }, { -1, 0 } };
|
|
|
|
|
LabelList *ll;
|
|
|
|
|
Label *lab;
|
|
|
|
|
Tile *tp;
|
|
|
|
|
LabRegion *reg;
|
2022-04-05 03:16:03 +02:00
|
|
|
NodeRegion *newNode;
|
|
|
|
|
int quad, pNum, n, nclasses;
|
2017-04-25 14:41:48 +02:00
|
|
|
Point p;
|
Corrected a subtle error in substrate extraction: In extHierSubstrate(),
extFindNodes() is called to find just the substrate node, then
ExtLabelRegions() is called to label the substrate node if such a label
exists. The ExtLabelRegions() routine has a section at line 344 in which
if it finds a label on the substrate plane that is over space, then it
attaches the label to the default substrate region. However, if the
label is inside an isolated substrate region, then it passes this check,
which never actually detects whether or not the label is over space.
Doing so is actually simple, since the preceding code detected connecting
tiles under the label, and that fact just needed to be carried forward
and checked. The upshot of the error was that if an isolated substrate
region like a pwell inside deep nwell was *labeled*, then it would
mysteriously get shorted to the global substrate, which is clearly wrong.
Thanks to Mark Martin for providing the failing example (and apologies to
Mark Martin for spending time trying to debug a very obscure problem).
2026-07-11 23:09:26 +02:00
|
|
|
bool found, connected;
|
2022-02-23 21:02:40 +01:00
|
|
|
TileType extSubType = 0;
|
2022-02-26 23:39:36 +01:00
|
|
|
LabelList *retList = NULL;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
|
|
|
|
{
|
|
|
|
|
found = FALSE;
|
Corrected a subtle error in substrate extraction: In extHierSubstrate(),
extFindNodes() is called to find just the substrate node, then
ExtLabelRegions() is called to label the substrate node if such a label
exists. The ExtLabelRegions() routine has a section at line 344 in which
if it finds a label on the substrate plane that is over space, then it
attaches the label to the default substrate region. However, if the
label is inside an isolated substrate region, then it passes this check,
which never actually detects whether or not the label is over space.
Doing so is actually simple, since the preceding code detected connecting
tiles under the label, and that fact just needed to be carried forward
and checked. The upshot of the error was that if an isolated substrate
region like a pwell inside deep nwell was *labeled*, then it would
mysteriously get shorted to the global substrate, which is clearly wrong.
Thanks to Mark Martin for providing the failing example (and apologies to
Mark Martin for spending time trying to debug a very obscure problem).
2026-07-11 23:09:26 +02:00
|
|
|
connected = FALSE;
|
2017-04-25 14:41:48 +02:00
|
|
|
pNum = DBPlane(lab->lab_type);
|
|
|
|
|
if (lab->lab_type == TT_SPACE || pNum < PL_TECHDEPBASE)
|
|
|
|
|
continue;
|
2022-01-14 22:13:36 +01:00
|
|
|
/*
|
|
|
|
|
* See ExtBasic.c: Labels that do not get output as "equiv"
|
|
|
|
|
* records in the .ext file cannot be used for merges and
|
|
|
|
|
* caps.
|
|
|
|
|
*/
|
|
|
|
|
if (lab->lab_port == INFINITY) continue;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
for (quad = 0; quad < 4; quad++)
|
|
|
|
|
{
|
Corrected a subtle error in substrate extraction: In extHierSubstrate(),
extFindNodes() is called to find just the substrate node, then
ExtLabelRegions() is called to label the substrate node if such a label
exists. The ExtLabelRegions() routine has a section at line 344 in which
if it finds a label on the substrate plane that is over space, then it
attaches the label to the default substrate region. However, if the
label is inside an isolated substrate region, then it passes this check,
which never actually detects whether or not the label is over space.
Doing so is actually simple, since the preceding code detected connecting
tiles under the label, and that fact just needed to be carried forward
and checked. The upshot of the error was that if an isolated substrate
region like a pwell inside deep nwell was *labeled*, then it would
mysteriously get shorted to the global substrate, which is clearly wrong.
Thanks to Mark Martin for providing the failing example (and apologies to
Mark Martin for spending time trying to debug a very obscure problem).
2026-07-11 23:09:26 +02:00
|
|
|
bool locconn;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
2020-10-26 18:01:04 +01:00
|
|
|
* Visit each of the four quadrants surrounding the center
|
|
|
|
|
* point of the label, searching for a tile whose type matches
|
|
|
|
|
* that of the label or connects to it.
|
2017-04-25 14:41:48 +02:00
|
|
|
*/
|
2020-10-26 18:01:04 +01:00
|
|
|
p.p_x = ((lab->lab_rect.r_xbot + lab->lab_rect.r_xtop) >> 1)
|
|
|
|
|
+ offsets[quad].p_x;
|
|
|
|
|
p.p_y = ((lab->lab_rect.r_ybot + lab->lab_rect.r_ytop) >> 1)
|
|
|
|
|
+ offsets[quad].p_y;
|
2025-02-21 19:15:02 +01:00
|
|
|
tp = PlaneGetHint(def->cd_planes[pNum]);
|
2017-04-25 14:41:48 +02:00
|
|
|
GOTOPOINT(tp, &p);
|
2025-02-21 19:15:02 +01:00
|
|
|
PlaneSetHint(def->cd_planes[pNum], tp);
|
Corrected a subtle error in substrate extraction: In extHierSubstrate(),
extFindNodes() is called to find just the substrate node, then
ExtLabelRegions() is called to label the substrate node if such a label
exists. The ExtLabelRegions() routine has a section at line 344 in which
if it finds a label on the substrate plane that is over space, then it
attaches the label to the default substrate region. However, if the
label is inside an isolated substrate region, then it passes this check,
which never actually detects whether or not the label is over space.
Doing so is actually simple, since the preceding code detected connecting
tiles under the label, and that fact just needed to be carried forward
and checked. The upshot of the error was that if an isolated substrate
region like a pwell inside deep nwell was *labeled*, then it would
mysteriously get shorted to the global substrate, which is clearly wrong.
Thanks to Mark Martin for providing the failing example (and apologies to
Mark Martin for spending time trying to debug a very obscure problem).
2026-07-11 23:09:26 +02:00
|
|
|
|
|
|
|
|
locconn = extConnectsTo(TiGetType(tp), lab->lab_type, connTo);
|
|
|
|
|
if (locconn && extHasRegion(tp, CLIENTDEFAULT))
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
found = TRUE;
|
2026-01-09 17:58:35 +01:00
|
|
|
reg = (LabRegion *) ExtGetRegion(tp, (TileType)0);
|
2017-04-25 14:41:48 +02:00
|
|
|
ll = (LabelList *) mallocMagic((unsigned) (sizeof (LabelList)));
|
|
|
|
|
ll->ll_label = lab;
|
|
|
|
|
if (lab->lab_flags & PORT_DIR_MASK)
|
|
|
|
|
ll->ll_attr = LL_PORTATTR;
|
|
|
|
|
else
|
|
|
|
|
ll->ll_attr = LL_NOATTR;
|
2023-06-27 21:35:57 +02:00
|
|
|
|
|
|
|
|
if ((lab->lab_flags & PORT_DIR_MASK) || (reg->lreg_labels == NULL))
|
|
|
|
|
{
|
|
|
|
|
ll->ll_next = reg->lreg_labels;
|
|
|
|
|
reg->lreg_labels = ll;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LabelList *fport = reg->lreg_labels;
|
|
|
|
|
|
|
|
|
|
/* Place *after* any labels with LL_PORTATTR */
|
|
|
|
|
while ((fport->ll_next != NULL) &&
|
|
|
|
|
(fport->ll_next->ll_attr == LL_PORTATTR))
|
|
|
|
|
fport = fport->ll_next;
|
|
|
|
|
|
|
|
|
|
ll->ll_next = fport->ll_next;
|
|
|
|
|
fport->ll_next = ll;
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
break;
|
|
|
|
|
}
|
Corrected a subtle error in substrate extraction: In extHierSubstrate(),
extFindNodes() is called to find just the substrate node, then
ExtLabelRegions() is called to label the substrate node if such a label
exists. The ExtLabelRegions() routine has a section at line 344 in which
if it finds a label on the substrate plane that is over space, then it
attaches the label to the default substrate region. However, if the
label is inside an isolated substrate region, then it passes this check,
which never actually detects whether or not the label is over space.
Doing so is actually simple, since the preceding code detected connecting
tiles under the label, and that fact just needed to be carried forward
and checked. The upshot of the error was that if an isolated substrate
region like a pwell inside deep nwell was *labeled*, then it would
mysteriously get shorted to the global substrate, which is clearly wrong.
Thanks to Mark Martin for providing the failing example (and apologies to
Mark Martin for spending time trying to debug a very obscure problem).
2026-07-11 23:09:26 +02:00
|
|
|
else if (locconn)
|
|
|
|
|
/* Label connects to a tile here (but it is not a
|
|
|
|
|
* substrate region).
|
|
|
|
|
*/
|
|
|
|
|
connected = TRUE;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
2022-02-26 23:39:36 +01:00
|
|
|
if (found == FALSE)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2022-02-24 22:47:11 +01:00
|
|
|
/* Handle unconnected node label. */
|
2017-04-25 14:41:48 +02:00
|
|
|
|
Corrected a subtle error in substrate extraction: In extHierSubstrate(),
extFindNodes() is called to find just the substrate node, then
ExtLabelRegions() is called to label the substrate node if such a label
exists. The ExtLabelRegions() routine has a section at line 344 in which
if it finds a label on the substrate plane that is over space, then it
attaches the label to the default substrate region. However, if the
label is inside an isolated substrate region, then it passes this check,
which never actually detects whether or not the label is over space.
Doing so is actually simple, since the preceding code detected connecting
tiles under the label, and that fact just needed to be carried forward
and checked. The upshot of the error was that if an isolated substrate
region like a pwell inside deep nwell was *labeled*, then it would
mysteriously get shorted to the global substrate, which is clearly wrong.
Thanks to Mark Martin for providing the failing example (and apologies to
Mark Martin for spending time trying to debug a very obscure problem).
2026-07-11 23:09:26 +02:00
|
|
|
/* If the label is the substrate type and is over space,
|
|
|
|
|
* then assign the label to the default substrate region.
|
|
|
|
|
* The label need not be in the clip area. The check for
|
|
|
|
|
* "connected" eliminates labels attached to isolated
|
|
|
|
|
* substrate regions (the label is not over space).
|
|
|
|
|
*/
|
2022-02-24 22:47:11 +01:00
|
|
|
|
2022-04-05 03:16:03 +02:00
|
|
|
ll = (LabelList *)NULL;
|
2022-02-24 22:47:11 +01:00
|
|
|
if ((pNum == ExtCurStyle->exts_globSubstratePlane) &&
|
2022-02-23 21:02:40 +01:00
|
|
|
TTMaskHasType(&ExtCurStyle->exts_globSubstrateTypes,
|
Corrected a subtle error in substrate extraction: In extHierSubstrate(),
extFindNodes() is called to find just the substrate node, then
ExtLabelRegions() is called to label the substrate node if such a label
exists. The ExtLabelRegions() routine has a section at line 344 in which
if it finds a label on the substrate plane that is over space, then it
attaches the label to the default substrate region. However, if the
label is inside an isolated substrate region, then it passes this check,
which never actually detects whether or not the label is over space.
Doing so is actually simple, since the preceding code detected connecting
tiles under the label, and that fact just needed to be carried forward
and checked. The upshot of the error was that if an isolated substrate
region like a pwell inside deep nwell was *labeled*, then it would
mysteriously get shorted to the global substrate, which is clearly wrong.
Thanks to Mark Martin for providing the failing example (and apologies to
Mark Martin for spending time trying to debug a very obscure problem).
2026-07-11 23:09:26 +02:00
|
|
|
lab->lab_type) && (connected == FALSE))
|
2022-02-24 22:47:11 +01:00
|
|
|
{
|
2022-04-05 03:16:03 +02:00
|
|
|
if (nodeList != NULL)
|
|
|
|
|
{
|
|
|
|
|
/* temp_subsnode only defined when extFindNodes() */
|
|
|
|
|
/* was called before ExtLabelRegions() */
|
|
|
|
|
if (temp_subsnode != NULL)
|
|
|
|
|
{
|
|
|
|
|
ll = (LabelList *)mallocMagic(sizeof(LabelList));
|
|
|
|
|
ll->ll_label = lab;
|
|
|
|
|
if (lab->lab_flags & PORT_DIR_MASK)
|
|
|
|
|
ll->ll_attr = LL_PORTATTR;
|
|
|
|
|
else
|
|
|
|
|
ll->ll_attr = LL_NOATTR;
|
|
|
|
|
|
|
|
|
|
ll->ll_next = temp_subsnode->nreg_labels;
|
|
|
|
|
temp_subsnode->nreg_labels = ll;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2022-02-23 21:02:40 +01:00
|
|
|
{
|
|
|
|
|
ll = (LabelList *)mallocMagic(sizeof(LabelList));
|
|
|
|
|
ll->ll_label = lab;
|
|
|
|
|
if (lab->lab_flags & PORT_DIR_MASK)
|
|
|
|
|
ll->ll_attr = LL_PORTATTR;
|
|
|
|
|
else
|
|
|
|
|
ll->ll_attr = LL_NOATTR;
|
2022-02-26 23:39:36 +01:00
|
|
|
|
2022-04-05 03:16:03 +02:00
|
|
|
ll->ll_next = (LabelList *)NULL;
|
|
|
|
|
if (retList != NULL) freeMagic(retList);
|
|
|
|
|
retList = ll;
|
2022-02-24 22:47:11 +01:00
|
|
|
}
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2023-09-22 22:03:53 +02:00
|
|
|
/* This may be a "sticky label". If it is not connected to a
|
|
|
|
|
* non-electrical type (includes TT_SPACE), then create a new node
|
|
|
|
|
* region for it. The label must be within the clip area.
|
2022-02-24 22:47:11 +01:00
|
|
|
*/
|
2022-04-05 03:16:03 +02:00
|
|
|
if ((ll == NULL) && (nodeList != NULL) &&
|
2022-02-26 23:39:36 +01:00
|
|
|
(GEO_SURROUND(&lab->lab_rect, clipArea) ||
|
2022-02-24 22:47:11 +01:00
|
|
|
GEO_TOUCH(&lab->lab_rect, clipArea))
|
2023-09-22 22:03:53 +02:00
|
|
|
&& (lab->lab_type != TT_SPACE)
|
|
|
|
|
&& TTMaskHasType(&ExtCurStyle->exts_activeTypes, lab->lab_type))
|
2022-02-24 22:47:11 +01:00
|
|
|
{
|
|
|
|
|
nclasses = ExtCurStyle->exts_numResistClasses;
|
|
|
|
|
n = sizeof (NodeRegion) + (sizeof (PerimArea) * (nclasses - 1));
|
|
|
|
|
newNode = (NodeRegion *)mallocMagic((unsigned) n);
|
|
|
|
|
|
|
|
|
|
ll = (LabelList *)mallocMagic(sizeof(LabelList));
|
|
|
|
|
ll->ll_label = lab;
|
|
|
|
|
ll->ll_next = NULL;
|
|
|
|
|
if (lab->lab_flags & PORT_DIR_MASK)
|
|
|
|
|
ll->ll_attr = LL_PORTATTR;
|
|
|
|
|
else
|
|
|
|
|
ll->ll_attr = LL_NOATTR;
|
|
|
|
|
|
|
|
|
|
newNode->nreg_next = *nodeList;
|
|
|
|
|
newNode->nreg_pnum = pNum;
|
|
|
|
|
newNode->nreg_type = lab->lab_type;
|
|
|
|
|
newNode->nreg_ll = lab->lab_rect.r_ll;
|
|
|
|
|
newNode->nreg_cap = (CapValue)0;
|
|
|
|
|
newNode->nreg_resist = 0;
|
|
|
|
|
for (n = 0; n < nclasses; n++)
|
|
|
|
|
newNode->nreg_pa[n].pa_perim = newNode->nreg_pa[n].pa_area = 0;
|
|
|
|
|
newNode->nreg_labels = ll;
|
|
|
|
|
|
|
|
|
|
*nodeList = newNode;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-26 23:39:36 +01:00
|
|
|
return retList;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* ExtLabelOneRegion --
|
|
|
|
|
*
|
|
|
|
|
* Same as ExtLabelRegion, but it only assigns labels to one particular
|
|
|
|
|
* region.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The region has labels added to its label list.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ExtLabelOneRegion(def, connTo, reg)
|
|
|
|
|
CellDef *def; /* Cell definition being labelled */
|
|
|
|
|
TileTypeBitMask *connTo; /* Connectivity table (see above) */
|
|
|
|
|
NodeRegion *reg; /* The region whose labels we want */
|
|
|
|
|
{
|
|
|
|
|
static Point offsets[] = { { 0, 0 }, { 0, -1 }, { -1, -1 }, { -1, 0 } };
|
|
|
|
|
LabelList *ll;
|
|
|
|
|
Label *lab;
|
|
|
|
|
Tile *tp;
|
|
|
|
|
int quad, pNum;
|
|
|
|
|
Point p;
|
|
|
|
|
|
|
|
|
|
/* Generate segment list for subcircuit boundary, if any */
|
|
|
|
|
|
|
|
|
|
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
|
|
|
|
{
|
|
|
|
|
pNum = DBPlane(lab->lab_type);
|
|
|
|
|
if (lab->lab_type == TT_SPACE || pNum < PL_TECHDEPBASE)
|
|
|
|
|
continue;
|
|
|
|
|
for (quad = 0; quad < 4; quad++)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Visit each of the four quadrants surrounding
|
|
|
|
|
* the lower-left corner of the label, searching
|
|
|
|
|
* for a tile whose type matches that of the label
|
|
|
|
|
* or connects to it.
|
|
|
|
|
*/
|
|
|
|
|
p.p_x = lab->lab_rect.r_xbot + offsets[quad].p_x;
|
|
|
|
|
p.p_y = lab->lab_rect.r_ybot + offsets[quad].p_y;
|
2025-02-21 19:15:02 +01:00
|
|
|
tp = PlaneGetHint(def->cd_planes[pNum]);
|
2017-04-25 14:41:48 +02:00
|
|
|
GOTOPOINT(tp, &p);
|
2025-02-21 19:15:02 +01:00
|
|
|
PlaneSetHint(def->cd_planes[pNum], tp);
|
2017-04-25 14:41:48 +02:00
|
|
|
if (extConnectsTo(TiGetType(tp), lab->lab_type, connTo)
|
2026-01-09 17:58:35 +01:00
|
|
|
&& (NodeRegion *) ExtGetRegion(tp, (TileType)0) == reg)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
ll = (LabelList *) mallocMagic((unsigned) (sizeof (LabelList)));
|
|
|
|
|
ll->ll_label = lab;
|
|
|
|
|
if (lab->lab_flags & PORT_DIR_MASK)
|
|
|
|
|
ll->ll_attr = LL_PORTATTR;
|
|
|
|
|
else
|
|
|
|
|
ll->ll_attr = LL_NOATTR;
|
2023-06-27 21:35:57 +02:00
|
|
|
|
|
|
|
|
if ((lab->lab_flags & PORT_DIR_MASK) || (reg->nreg_labels == NULL))
|
|
|
|
|
{
|
|
|
|
|
ll->ll_next = reg->nreg_labels;
|
|
|
|
|
reg->nreg_labels = ll;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LabelList *fport = reg->nreg_labels;
|
|
|
|
|
|
|
|
|
|
/* Place *after* any labels with LL_PORTATTR */
|
|
|
|
|
while ((fport->ll_next != NULL) &&
|
|
|
|
|
(fport->ll_next->ll_attr == LL_PORTATTR))
|
|
|
|
|
fport = fport->ll_next;
|
|
|
|
|
|
|
|
|
|
ll->ll_next = fport->ll_next;
|
|
|
|
|
fport->ll_next = ll;
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* ExtResetTiles --
|
|
|
|
|
*
|
|
|
|
|
* Given a CellDef whose tiles have been set to point to Regions
|
|
|
|
|
* by ExtFindRegions, reset all the tiles to uninitialized.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* All the non-space tiles in the CellDef have their ti_client
|
2023-02-24 03:27:08 +01:00
|
|
|
* fields set back to uninitialized. Does not free the ExtRegion
|
2017-04-25 14:41:48 +02:00
|
|
|
* structs that these tiles point to; that must be done by
|
|
|
|
|
* ExtFreeRegions, ExtFreeLabRegions, or ExtFreeHierLabRegions.
|
|
|
|
|
*
|
|
|
|
|
* Non-interruptible.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ExtResetTiles(def, resetTo)
|
|
|
|
|
CellDef *def;
|
|
|
|
|
ClientData resetTo; /* New value for ti_client */
|
|
|
|
|
{
|
|
|
|
|
int pNum;
|
|
|
|
|
|
|
|
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
2026-01-09 17:58:35 +01:00
|
|
|
DBResetTilePlaneSpecial(def->cd_planes[pNum], resetTo);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* ExtFreeRegions --
|
|
|
|
|
* ExtFreeLabRegions --
|
|
|
|
|
* ExtFreeHierLabRegions --
|
|
|
|
|
*
|
|
|
|
|
* Free a list of Regions.
|
|
|
|
|
* ExtFreeLabRegions also frees the LabelLists pointed to by lreg_labels.
|
|
|
|
|
* ExtFreeHierLabRegions, in addition to freeing the LabelLists, frees
|
|
|
|
|
* the labels they point to.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Frees memory.
|
|
|
|
|
*
|
|
|
|
|
* Non-interruptible.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ExtFreeRegions(regList)
|
2023-02-24 03:27:08 +01:00
|
|
|
ExtRegion *regList; /* List of regions to be freed */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2023-02-24 03:27:08 +01:00
|
|
|
ExtRegion *reg;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2025-02-13 09:11:16 +01:00
|
|
|
free_magic1_t mm1 = freeMagic1_init();
|
2017-04-25 14:41:48 +02:00
|
|
|
for (reg = regList; reg; reg = reg->reg_next)
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1(&mm1, (char *) reg);
|
|
|
|
|
freeMagic1_end(&mm1);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ExtFreeLabRegions(regList)
|
|
|
|
|
LabRegion *regList; /* List of regions to be freed */
|
|
|
|
|
{
|
|
|
|
|
LabRegion *lreg;
|
|
|
|
|
LabelList *ll;
|
|
|
|
|
|
2025-02-13 09:11:16 +01:00
|
|
|
free_magic1_t mm1 = freeMagic1_init();
|
2017-04-25 14:41:48 +02:00
|
|
|
for (lreg = regList; lreg; lreg = lreg->lreg_next)
|
|
|
|
|
{
|
2025-02-13 09:11:16 +01:00
|
|
|
free_magic1_t mm1_ = freeMagic1_init();
|
2017-04-25 14:41:48 +02:00
|
|
|
for (ll = lreg->lreg_labels; ll; ll = ll->ll_next)
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1(&mm1_, (char *) ll);
|
|
|
|
|
freeMagic1_end(&mm1_);
|
|
|
|
|
freeMagic1(&mm1, (char *) lreg);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1_end(&mm1);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ExtFreeHierLabRegions(regList)
|
2023-02-24 03:27:08 +01:00
|
|
|
ExtRegion *regList; /* List of regions to be freed */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2023-02-24 03:27:08 +01:00
|
|
|
ExtRegion *reg;
|
2017-04-25 14:41:48 +02:00
|
|
|
LabelList *ll;
|
|
|
|
|
|
2025-02-13 09:11:16 +01:00
|
|
|
free_magic1_t mm1 = freeMagic1_init();
|
2017-04-25 14:41:48 +02:00
|
|
|
for (reg = regList; reg; reg = reg->reg_next)
|
|
|
|
|
{
|
2025-02-13 09:11:16 +01:00
|
|
|
free_magic1_t mm1_ = freeMagic1_init();
|
2017-04-25 14:41:48 +02:00
|
|
|
for (ll = ((LabRegion *)reg)->lreg_labels; ll; ll = ll->ll_next)
|
|
|
|
|
{
|
|
|
|
|
freeMagic((char *) ll->ll_label);
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1(&mm1_, (char *) ll);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1_end(&mm1_);
|
|
|
|
|
freeMagic1(&mm1, (char *) reg);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1_end(&mm1);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|