mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-08-30 01:48:43 +02:00
the extraction, especially for routines like ExtFindNeighbors where it was previously not handled at all. A new method was introduced in which split tiles with neither side TT_SPACE will get an extra allocated structure that contains pointers to two regions representing the nodes on the tile's left and right sides, independently. The fix (as yet not fully tested) should resolve problems with extracting the sky130 I/O cells, which contain a FET with 45 degree angles on the gate, where a split tile is divided between the gate and the source or drain, and therefore represents two different nodes. Also, there were extraction errors related to incorrect handling of split tiles having only one node, where a split tile became connected to the wrong node.
1037 lines
32 KiB
C
1037 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;
|
|
|
|
free_magic1_t mm1 = freeMagic1_init();
|
|
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);
|
|
freeMagic1(&mm1, lab);
|
|
parentDef->cd_labels = lab->lab_next;
|
|
}
|
|
freeMagic1_end(&mm1);
|
|
}
|
|
|
|
#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;
|
|
TileType dinfo;
|
|
|
|
tp = extNodeToTile(np, et1, &dinfo);
|
|
if (tp && TiGetType(tp) != TT_SPACE && extHasRegion(tp, CLIENTDEFAULT))
|
|
return (extArrayTileToNode(tp, dinfo, np->nreg_pnum, et1, ha, TRUE));
|
|
|
|
tp = extNodeToTile(np, et2, &dinfo);
|
|
if (tp && TiGetType(tp) != TT_SPACE && extHasRegion(tp, CLIENTDEFAULT))
|
|
return (extArrayTileToNode(tp, dinfo, 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 ExtRegion 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, dinfo, pNum, et, ha, doHard)
|
|
Tile *tp;
|
|
TileType dinfo;
|
|
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, CLIENTDEFAULT))
|
|
{
|
|
reg = (LabRegion *) ExtGetRegion(tp, dinfo);
|
|
if (reg->lreg_labels)
|
|
goto found;
|
|
}
|
|
|
|
if (!DebugIsSet(extDebugID, extDebNoHard))
|
|
if ((reg = (LabRegion *) extArrayHardNode(tp, dinfo, 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, dinfo, pNum, def, ha)
|
|
Tile *tp;
|
|
TileType dinfo;
|
|
int pNum;
|
|
CellDef *def;
|
|
HierExtractArg *ha;
|
|
{
|
|
TileType type;
|
|
char labelBuf[4096];
|
|
SearchContext scx;
|
|
HardWay arg;
|
|
|
|
if (IsSplit(tp))
|
|
type = (dinfo & TT_SIDE) ? TiGetRightType(tp) : TiGetLeftType(tp);
|
|
else
|
|
type = TiGetType(tp);
|
|
|
|
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, dinfo);
|
|
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);
|
|
}
|