1027 lines
32 KiB
C
1027 lines
32 KiB
C
/*
|
|
* ExtArray.c --
|
|
*
|
|
* Circuit extraction.
|
|
* Extract interactions between elements of an array.
|
|
* The routines 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/ExtArray.c,v 1.2 2009/05/30 03:14:00 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.h>
|
|
#include <string.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 "debug/debug.h"
|
|
#include "extract/extract.h"
|
|
#include "extract/extractInt.h"
|
|
#include "utils/signals.h"
|
|
#include "utils/styles.h"
|
|
#include "windows/windows.h"
|
|
#include "dbwind/dbwind.h"
|
|
|
|
/* Canonical interaction areas */
|
|
#define AREA_A 0
|
|
#define AREA_B 1
|
|
#define AREA_C 2
|
|
|
|
/* Imports from elsewhere in this module */
|
|
extern int extHardProc();
|
|
|
|
/* Local data passed to extArrayTileToNode() and its children */
|
|
Point extArrayPrimXY; /* X, Y indices of primary array element */
|
|
Point extArrayInterXY; /* X, Y indices of intersecting array element */
|
|
Transform extArrayPTrans; /* Transform from primary element to root */
|
|
Transform extArrayITrans; /* Transform from intersecting element ... */
|
|
int extArrayWhich; /* Which interaction area is being processed */
|
|
ExtTree *extArrayPrimary; /* Primary array element */
|
|
|
|
/* Forward declarations */
|
|
int extArrayFunc();
|
|
int extArrayPrimaryFunc(), extArrayInterFunc();
|
|
char *extArrayRange();
|
|
char *extArrayTileToNode();
|
|
LabRegion *extArrayHardNode();
|
|
char *extArrayNodeName();
|
|
|
|
void extArrayProcess();
|
|
void extArrayAdjust();
|
|
void extArrayHardSearch();
|
|
|
|
#if 0
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* extOutputGeneratedLabels ---
|
|
*
|
|
* Write to the .ext file output "node" lines for labels generated in
|
|
* the parent cell where paint in the subcell is not otherwise
|
|
* represented by a node in the parent. These nodes have no material
|
|
* in the parent, and therefore have no capacitance or resistance
|
|
* associated with them.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
extOutputGeneratedLabels(parentUse, f)
|
|
CellUse *parentUse;
|
|
FILE *f;
|
|
{
|
|
CellDef *parentDef;
|
|
Label *lab;
|
|
int n;
|
|
|
|
parentDef = parentUse->cu_def;
|
|
|
|
while ((lab = parentDef->cd_labels) != NULL)
|
|
{
|
|
if ((lab->lab_flags & LABEL_GENERATE) == 0) return;
|
|
|
|
fprintf(f, "node \"%s\" 0 0 %d %d %s",
|
|
lab->lab_text, lab->lab_rect.r_xbot,
|
|
lab->lab_rect.r_ybot,
|
|
DBTypeShortName(lab->lab_type));
|
|
for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
|
|
fprintf(f, " 0 0");
|
|
putc('\n', f);
|
|
freeMagic(lab);
|
|
parentDef->cd_labels = lab->lab_next;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extArray --
|
|
*
|
|
* Extract all connections resulting from interactions within each
|
|
* array of subcells in the cell parentUse->cu_def.
|
|
*
|
|
* This procedure only finds arrays, and then calls extArrayFunc() to
|
|
* do the real work. See the comments there for more details.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Outputs connections and adjustments to the file 'f'.
|
|
* There are two kinds of records; see extSubtree for a description.
|
|
* However, when we output nodenames, they may contain implicit
|
|
* subscripting information, e.g,
|
|
*
|
|
* cap a[1:3]/In a[2:4]/Phi1 deltaC
|
|
*
|
|
* which is like 3 separate "cap" records:
|
|
*
|
|
* cap a[1]/In a[2]/Phi1 deltaC
|
|
* cap a[2]/In a[3]/Phi1 deltaC
|
|
* cap a[3]/In a[4]/Phi1 deltaC
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
extArray(parentUse, f)
|
|
CellUse *parentUse;
|
|
FILE *f;
|
|
{
|
|
SearchContext scx;
|
|
HierExtractArg ha;
|
|
|
|
/*
|
|
* The connection hash table is initialized here but doesn't get
|
|
* cleared until the end. It is responsible for changes to the
|
|
* node structure over the entire cell 'parentUse->cu_def'.
|
|
*/
|
|
ha.ha_outf = f;
|
|
ha.ha_parentUse = parentUse;
|
|
ha.ha_nodename = extArrayTileToNode;
|
|
ha.ha_cumFlat.et_use = extYuseCum;
|
|
HashInit(&ha.ha_connHash, 32, 0);
|
|
|
|
/* The real work of processing each array is done by extArrayFunc() */
|
|
scx.scx_use = parentUse;
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
scx.scx_area = TiPlaneRect;
|
|
(void) DBCellSrArea(&scx, extArrayFunc, (ClientData) &ha);
|
|
|
|
#if 0
|
|
/* Output generated labels and remove them from the parent */
|
|
extOutputGeneratedLabels(parentUse, f);
|
|
#endif
|
|
|
|
/* Output connections and node adjustments */
|
|
extOutputConns(&ha.ha_connHash, f);
|
|
HashKill(&ha.ha_connHash);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extArrayFunc --
|
|
*
|
|
* Given a CellUse as argument, extract and output all the connections that
|
|
* result from interactions between neighboring elements of the array.
|
|
*
|
|
* Results:
|
|
* Returns 2 always so we stop after the first CellUse in the array.
|
|
*
|
|
* Side effects:
|
|
* Writes to the file 'ha->ha_outf'
|
|
*
|
|
* Design:
|
|
* To extract all the connections made between members of an array, we
|
|
* only have to look for interactions in three canonical areas, shaded as
|
|
* A, B, and C in the diagram below. Each interaction area consists only
|
|
* of the portion of overlap between the canonical cell (1 for A, B, and
|
|
* 2 for C) and its neighbors. Hence the exact size of the interaction
|
|
* areas depends on how much overlap there is. In the extreme cases,
|
|
* there may be no areas to check at all (instances widely separated),
|
|
* or there may even be areas with more than four instances overlapping
|
|
* (spacing less than half the size of the instance).
|
|
*
|
|
* -------------------------------------------------
|
|
* | | | |
|
|
* | 2 | | |
|
|
* | | | |
|
|
* | CCC | |
|
|
* --------------CCC--------------------------------
|
|
* | | | |
|
|
* | | | |
|
|
* | | | |
|
|
* | | | |
|
|
* AAAAAAAAAAAAAAaba-------------------------------|
|
|
* AAAAAAAAAAAAAAbab | |
|
|
* | BBB | |
|
|
* | 1 BBB | |
|
|
* | BBB | |
|
|
* --------------BBB--------------------------------
|
|
*
|
|
* In area A, we check for interactions with 1 and the elements directly
|
|
* above, or above and to the right. In area B, we check for interactions
|
|
* only with elements at the same level but to the right. In area C, we
|
|
* check for interactions only with elements below and to the right.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
extArrayFunc(scx, ha)
|
|
SearchContext *scx; /* Describes first element of array */
|
|
HierExtractArg *ha; /* Extraction context */
|
|
{
|
|
int xsep, ysep; /* X, Y separation in parent coordinates */
|
|
int xsize, ysize; /* X, Y sizes in parent coordinates */
|
|
int halo = ExtCurStyle->exts_sideCoupleHalo + 1;
|
|
CellUse *use = scx->scx_use;
|
|
CellDef *def = use->cu_def;
|
|
Rect tmp, tmp2, primary;
|
|
|
|
/* Skip uses that aren't arrays */
|
|
if ((use->cu_xlo == use->cu_xhi) && (use->cu_ylo == use->cu_yhi))
|
|
return (2);
|
|
|
|
if ((ExtOptions & (EXT_DOCOUPLING|EXT_DOADJUST))
|
|
!= (EXT_DOCOUPLING|EXT_DOADJUST))
|
|
halo = 1;
|
|
|
|
/*
|
|
* Compute the sizes and separations of elements, in coordinates
|
|
* of the parent. If the array is 1-dimensional, we set the
|
|
* corresponding spacing to an impossibly large distance.
|
|
*/
|
|
tmp.r_xbot = tmp.r_ybot = 0;
|
|
if (use->cu_xlo == use->cu_xhi)
|
|
tmp.r_xtop = def->cd_bbox.r_xtop - def->cd_bbox.r_xbot + 2;
|
|
else tmp.r_xtop = use->cu_xsep;
|
|
if (use->cu_ylo == use->cu_yhi)
|
|
tmp.r_ytop = def->cd_bbox.r_ytop - def->cd_bbox.r_ybot + 2;
|
|
else tmp.r_ytop = use->cu_ysep;
|
|
GeoTransRect(&use->cu_transform, &tmp, &tmp2);
|
|
xsep = tmp2.r_xtop - tmp2.r_xbot;
|
|
ysep = tmp2.r_ytop - tmp2.r_ybot;
|
|
GeoTransRect(&use->cu_transform, &def->cd_bbox, &tmp2);
|
|
xsize = tmp2.r_xtop - tmp2.r_xbot;
|
|
ysize = tmp2.r_ytop - tmp2.r_ybot;
|
|
|
|
/*
|
|
* For areas A and B, we will be looking at the interactions
|
|
* between the element in the lower-left corner of the array
|
|
* (in parent coordinates) and its neighbors to the top, right,
|
|
* and top-right.
|
|
*/
|
|
primary.r_xbot = use->cu_bbox.r_xbot;
|
|
primary.r_xtop = use->cu_bbox.r_xbot + 1;
|
|
primary.r_ybot = use->cu_bbox.r_ybot;
|
|
primary.r_ytop = use->cu_bbox.r_ybot + 1;
|
|
ha->ha_subUse = use;
|
|
|
|
/* Area A */
|
|
if (ysep <= ysize)
|
|
{
|
|
ha->ha_clipArea.r_xbot = use->cu_bbox.r_xbot;
|
|
ha->ha_clipArea.r_xtop = use->cu_bbox.r_xbot + xsize + halo;
|
|
ha->ha_clipArea.r_ybot = use->cu_bbox.r_ybot + ysep - halo;
|
|
ha->ha_clipArea.r_ytop = use->cu_bbox.r_ybot + ysize + halo;
|
|
ha->ha_interArea = ha->ha_clipArea;
|
|
extArrayWhich = AREA_A;
|
|
extArrayProcess(ha, &primary);
|
|
if (SigInterruptPending)
|
|
return (1);
|
|
}
|
|
|
|
/* Area B */
|
|
if (xsep <= xsize)
|
|
{
|
|
ha->ha_clipArea.r_xbot = use->cu_bbox.r_xbot + xsep - halo;
|
|
ha->ha_clipArea.r_xtop = use->cu_bbox.r_xbot + xsize + halo;
|
|
ha->ha_clipArea.r_ybot = use->cu_bbox.r_ybot;
|
|
ha->ha_clipArea.r_ytop = use->cu_bbox.r_ybot + ysize + halo;
|
|
ha->ha_interArea = ha->ha_clipArea;
|
|
extArrayWhich = AREA_B;
|
|
extArrayProcess(ha, &primary);
|
|
if (SigInterruptPending)
|
|
return (1);
|
|
}
|
|
|
|
/* Area C */
|
|
if (ysep <= ysize && xsep <= xsize)
|
|
{
|
|
/*
|
|
* For area C, we will be looking at the interactions between
|
|
* the element in the upper-left corner of the array (in parent
|
|
* coordinates) and its neighbors to the bottom-right only.
|
|
*/
|
|
primary.r_ybot = use->cu_bbox.r_ytop - 1;
|
|
primary.r_ytop = use->cu_bbox.r_ytop;
|
|
ha->ha_clipArea.r_xbot = use->cu_bbox.r_xbot + xsep - halo;
|
|
ha->ha_clipArea.r_xtop = use->cu_bbox.r_xbot + xsize + halo;
|
|
ha->ha_clipArea.r_ybot = use->cu_bbox.r_ytop - ysize - halo;
|
|
ha->ha_clipArea.r_ytop = use->cu_bbox.r_ytop - ysep + halo;
|
|
ha->ha_interArea = ha->ha_clipArea;
|
|
extArrayWhich = AREA_C;
|
|
extArrayProcess(ha, &primary);
|
|
}
|
|
|
|
return (2);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extArrayProcess --
|
|
*
|
|
* Process a single canonical interaction area for the arrayed CellUse
|
|
* 'ha->ha_subUse'. The area 'primary', in parent coordinates, should
|
|
* be contained in only one element of the array. For each other element
|
|
* in the array that appears in the area 'ha->ha_interArea', we determine
|
|
* all connections and R/C adjustments and output them in the form of an
|
|
* implicitly iterated "merge" or "adjust" line for the rest of the array.
|
|
*
|
|
* Expects extArrayWhich to be one of AREA_A, AREA_B, or AREA_C; this
|
|
* is the interaction area being searched.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* See extArrayPrimaryFunc and extArrayInterFunc for details.
|
|
* Trashes ha->ha_cumFlat.et_use.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
extArrayProcess(ha, primary)
|
|
HierExtractArg *ha;
|
|
Rect *primary; /* Area guaranteed to contain only the primary
|
|
* element of the array, against which we will
|
|
* extract all other elements that overlap the
|
|
* area 'ha->ha_interArea'.
|
|
*/
|
|
{
|
|
CellUse *use = ha->ha_subUse;
|
|
|
|
|
|
/*
|
|
* Yank the primary array element into a new yank buffer
|
|
* that we leave extArrayPrimary pointing to.
|
|
*/
|
|
extArrayPrimary = (ExtTree *) NULL;
|
|
if (DBArraySr(use, primary, extArrayPrimaryFunc, (ClientData) ha) == 0)
|
|
{
|
|
DBWFeedbackAdd(primary,
|
|
"System error: expected array element but none found",
|
|
ha->ha_parentUse->cu_def, 1, STYLE_MEDIUMHIGHLIGHTS);
|
|
extNumErrors++;
|
|
return;
|
|
}
|
|
if (SigInterruptPending) goto done;
|
|
|
|
/*
|
|
* Find and process all other elements that intersect ha->ha_interArea,
|
|
* extracting connections against extArrayPrimary.
|
|
*/
|
|
(void) DBArraySr(use, &ha->ha_interArea, extArrayInterFunc, (ClientData)ha);
|
|
|
|
done:
|
|
if (extArrayPrimary) extHierFreeOne(extArrayPrimary);
|
|
extArrayPrimary = (ExtTree *) NULL;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extArrayPrimaryFunc --
|
|
*
|
|
* Called by DBArraySr, which should only find a single array element.
|
|
* We record which element was found by setting extArrayPrimXY.p_x
|
|
* and extArrayPrimXY.p_y, and also the transform in extArrayPTrans
|
|
* for use by extArrayHardNode().
|
|
*
|
|
* We yank the paint and labels of this array element into a new ExtTree,
|
|
* which we leave extArrayPrimary pointing to. The area, perimeter,
|
|
* capacitance, and coupling capacitance for this element are extracted.
|
|
*
|
|
* Results:
|
|
* Returns 1 to cause DBArraySr to abort and return 1 itself.
|
|
* This is so the caller of DBArraySr can tell whether or not
|
|
* any elements were found (a sanity check).
|
|
*
|
|
* Side effects:
|
|
* See above.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
extArrayPrimaryFunc(use, trans, x, y, ha)
|
|
CellUse *use; /* Use of which this is an array element */
|
|
Transform *trans; /* Transform from coordinates of use->cu_def to those
|
|
* in use->cu_parent, for the array element (x, y).
|
|
*/
|
|
int x, y; /* X, Y indices of this array element */
|
|
HierExtractArg *ha;
|
|
{
|
|
CellDef *primDef;
|
|
HierYank hy;
|
|
|
|
/*
|
|
* Remember the indices of this array element.
|
|
* When we are looking for all other array elements intersecting
|
|
* this area, we will ignore this element. We also remember the
|
|
* transform in case we need to use it in extArrayHardNode().
|
|
*/
|
|
extArrayPrimXY.p_x = x, extArrayPrimXY.p_y = y;
|
|
extArrayPTrans = *trans;
|
|
|
|
/* Restrict searching to interaction area for this element of array */
|
|
GeoTransRect(trans, &use->cu_def->cd_bbox, &ha->ha_subArea);
|
|
GeoClip(&ha->ha_subArea, &ha->ha_interArea);
|
|
|
|
/* Yank this element into the primary buffer */
|
|
extArrayPrimary = extHierNewOne();
|
|
hy.hy_area = &ha->ha_subArea;
|
|
hy.hy_target = extArrayPrimary->et_use;
|
|
hy.hy_prefix = FALSE;
|
|
(void) extHierYankFunc(use, trans, x, y, &hy);
|
|
|
|
/*
|
|
* Extract extArrayPrimary, getting node capacitance, perimeter,
|
|
* and area, and coupling capacitances between nodes. Assign
|
|
* labels from primDef's label list.
|
|
*/
|
|
primDef = extArrayPrimary->et_use->cu_def;
|
|
extArrayPrimary->et_nodes = extFindNodes(primDef, &ha->ha_clipArea, FALSE);
|
|
ExtLabelRegions(primDef, ExtCurStyle->exts_nodeConn,
|
|
&extArrayPrimary->et_nodes, &ha->ha_clipArea);
|
|
if ((ExtOptions & (EXT_DOADJUST|EXT_DOCOUPLING))
|
|
== (EXT_DOADJUST|EXT_DOCOUPLING))
|
|
extFindCoupling(primDef, &extArrayPrimary->et_coupleHash,
|
|
&ha->ha_clipArea);
|
|
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extArrayInterFunc --
|
|
*
|
|
* Called by DBArraySr, which should find all array elements inside
|
|
* 'ha->ha_interArea' (in parent coordinates). If the array element
|
|
* (x, y) is the same as the primary element found by extArrayPrimaryFunc,
|
|
* i.e, the element (extArrayPrimXY.p_x, extArrayPrimXY.p_y), we
|
|
* skip it. Otherwise, we yank the overlap of this array element with
|
|
* 'ha->ha_interArea' into its own subtree and extract the interactions
|
|
* between it and extArrayPrimary.
|
|
*
|
|
* Results:
|
|
* Returns 0 to cause DBArraySr to continue.
|
|
*
|
|
* Side effects:
|
|
* Sets extArrayInterXY.p_x, extArrayInterXY.p_y to the element
|
|
* (x, y) so that lower-level functions have access to this information.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
extArrayInterFunc(use, trans, x, y, ha)
|
|
CellUse *use; /* Use of which this is an array element */
|
|
Transform *trans; /* Transform from use->cu_def to use->cu_parent
|
|
* coordinates, for the array element (x, y).
|
|
*/
|
|
int x, y; /* X, Y of this array element in use->cu_def coords */
|
|
HierExtractArg *ha;
|
|
{
|
|
CellUse *cumUse = ha->ha_cumFlat.et_use;
|
|
CellDef *cumDef = cumUse->cu_def;
|
|
SearchContext scx;
|
|
CellDef *oneDef;
|
|
ExtTree *oneFlat;
|
|
HierYank hy;
|
|
|
|
/* Skip this element if it is the primary one */
|
|
if (x == extArrayPrimXY.p_x && y == extArrayPrimXY.p_y)
|
|
return (0);
|
|
|
|
switch (extArrayWhich)
|
|
{
|
|
/*
|
|
* Area A is above, or above and to the right.
|
|
* Given where we search, there are no elements below and
|
|
* to the right of area A.
|
|
*/
|
|
case AREA_A:
|
|
if (x == extArrayPrimXY.p_x || y == extArrayPrimXY.p_y)
|
|
{
|
|
/*
|
|
* Exactly one of X or Y is the same as for
|
|
* the primary element.
|
|
*/
|
|
if (trans->t_a)
|
|
{
|
|
/*
|
|
* X, Y are still X, Y in parent.
|
|
* If X is different, this element is only to the
|
|
* right and so belongs to area B.
|
|
*/
|
|
if (x != extArrayPrimXY.p_x) return (0);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* X, Y are interchanged in parent.
|
|
* If Y is different, this element is only to the
|
|
* right and so belongs to area B.
|
|
*/
|
|
if (y != extArrayPrimXY.p_y) return (0);
|
|
}
|
|
}
|
|
break;
|
|
/*
|
|
* Area B is only interactions to the right (not
|
|
* above, or diagonally above or below), in parent
|
|
* coordinates.
|
|
*/
|
|
case AREA_B:
|
|
if (trans->t_a)
|
|
{
|
|
/* x, y are still x, y in parent */
|
|
if (y != extArrayPrimXY.p_y) return (0);
|
|
}
|
|
else
|
|
{
|
|
/* x, y are interchanged in parent */
|
|
if (x != extArrayPrimXY.p_x) return (0);
|
|
}
|
|
break;
|
|
/*
|
|
* Area C checks only diagonal interactions.
|
|
* Given where we search, there are no interactions
|
|
* above and to the right of area C; the only diagonal
|
|
* interactions are below and to the right.
|
|
*/
|
|
case AREA_C:
|
|
if (x == extArrayPrimXY.p_x || y == extArrayPrimXY.p_y)
|
|
return (0);
|
|
break;
|
|
}
|
|
|
|
/* Indicate which element this is to connection output routines */
|
|
extArrayInterXY.p_x = x, extArrayInterXY.p_y = y;
|
|
extArrayITrans = *trans;
|
|
|
|
/* Restrict searching to interaction area for this element of array */
|
|
GeoTransRect(trans, &use->cu_def->cd_bbox, &ha->ha_subArea);
|
|
GeoClip(&ha->ha_subArea, &ha->ha_interArea);
|
|
|
|
/* Yank this array element into a new ExtTree */
|
|
oneFlat = extHierNewOne();
|
|
hy.hy_area = &ha->ha_subArea;
|
|
hy.hy_target = oneFlat->et_use;
|
|
hy.hy_prefix = FALSE;
|
|
(void) extHierYankFunc(use, trans, x, y, &hy);
|
|
|
|
/*
|
|
* Extract node capacitance, perimeter, area, and coupling capacitance
|
|
* for this subtree. Labels come from the hierarchical labels yanked
|
|
* above, but may have additional labels added when we find names the
|
|
* hard way.
|
|
*/
|
|
oneDef = oneFlat->et_use->cu_def;
|
|
oneFlat->et_nodes = extFindNodes(oneDef, &ha->ha_clipArea, FALSE);
|
|
ExtLabelRegions(oneDef, ExtCurStyle->exts_nodeConn, &oneFlat->et_nodes,
|
|
&ha->ha_clipArea);
|
|
if ((ExtOptions & (EXT_DOADJUST|EXT_DOCOUPLING))
|
|
== (EXT_DOADJUST|EXT_DOCOUPLING))
|
|
extFindCoupling(oneDef, &oneFlat->et_coupleHash, &ha->ha_clipArea);
|
|
|
|
/* Process connections */
|
|
extHierConnections(ha, extArrayPrimary, oneFlat);
|
|
|
|
/* Process substrate connection */
|
|
if (use->cu_xlo == use->cu_xhi)
|
|
extHierSubstrate(ha, use, -1, y);
|
|
else if (use->cu_ylo == use->cu_yhi)
|
|
extHierSubstrate(ha, use, x, -1);
|
|
else
|
|
extHierSubstrate(ha, use, x, y);
|
|
|
|
ha->ha_cumFlat.et_nodes = (NodeRegion *) NULL;
|
|
if (ExtOptions & EXT_DOADJUST)
|
|
{
|
|
/* Build cumulative buffer from both extArrayPrimary and oneFlat */
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
scx.scx_area = TiPlaneRect;
|
|
scx.scx_use = oneFlat->et_use;
|
|
DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, cumUse);
|
|
scx.scx_use = extArrayPrimary->et_use;
|
|
DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, cumUse);
|
|
|
|
/*
|
|
* Extract everything in the cumulative buffer.
|
|
* Don't bother labelling the nodes, though, since we will never look
|
|
* at the node labels (we only search extArrayPrimary or oneFlat for
|
|
* the name of a node). Finally, compute and output adjustments for
|
|
* nodes and coupling capacitance.
|
|
*/
|
|
HashInit(&ha->ha_cumFlat.et_coupleHash, 32,
|
|
HashSize(sizeof (CoupleKey)));
|
|
ha->ha_cumFlat.et_nodes = extFindNodes(cumDef, &ha->ha_clipArea, FALSE);
|
|
if (ExtOptions & EXT_DOCOUPLING)
|
|
extFindCoupling(cumDef, &ha->ha_cumFlat.et_coupleHash,
|
|
&ha->ha_clipArea);
|
|
extArrayAdjust(ha, oneFlat, extArrayPrimary);
|
|
if (ExtOptions & EXT_DOCOUPLING)
|
|
extCapHashKill(&ha->ha_cumFlat.et_coupleHash);
|
|
}
|
|
|
|
/* Clean up */
|
|
if (oneFlat) extHierFreeOne(oneFlat);
|
|
if (ha->ha_cumFlat.et_nodes)
|
|
ExtFreeLabRegions((LabRegion *) ha->ha_cumFlat.et_nodes);
|
|
ha->ha_cumFlat.et_nodes = (NodeRegion *) NULL;
|
|
DBCellClearDef(cumDef);
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
extArrayAdjust(ha, et1, et2)
|
|
HierExtractArg *ha;
|
|
ExtTree *et1, *et2;
|
|
{
|
|
CapValue cap; /* value of capacitance WAS: int */
|
|
NodeRegion *np;
|
|
CoupleKey *ck;
|
|
HashEntry *he;
|
|
NodeName *nn;
|
|
HashSearch hs;
|
|
char *name;
|
|
|
|
/*
|
|
* Initialize the capacitance, perimeter, and area values
|
|
* in the Nodes in the hash table ha->ha_connHash, taking
|
|
* their values from the NodeRegions in ha->ha_cumFlat.
|
|
*/
|
|
for (np = ha->ha_cumFlat.et_nodes; np; np = np->nreg_next)
|
|
{
|
|
if ((name = extArrayNodeName(np, ha, et1, et2))
|
|
&& (he = HashLookOnly(&ha->ha_connHash, name))
|
|
&& (nn = (NodeName *) HashGetValue(he)))
|
|
{
|
|
nn->nn_node->node_cap = np->nreg_cap;
|
|
bcopy((char *) np->nreg_pa, (char *) nn->nn_node->node_pa,
|
|
ExtCurStyle->exts_numResistClasses * sizeof (PerimArea));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Coupling capacitance from et1 and et2 gets subtracted from that
|
|
* stored in ha->ha_cumFlat. Also, subtract the node capacitance,
|
|
* perimeter, and area of each subtree from ha->ha_cumFlat's nodes.
|
|
*/
|
|
extHierAdjustments(ha, &ha->ha_cumFlat, et1, et1);
|
|
extHierAdjustments(ha, &ha->ha_cumFlat, et2, et2);
|
|
|
|
HashStartSearch(&hs);
|
|
while (he = HashNext(&ha->ha_cumFlat.et_coupleHash, &hs))
|
|
{
|
|
cap = extGetCapValue(he) / ExtCurStyle->exts_capScale;
|
|
if (cap == 0)
|
|
continue;
|
|
|
|
ck = (CoupleKey *) he->h_key.h_words;
|
|
name = extArrayNodeName(ck->ck_1, ha, et1, et2);
|
|
fprintf(ha->ha_outf, "cap \"%s\" ", name);
|
|
name = extArrayNodeName(ck->ck_2, ha, et1, et2);
|
|
fprintf(ha->ha_outf, "\"%s\" %lg\n", name, cap);
|
|
}
|
|
}
|
|
|
|
char *
|
|
extArrayNodeName(np, ha, et1, et2)
|
|
NodeRegion *np;
|
|
HierExtractArg *ha;
|
|
ExtTree *et1, *et2;
|
|
{
|
|
Tile *tp;
|
|
|
|
tp = extNodeToTile(np, et1);
|
|
if (tp && TiGetType(tp) != TT_SPACE && extHasRegion(tp, extUnInit))
|
|
return (extArrayTileToNode(tp, np->nreg_pnum, et1, ha, TRUE));
|
|
|
|
tp = extNodeToTile(np, et2);
|
|
if (tp && TiGetType(tp) != TT_SPACE && extHasRegion(tp, extUnInit))
|
|
return (extArrayTileToNode(tp, np->nreg_pnum, et2, ha, TRUE));
|
|
|
|
return ("(none)");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extArrayTileToNode --
|
|
*
|
|
* Map from a Tile in a given ExtTree to the name of the node
|
|
* containing that tile.
|
|
*
|
|
* The node associated with a tile can be determined in one of the
|
|
* following ways:
|
|
*
|
|
* (1) Look for a label on the list of the Region pointed to by the
|
|
* tile planes of 'et->et_use->cu_def'. If no label was found,
|
|
* then try (2).
|
|
*
|
|
* (2) Call extArrayHardNode() to do a painful extraction of a label.
|
|
* See the comments in extArrayHardNode() for a description of
|
|
* the algorithm used. Only do this if doHard is TRUE.
|
|
*
|
|
* The actual name we use will be prefixed by the array use identifier
|
|
* (from ha->ha_subUse), followed by the range of subscripts for that array
|
|
* for which this is valid. The ExtTree 'et' tells us whether we are looking
|
|
* at the primary element of an array (when it is extArrayPrimary), or at
|
|
* one of the elements against which the primary is being extracted.
|
|
*
|
|
* Results:
|
|
* Returns a pointer to the name of the node containing
|
|
* the tile. If no node name was found, and doHard was
|
|
* TRUE, return the string "(none)"; if doHard was FALSE,
|
|
* return NULL.
|
|
*
|
|
* Side effects:
|
|
* The string returned is allocated from a static buffer, so
|
|
* subsequent calls to extArrayTileToNode() will overwrite
|
|
* the results returned in previous calls.
|
|
*
|
|
* Records an error with the feedback package if no node name
|
|
* could be found, and doHard was TRUE.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
char *
|
|
extArrayTileToNode(tp, pNum, et, ha, doHard)
|
|
Tile *tp;
|
|
int pNum;
|
|
ExtTree *et;
|
|
HierExtractArg *ha;
|
|
bool doHard; /* If TRUE, we look up this node's name the hard way
|
|
* if we can't find it any other way; otherwise, we
|
|
* return NULL if we can't find the node's name.
|
|
*/
|
|
{
|
|
static char name[2048];
|
|
static char errorStr[] =
|
|
"Cannot find the name of this node (probable extractor error)";
|
|
CellDef *def = et->et_use->cu_def;
|
|
CellUse *use = ha->ha_subUse;
|
|
char *srcp, *dstp, *endp;
|
|
bool hasX = (use->cu_xlo != use->cu_xhi);
|
|
bool hasY = (use->cu_ylo != use->cu_yhi);
|
|
int xdiff = extArrayInterXY.p_x - extArrayPrimXY.p_x;
|
|
int ydiff = extArrayInterXY.p_y - extArrayPrimXY.p_y;
|
|
LabRegion *reg;
|
|
Rect r;
|
|
|
|
if (extHasRegion(tp, extUnInit))
|
|
{
|
|
reg = (LabRegion *) extGetRegion(tp);
|
|
if (reg->lreg_labels)
|
|
goto found;
|
|
}
|
|
|
|
if (!DebugIsSet(extDebugID, extDebNoHard))
|
|
if (reg = (LabRegion *) extArrayHardNode(tp, pNum, def, ha))
|
|
goto found;
|
|
|
|
/* Blew it */
|
|
if (!doHard) return ((char *) NULL);
|
|
extNumErrors++;
|
|
TiToRect(tp, &r);
|
|
if (!DebugIsSet(extDebugID, extDebNoFeedback))
|
|
DBWFeedbackAdd(&r, errorStr, ha->ha_parentUse->cu_def, 1,
|
|
STYLE_MEDIUMHIGHLIGHTS);
|
|
return ("(none)");
|
|
|
|
found:
|
|
/* Copy in the use id, leaving room for [%d:%d,%d:%d] at the end */
|
|
srcp = use->cu_id;
|
|
dstp = name;
|
|
endp = &name[sizeof name - 40];
|
|
while (dstp < endp && (*dstp++ = *srcp++))
|
|
/* Nothing */;
|
|
if (dstp >= endp) goto done;
|
|
dstp--;
|
|
|
|
#define Far(v, lo, hi) ((v) == (lo) ? (hi) : (lo))
|
|
#define FarX(u) Far(extArrayPrimXY.p_x, (u)->cu_xlo, (u)->cu_xhi)
|
|
#define FarY(u) Far(extArrayPrimXY.p_y, (u)->cu_ylo, (u)->cu_yhi)
|
|
|
|
/*
|
|
* Append the array subscripts.
|
|
* Remember that 2-d arrays are subscripted [y,x] and not [x,y].
|
|
*/
|
|
if (def == extArrayPrimary->et_use->cu_def)
|
|
{
|
|
if (hasY)
|
|
dstp = extArrayRange(dstp, extArrayPrimXY.p_y,
|
|
FarY(use) - ydiff, FALSE, hasX);
|
|
if (hasX)
|
|
dstp = extArrayRange(dstp, extArrayPrimXY.p_x,
|
|
FarX(use) - xdiff, hasY, FALSE);
|
|
}
|
|
else
|
|
{
|
|
if (hasY)
|
|
dstp = extArrayRange(dstp, extArrayInterXY.p_y,
|
|
FarY(use), FALSE, hasX);
|
|
if (hasX)
|
|
dstp = extArrayRange(dstp, extArrayInterXY.p_x,
|
|
FarX(use), hasY, FALSE);
|
|
}
|
|
|
|
#undef Far
|
|
#undef FarX
|
|
#undef FarY
|
|
|
|
done:
|
|
*dstp++ = '/';
|
|
endp = &name[sizeof name - 1];
|
|
srcp = extNodeName(reg);
|
|
while (dstp < endp && (*dstp++ = *srcp++))
|
|
/* Nothing */;
|
|
|
|
*dstp = '\0';
|
|
return (name);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extArrayRange --
|
|
*
|
|
* Called by extArrayTileToNode above, we print a range of the form [lo:hi]
|
|
* into the string pointed to by 'dstp'. Guarantees that lo <= hi.
|
|
*
|
|
* Results:
|
|
* Returns a pointer to the NULL byte at the end of the string
|
|
* we print into (dstp).
|
|
*
|
|
* Side effects:
|
|
* Writes characters into 'dstp', which should be large enough
|
|
* to hold any possible string of the form [int:int].
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
char *
|
|
extArrayRange(dstp, lo, hi, prevRange, followRange)
|
|
char *dstp;
|
|
int lo, hi;
|
|
bool prevRange; /* TRUE if preceded by a range */
|
|
bool followRange; /* TRUE if followed by a range */
|
|
{
|
|
if (!prevRange) *dstp++ = '[';
|
|
if (hi < lo)
|
|
(void) sprintf(dstp, "%d:%d", hi, lo);
|
|
else
|
|
(void) sprintf(dstp, "%d:%d", lo, hi);
|
|
while (*dstp++) /* Nothing */;
|
|
dstp[-1] = followRange ? ',' : ']';
|
|
*dstp = '\0';
|
|
return (dstp);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extArrayHardNode --
|
|
*
|
|
* Find a node name for the electrical node containing the tile 'tp'
|
|
* the hard way. We assume tp->ti_client points to a LabRegion that
|
|
* had no labels associated with it; if we succeed, we leave this
|
|
* LabRegion pointing to a newly allocated LabelList and Label.
|
|
*
|
|
* Results:
|
|
* Returns a pointer to LabRegion for the node to which the tile
|
|
* 'tp' belongs. Returns NULL if no region could be found.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* Algorithm:
|
|
* Search in the appropriate array element to the yank buffer
|
|
* in question: if 'def' is the primary buffer, search the
|
|
* element (extArrayPrimXY.p_x, extArrayPrimXY.p_y); otherwise,
|
|
* search (extArrayInterXY.p_x, extArrayInterXY.p_y).
|
|
*
|
|
* For each cell we find in the course of a hierarchical search
|
|
* of this array element in the area of the tile 'tp', trace out
|
|
* the nodes lying in the area of the overlap, and then do a label
|
|
* assignment for those nodes. As soon as we find a label, we're
|
|
* done. Otherwise, we reset this def back the way we found it
|
|
* and continue on to the next cell in our search.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
LabRegion *
|
|
extArrayHardNode(tp, pNum, def, ha)
|
|
Tile *tp;
|
|
int pNum;
|
|
CellDef *def;
|
|
HierExtractArg *ha;
|
|
{
|
|
TileType type = TiGetType(tp);
|
|
char labelBuf[4096];
|
|
SearchContext scx;
|
|
HardWay arg;
|
|
|
|
arg.hw_ha = ha;
|
|
arg.hw_label = (Label *) NULL;
|
|
arg.hw_mask = DBPlaneTypes[pNum];
|
|
TTMaskAndMask(&arg.hw_mask, &DBConnectTbl[type]);
|
|
arg.hw_tpath.tp_last = &labelBuf[sizeof labelBuf - 3];
|
|
arg.hw_tpath.tp_first = arg.hw_tpath.tp_next = labelBuf;
|
|
arg.hw_prefix = FALSE;
|
|
arg.hw_autogen = FALSE;
|
|
TiToRect(tp, &arg.hw_area);
|
|
scx.scx_use = ha->ha_subUse;
|
|
|
|
/* Find a label in the interaction area */
|
|
labelBuf[0] = '\0';
|
|
extArrayHardSearch(def, &arg, &scx, extHardProc);
|
|
if (arg.hw_label == NULL)
|
|
{
|
|
labelBuf[0] = '\0';
|
|
arg.hw_autogen = TRUE;
|
|
extArrayHardSearch(def, &arg, &scx, extHardProc);
|
|
}
|
|
|
|
if (arg.hw_label)
|
|
{
|
|
LabRegion *lreg;
|
|
LabelList *ll;
|
|
|
|
lreg = (LabRegion *) extGetRegion(tp);
|
|
ll = (LabelList *) mallocMagic((unsigned) (sizeof (LabelList)));
|
|
lreg->lreg_labels = ll;
|
|
ll->ll_next = (LabelList *) NULL;
|
|
ll->ll_label = arg.hw_label;
|
|
arg.hw_label->lab_next = def->cd_labels;
|
|
def->cd_labels = arg.hw_label;
|
|
return (lreg);
|
|
}
|
|
|
|
return ((LabRegion *) NULL);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* extArrayHardSearch --
|
|
*
|
|
* Do the actual work of calling (*proc)() either to find a label the hard
|
|
* way, or to create a new label. Called from extArrayHardNode above.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Those of (*proc)().
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
extArrayHardSearch(def, arg, scx, proc)
|
|
CellDef *def;
|
|
HardWay *arg;
|
|
SearchContext *scx;
|
|
int (*proc)();
|
|
{
|
|
Transform tinv;
|
|
|
|
if (def == extArrayPrimary->et_use->cu_def)
|
|
{
|
|
scx->scx_trans = extArrayPTrans;
|
|
scx->scx_x = extArrayPrimXY.p_x;
|
|
scx->scx_y = extArrayPrimXY.p_y;
|
|
}
|
|
else
|
|
{
|
|
scx->scx_trans = extArrayITrans;
|
|
scx->scx_x = extArrayInterXY.p_x;
|
|
scx->scx_y = extArrayInterXY.p_y;
|
|
}
|
|
GeoInvertTrans(&scx->scx_trans, &tinv);
|
|
GeoTransRect(&tinv, &arg->hw_area, &scx->scx_area);
|
|
(void) (*proc)(scx, arg);
|
|
}
|