Compare commits
8 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
d24d52e403 | |
|
|
a93d248a5a | |
|
|
4ccd5a78d1 | |
|
|
f998f8ee6f | |
|
|
662e21a2d1 | |
|
|
949ec7672c | |
|
|
bd417aa54b | |
|
|
73e08e0c88 |
|
|
@ -487,8 +487,6 @@ enumerate:
|
||||||
newType = (method == (unsigned char)PAINT_XOR) ?
|
newType = (method == (unsigned char)PAINT_XOR) ?
|
||||||
*resultTbl : resultTbl[oldType];
|
*resultTbl : resultTbl[oldType];
|
||||||
|
|
||||||
if (mergeFlags & MRG_RIGHT)
|
|
||||||
tile = TiNMMergeRight(tile, plane); // was commented out?
|
|
||||||
if (mergeFlags & MRG_LEFT)
|
if (mergeFlags & MRG_LEFT)
|
||||||
TiNMMergeLeft(LB(newtile), plane);
|
TiNMMergeLeft(LB(newtile), plane);
|
||||||
}
|
}
|
||||||
|
|
@ -496,8 +494,6 @@ enumerate:
|
||||||
{
|
{
|
||||||
if (mergeFlags & MRG_LEFT)
|
if (mergeFlags & MRG_LEFT)
|
||||||
TiNMMergeLeft(newtile, plane);
|
TiNMMergeLeft(newtile, plane);
|
||||||
if (mergeFlags & MRG_RIGHT)
|
|
||||||
TiNMMergeRight(LB(tile), plane); // was commented out?
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
173
drc/DRCsubcell.c
173
drc/DRCsubcell.c
|
|
@ -27,6 +27,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
|
#include "utils/malloc.h"
|
||||||
#include "utils/signals.h"
|
#include "utils/signals.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "tiles/tile.h"
|
#include "tiles/tile.h"
|
||||||
|
|
@ -37,18 +38,12 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
#include "commands/commands.h"
|
#include "commands/commands.h"
|
||||||
#include "utils/undo.h"
|
#include "utils/undo.h"
|
||||||
|
|
||||||
/* The variables below are made owns so that they can be used to
|
/* The variables below are made global so that they can be used to
|
||||||
* pass information to the various search functions.
|
* pass information to the various search functions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static Rect drcSubIntArea; /* Accumulates area of interactions. */
|
|
||||||
static CellDef *drcSubDef; /* Cell definition we're checking. */
|
|
||||||
static int drcSubRadius; /* Interaction radius. */
|
|
||||||
static CellUse *drcCurSub; /* Holds current use while searching for interactions */
|
|
||||||
static Rect drcSubLookArea; /* Area where we're looking for interactions */
|
|
||||||
static void (*drcSubFunc)(); /* Error function. */
|
static void (*drcSubFunc)(); /* Error function. */
|
||||||
static ClientData drcSubClientData;
|
static ClientData drcSubClientData; /* To be passed to error function. */
|
||||||
/* To be passed to error function. */
|
|
||||||
|
|
||||||
/* The cookie below is dummied up to provide an error message for
|
/* The cookie below is dummied up to provide an error message for
|
||||||
* errors that occur because of inexact overlaps between subcells.
|
* errors that occur because of inexact overlaps between subcells.
|
||||||
|
|
@ -92,6 +87,28 @@ static DRCCookie drcOffGridCookie = {
|
||||||
extern int DRCErrorType;
|
extern int DRCErrorType;
|
||||||
extern CellDef *DRCErrorDef;
|
extern CellDef *DRCErrorDef;
|
||||||
|
|
||||||
|
/* Structure used to hold information about child uses found in the
|
||||||
|
* search area during DRCFindInteractions(), so these can be
|
||||||
|
* subsequently searched for sibling interactions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct drcLinkedUse {
|
||||||
|
CellUse *dlu_use; // Use being checked
|
||||||
|
Rect dlu_area; // Area of use to check (w/halo)
|
||||||
|
struct drcLinkedUse *dlu_next; // For linked list
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Structure used to pass information to and from drcSubcellFunc() */
|
||||||
|
|
||||||
|
struct drcSubcellArg {
|
||||||
|
CellDef *dsa_def; /* Cell use being checked */
|
||||||
|
int dsa_radius; /* Halo radius around area to check */
|
||||||
|
Rect *dsa_searchArea; /* Area of cell use being searched */
|
||||||
|
Rect *dsa_intArea; /* Total interaction area */
|
||||||
|
bool dsa_found; /* At least one interacting cell was found */
|
||||||
|
struct drcLinkedUse *dsa_dlu;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -113,12 +130,12 @@ extern CellDef *DRCErrorDef;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
drcFindOtherCells(use, area)
|
drcFindOtherCells(use, dlu)
|
||||||
CellUse *use;
|
CellUse *use;
|
||||||
Rect *area;
|
struct drcLinkedUse *dlu;
|
||||||
{
|
{
|
||||||
if (use != drcCurSub)
|
if (use != dlu->dlu_use)
|
||||||
GeoInclude(&use->cu_bbox, area);
|
GeoInclude(&use->cu_bbox, &dlu->dlu_area);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -228,68 +245,56 @@ drcSubCopyFunc(scx, cdarg)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
drcSubcellFunc(subUse, flags)
|
drcSubcellFunc(subUse, dsa)
|
||||||
CellUse *subUse; /* Subcell instance. */
|
CellUse *subUse; /* Subcell instance found in area. */
|
||||||
int *flags; /* Information to propagate up */
|
struct drcSubcellArg *dsa; /* Information needed for funtion and to pass
|
||||||
|
* back to the caller.
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
Rect area, haloArea, intArea, subIntArea, locIntArea;
|
Rect area, haloArea, intArea;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* A subcell has been seen, so set the "cell found" flag */
|
/* Record that a subcell has been seen in the search area. */
|
||||||
*flags |= CELLFOUND_FLAG;
|
dsa->dsa_found = TRUE;
|
||||||
|
|
||||||
/* To determine interactions, find the bounding box of
|
/* To determine interactions, find the bounding box of
|
||||||
* all paint and other subcells within one halo of this
|
* all paint and other subcells within one halo of this
|
||||||
* subcell (and also within the original area where
|
* subcell (and also within the original area where
|
||||||
* we're recomputing errors).
|
* we're recomputing errors).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
area = subUse->cu_bbox;
|
area = subUse->cu_bbox;
|
||||||
|
|
||||||
GEO_EXPAND(&area, drcSubRadius, &haloArea);
|
GEO_EXPAND(&area, dsa->dsa_radius, &haloArea);
|
||||||
GeoClip(&haloArea, &drcSubLookArea);
|
GeoClip(&haloArea, dsa->dsa_searchArea);
|
||||||
|
|
||||||
intArea = GeoNullRect;
|
intArea = GeoNullRect;
|
||||||
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
|
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
|
||||||
{
|
{
|
||||||
(void) DBSrPaintArea((Tile *) NULL, drcSubDef->cd_planes[i],
|
(void) DBSrPaintArea((Tile *) NULL, dsa->dsa_def->cd_planes[i],
|
||||||
&haloArea, &DBAllButSpaceBits, drcIncludeArea,
|
&haloArea, &DBAllButSpaceBits, drcIncludeArea,
|
||||||
(ClientData) &intArea);
|
(ClientData) &intArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DRC error tiles in a subcell are automatically pulled into the */
|
/* To check sibling interactions, DBSrCellPlaneArea() must not be
|
||||||
/* interaction area of the parent. Ultimately this is recursive as */
|
* called from within itself, so save the information about this
|
||||||
/* all cells are checked and errors propagate to the top level. */
|
* cell and its area in a linked list. If haloArea is already
|
||||||
|
* inside intArea, then do nothing.
|
||||||
|
*/
|
||||||
|
|
||||||
subIntArea = GeoNullRect;
|
if (!GEO_SURROUND(&intArea, &haloArea))
|
||||||
|
{
|
||||||
#if (0)
|
struct drcLinkedUse *newdlu;
|
||||||
/* NOTE: DRC errors inside a subcell should be ignored for */
|
newdlu = (struct drcLinkedUse *)mallocMagic(sizeof(struct drcLinkedUse));
|
||||||
/* the purpose of finding interactions. Errors should only */
|
newdlu->dlu_use = subUse;
|
||||||
/* be copied up into the parent when in a non-interaction */
|
newdlu->dlu_area = haloArea;
|
||||||
/* area. This is done below in DRCFindInteractions(). */
|
newdlu->dlu_next = dsa->dsa_dlu;
|
||||||
/* (Method added by Tim, 10/15/2020) */
|
dsa->dsa_dlu = newdlu;
|
||||||
|
}
|
||||||
/* Maybe S and PS errors should be pulled here? */
|
|
||||||
|
|
||||||
DBSrPaintArea((Tile *) NULL, subUse->cu_def->cd_planes[PL_DRC_ERROR],
|
|
||||||
&TiPlaneRect, &DBAllButSpaceBits, drcIncludeArea,
|
|
||||||
(ClientData) &subIntArea);
|
|
||||||
|
|
||||||
GeoTransRect(&(subUse->cu_transform), &subIntArea, &locIntArea);
|
|
||||||
GeoInclude(&locIntArea, &intArea);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!GEO_RECTNULL(&subIntArea)) *flags |= PROPAGATE_FLAG;
|
|
||||||
|
|
||||||
drcCurSub = subUse;
|
|
||||||
(void) DBSrCellPlaneArea(drcSubDef->cd_cellPlane, &haloArea,
|
|
||||||
drcFindOtherCells, (ClientData)(&intArea));
|
|
||||||
if (GEO_RECTNULL(&intArea)) return 0;
|
if (GEO_RECTNULL(&intArea)) return 0;
|
||||||
|
|
||||||
GEO_EXPAND(&intArea, drcSubRadius, &intArea);
|
GEO_EXPAND(&intArea, dsa->dsa_radius, &intArea);
|
||||||
GeoClip(&intArea, &haloArea);
|
GeoClip(&intArea, &haloArea);
|
||||||
(void) GeoInclude(&intArea, &drcSubIntArea);
|
(void) GeoInclude(&intArea, dsa->dsa_intArea);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -413,10 +418,11 @@ DRCFindInteractions(def, area, radius, interaction)
|
||||||
int i;
|
int i;
|
||||||
CellUse *use;
|
CellUse *use;
|
||||||
SearchContext scx;
|
SearchContext scx;
|
||||||
|
Rect searchArea, intArea;
|
||||||
int flags;
|
int flags;
|
||||||
|
struct drcSubcellArg dsa;
|
||||||
|
struct drcLinkedUse *curDLU;
|
||||||
|
|
||||||
drcSubDef = def;
|
|
||||||
drcSubRadius = radius;
|
|
||||||
DRCDummyUse->cu_def = def;
|
DRCDummyUse->cu_def = def;
|
||||||
|
|
||||||
/* Find all the interactions in the area and compute the
|
/* Find all the interactions in the area and compute the
|
||||||
|
|
@ -426,11 +432,53 @@ DRCFindInteractions(def, area, radius, interaction)
|
||||||
* each cell has material everywhere within its bounding box.
|
* each cell has material everywhere within its bounding box.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
drcSubIntArea = GeoNullRect;
|
GEO_EXPAND(area, radius, &searchArea);
|
||||||
GEO_EXPAND(area, radius, &drcSubLookArea);
|
intArea = GeoNullRect;
|
||||||
flags = 0;
|
|
||||||
(void) DBSrCellPlaneArea(def->cd_cellPlane, &drcSubLookArea,
|
/* Copy drcSubLookArea to a local Rect structure because it
|
||||||
drcSubcellFunc, (ClientData)(&flags));
|
* gets modified by drcSubcellFunc().
|
||||||
|
*/
|
||||||
|
|
||||||
|
dsa.dsa_def = def;
|
||||||
|
dsa.dsa_radius = radius;
|
||||||
|
dsa.dsa_searchArea = &searchArea;
|
||||||
|
dsa.dsa_intArea = &intArea;
|
||||||
|
dsa.dsa_found = FALSE;
|
||||||
|
dsa.dsa_dlu = (struct drcLinkedUse *)NULL;
|
||||||
|
|
||||||
|
(void) DBSrCellPlaneArea(def->cd_cellPlane, &searchArea,
|
||||||
|
drcSubcellFunc, (ClientData)&dsa);
|
||||||
|
|
||||||
|
/* If no subcells were in the search area, there is nothing
|
||||||
|
* more to do.
|
||||||
|
*/
|
||||||
|
if (dsa.dsa_found == FALSE) return -1;
|
||||||
|
|
||||||
|
/* If drcSubcellFunc() returned a list of uses, then check
|
||||||
|
* the area of each use for interacting sibling uses, and
|
||||||
|
* add the overlap to the potential interaction area.
|
||||||
|
*/
|
||||||
|
curDLU = dsa.dsa_dlu;
|
||||||
|
while (curDLU != NULL)
|
||||||
|
{
|
||||||
|
Rect subIntArea, subSearchArea;
|
||||||
|
struct drcLinkedUse *nextdlu = curDLU->dlu_next;
|
||||||
|
|
||||||
|
subSearchArea = curDLU->dlu_area;
|
||||||
|
curDLU->dlu_area = GeoNullRect;
|
||||||
|
|
||||||
|
(void) DBSrCellPlaneArea(def->cd_cellPlane, &subSearchArea,
|
||||||
|
drcFindOtherCells, (ClientData)curDLU);
|
||||||
|
|
||||||
|
/* Re-clip interaction area to subcell halo area */
|
||||||
|
GEO_EXPAND(&curDLU->dlu_area, radius, &curDLU->dlu_area);
|
||||||
|
GeoClip(&curDLU->dlu_area, &subSearchArea);
|
||||||
|
(void) GeoInclude(&curDLU->dlu_area, &intArea);
|
||||||
|
|
||||||
|
/* Free entry and move to next entry in linked list */
|
||||||
|
freeMagic((char *)curDLU);
|
||||||
|
curDLU = nextdlu;
|
||||||
|
}
|
||||||
|
|
||||||
/* If there seems to be an interaction area, make a second pass
|
/* If there seems to be an interaction area, make a second pass
|
||||||
* to make sure there's more than one cell with paint in the
|
* to make sure there's more than one cell with paint in the
|
||||||
|
|
@ -438,8 +486,7 @@ DRCFindInteractions(def, area, radius, interaction)
|
||||||
* have overlapping bounding boxes without overlapping paint.
|
* have overlapping bounding boxes without overlapping paint.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!(flags & CELLFOUND_FLAG)) return -1;
|
if (GEO_RECTNULL(&intArea)) return 0;
|
||||||
if (GEO_RECTNULL(&drcSubIntArea)) return 0;
|
|
||||||
use = NULL;
|
use = NULL;
|
||||||
|
|
||||||
/* If errors are being propagated up from child to parent, */
|
/* If errors are being propagated up from child to parent, */
|
||||||
|
|
@ -450,7 +497,7 @@ DRCFindInteractions(def, area, radius, interaction)
|
||||||
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
|
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
|
||||||
{
|
{
|
||||||
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[i],
|
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[i],
|
||||||
&drcSubIntArea, &DBAllButSpaceBits, drcAlwaysOne,
|
&intArea, &DBAllButSpaceBits, drcAlwaysOne,
|
||||||
(ClientData) NULL) != 0)
|
(ClientData) NULL) != 0)
|
||||||
{
|
{
|
||||||
use = (CellUse *) -1;
|
use = (CellUse *) -1;
|
||||||
|
|
@ -459,14 +506,14 @@ DRCFindInteractions(def, area, radius, interaction)
|
||||||
}
|
}
|
||||||
scx.scx_use = DRCDummyUse;
|
scx.scx_use = DRCDummyUse;
|
||||||
scx.scx_trans = GeoIdentityTransform;
|
scx.scx_trans = GeoIdentityTransform;
|
||||||
scx.scx_area = drcSubIntArea;
|
scx.scx_area = intArea;
|
||||||
if (DBTreeSrCells(&scx, 0, drcSubCheckPaint, (ClientData) &use) == 0)
|
if (DBTreeSrCells(&scx, 0, drcSubCheckPaint, (ClientData) &use) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK, no more excuses, there's really an interaction area here. */
|
/* OK, no more excuses, there's really an interaction area here. */
|
||||||
|
|
||||||
*interaction = drcSubIntArea;
|
*interaction = intArea;
|
||||||
GeoClip(interaction, area);
|
GeoClip(interaction, area);
|
||||||
if (GEO_RECTNULL(interaction)) return 0;
|
if (GEO_RECTNULL(interaction)) return 0;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
||||||
|
|
@ -378,6 +378,7 @@ spcHierWriteParams(
|
||||||
else
|
else
|
||||||
esSIvalue(esSpiceF, (dval + plist->parm_offset)
|
esSIvalue(esSpiceF, (dval + plist->parm_offset)
|
||||||
* scale * esScale * 1.0E-6);
|
* scale * esScale * 1.0E-6);
|
||||||
|
/* Why is this here? */
|
||||||
dparam->parm_name[0] = '\0';
|
dparam->parm_name[0] = '\0';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -602,6 +602,26 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
|
||||||
if (!strcasecmp(nodeName1, nodeName2)) equalByCase = TRUE;
|
if (!strcasecmp(nodeName1, nodeName2)) equalByCase = TRUE;
|
||||||
}
|
}
|
||||||
if (!equalByCase)
|
if (!equalByCase)
|
||||||
|
{
|
||||||
|
/* If one of the nodes has been generated from the
|
||||||
|
* other by "extract unique", then this is a case where
|
||||||
|
* the "extract unique" algorithm is blind to shorts
|
||||||
|
* through subcell hierarchy and has made a name unique
|
||||||
|
* unnecessarily. In that case, merge the node instead
|
||||||
|
* of generating a short.
|
||||||
|
*/
|
||||||
|
char *uniqstr1, *uniqstr2;
|
||||||
|
bool isuniq;
|
||||||
|
|
||||||
|
uniqstr1 = strstr(nodeName1, "_uq");
|
||||||
|
uniqstr2 = strstr(nodeName2, "_uq");
|
||||||
|
if (uniqstr1) *uniqstr1 = '\0';
|
||||||
|
if (uniqstr2) *uniqstr2 = '\0';
|
||||||
|
isuniq = !strcmp(nodeName1, nodeName2);
|
||||||
|
if (uniqstr1) *uniqstr1 = '_';
|
||||||
|
if (uniqstr2) *uniqstr2 = '_';
|
||||||
|
|
||||||
|
if (!isuniq)
|
||||||
{
|
{
|
||||||
if ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE)
|
if ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE)
|
||||||
{
|
{
|
||||||
|
|
@ -627,12 +647,16 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (!resist)
|
else if (!resist)
|
||||||
TxError("Warning: Ports \"%s\" and \"%s\" are electrically shorted.\n",
|
TxError("Warning: Ports \"%s\" and \"%s\" are electrically "
|
||||||
nodeName1, nodeName2);
|
"shorted.\n", nodeName1, nodeName2);
|
||||||
else
|
else
|
||||||
/* Do not merge the nodes when folding in extresist parasitics */
|
/* Do not merge the nodes when folding in extresist parasitics */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (resist)
|
||||||
|
/* Do not merge the nodes when folding in extresist parasitics */
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If both names exist and are for different nodes, merge them */
|
/* If both names exist and are for different nodes, merge them */
|
||||||
|
|
@ -652,8 +676,6 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
|
||||||
if (efWarn)
|
if (efWarn)
|
||||||
efReadError("Merged nodes %s and %s\n", nodeName1, nodeName2);
|
efReadError("Merged nodes %s and %s\n", nodeName1, nodeName2);
|
||||||
lostnode = efNodeMerge(&nn1->efnn_node, &nn2->efnn_node);
|
lostnode = efNodeMerge(&nn1->efnn_node, &nn2->efnn_node);
|
||||||
if (nn1->efnn_port > 0) nn2->efnn_port = nn1->efnn_port;
|
|
||||||
else if (nn2->efnn_port > 0) nn1->efnn_port = nn2->efnn_port;
|
|
||||||
|
|
||||||
/* Check if there are any device terminals pointing to the
|
/* Check if there are any device terminals pointing to the
|
||||||
* node that was just removed.
|
* node that was just removed.
|
||||||
|
|
@ -838,13 +860,13 @@ efBuildDevice(
|
||||||
const Rect *r, /* Coordinates of 1x1 rectangle entirely inside device */
|
const Rect *r, /* Coordinates of 1x1 rectangle entirely inside device */
|
||||||
int argc, /* Size of argv */
|
int argc, /* Size of argv */
|
||||||
char *argv[]) /* Tokens for the rest of the dev line.
|
char *argv[]) /* Tokens for the rest of the dev line.
|
||||||
* Starts with the last two position values, used to
|
* Starts after the four device coordinate arguments.
|
||||||
* hash the device record. The next arguments depend
|
* The next arguments (0, 1, or 2) depend on the type of
|
||||||
* on the type of device. The rest are taken in groups
|
* device, followed by optional parameters. The rest are
|
||||||
* of 3, one for each terminal. Each group of 3 consists
|
* taken in groups of 3, one for each terminal. Each
|
||||||
* of the node name to which the terminal connects, the
|
* group of 3 consists of the node name to which the
|
||||||
* length of the terminal, and an attribute list (or the
|
* terminal connects, the length of the terminal, and
|
||||||
* token 0).
|
* an attribute list (or the token 0).
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
int n, nterminals, pn;
|
int n, nterminals, pn;
|
||||||
|
|
@ -856,7 +878,7 @@ efBuildDevice(
|
||||||
int dev_type;
|
int dev_type;
|
||||||
char ptype, *pptr, **av;
|
char ptype, *pptr, **av;
|
||||||
char devhash[64];
|
char devhash[64];
|
||||||
int argstart = 1; /* start of terminal list in argv[] */
|
int termstart;
|
||||||
bool hasModel = strcmp(type, "None") ? TRUE : FALSE;
|
bool hasModel = strcmp(type, "None") ? TRUE : FALSE;
|
||||||
|
|
||||||
int area, perim; /* Total area, perimeter of primary type (i.e., channel) */
|
int area, perim; /* Total area, perimeter of primary type (i.e., channel) */
|
||||||
|
|
@ -871,24 +893,37 @@ efBuildDevice(
|
||||||
devtmp.dev_width = 0;
|
devtmp.dev_width = 0;
|
||||||
devtmp.dev_params = NULL;
|
devtmp.dev_params = NULL;
|
||||||
|
|
||||||
|
termstart = 1; /* Start of terminal list in argv[]; this is a default
|
||||||
|
* value if none of the cases below applies. The value
|
||||||
|
* of termstart does not initially account for parameter
|
||||||
|
* entries (<param>=<value>) but is adjusted as the
|
||||||
|
* parameters are parsed. The first terminal may be an
|
||||||
|
* (optional) substrate which is determined by whether
|
||||||
|
* the number of remaining arguments is divisible by 3
|
||||||
|
* or not.
|
||||||
|
*/
|
||||||
switch (class)
|
switch (class)
|
||||||
{
|
{
|
||||||
case DEV_FET:
|
case DEV_FET:
|
||||||
case DEV_MOSFET:
|
case DEV_MOSFET:
|
||||||
case DEV_ASYMMETRIC:
|
case DEV_ASYMMETRIC:
|
||||||
case DEV_BJT:
|
case DEV_BJT:
|
||||||
argstart = 3;
|
/* Terminals start after L and W values, plus parameters */
|
||||||
|
termstart = 2;
|
||||||
break;
|
break;
|
||||||
case DEV_DIODE:
|
case DEV_DIODE:
|
||||||
case DEV_NDIODE:
|
case DEV_NDIODE:
|
||||||
case DEV_PDIODE:
|
case DEV_PDIODE:
|
||||||
argstart = 0;
|
/* Terminals start immediately after parameters */
|
||||||
|
termstart = 0;
|
||||||
break;
|
break;
|
||||||
case DEV_RES:
|
case DEV_RES:
|
||||||
case DEV_CAP:
|
case DEV_CAP:
|
||||||
case DEV_CAPREV:
|
case DEV_CAPREV:
|
||||||
if (hasModel)
|
if (hasModel)
|
||||||
argstart = 2;
|
/* Terminals start after L and W values, plus parameters */
|
||||||
|
termstart = 2;
|
||||||
|
/* Otherwise, terminals start after device value, plus parameters */
|
||||||
break;
|
break;
|
||||||
case DEV_SUBCKT:
|
case DEV_SUBCKT:
|
||||||
case DEV_VERILOGA:
|
case DEV_VERILOGA:
|
||||||
|
|
@ -896,68 +931,121 @@ efBuildDevice(
|
||||||
case DEV_RSUBCKT:
|
case DEV_RSUBCKT:
|
||||||
case DEV_CSUBCKT:
|
case DEV_CSUBCKT:
|
||||||
case DEV_DSUBCKT:
|
case DEV_DSUBCKT:
|
||||||
argstart = 0;
|
/* Terminals start immediately after parameters */
|
||||||
|
termstart = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
devp = efGetDeviceParams(type);
|
devp = efGetDeviceParams(type);
|
||||||
|
|
||||||
/* Parse initial arguments for parameters */
|
/* Parse initial arguments for parameters */
|
||||||
while ((pptr = strchr(argv[argstart], '=')) != NULL)
|
while ((pptr = strchr(argv[termstart], '=')) != NULL)
|
||||||
{
|
{
|
||||||
// Check if this parameter is in the table.
|
/* If the parameter is in the parameter list "devp", then save
|
||||||
// If so, handle appropriately. Otherwise, the
|
* the value as appropriate. If not, then the entire phrase
|
||||||
// parameter gets saved verbatim locally. The
|
* will be output verbatim, so just save the whole string.
|
||||||
// "parameters" line comes before any "device" line
|
*
|
||||||
// in the .ext file, so the table should be complete.
|
* The "parameters" line comes before any "device" line in the
|
||||||
|
* .ext file, so the "devp" list should be complete.
|
||||||
|
*/
|
||||||
|
|
||||||
*pptr = '\0';
|
*pptr = '\0';
|
||||||
for (sparm = devp; sparm; sparm = sparm->parm_next)
|
for (sparm = devp; sparm; sparm = sparm->parm_next)
|
||||||
if (!strcasecmp(sparm->parm_type, argv[argstart]))
|
if (!strncasecmp(sparm->parm_type, argv[termstart], 2))
|
||||||
break;
|
break;
|
||||||
*pptr = '=';
|
*pptr = '=';
|
||||||
if (sparm == NULL)
|
if (sparm == NULL)
|
||||||
{
|
{
|
||||||
/* Copy the parameter into dev_params */
|
/* Copy the whole string into dev_params */
|
||||||
/* (parm_type and parm_scale records are not used) */
|
/* (parm_type and parm_scale records are not used) */
|
||||||
newparm = (DevParam *)mallocMagic(sizeof(DevParam));
|
newparm = (DevParam *)mallocMagic(sizeof(DevParam));
|
||||||
newparm->parm_name = StrDup((char **)NULL, argv[argstart]);
|
newparm->parm_name = StrDup((char **)NULL, argv[termstart]);
|
||||||
newparm->parm_next = devtmp.dev_params;
|
newparm->parm_next = devtmp.dev_params;
|
||||||
devtmp.dev_params = newparm;
|
devtmp.dev_params = newparm;
|
||||||
argstart++;
|
termstart++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pptr++;
|
pptr++;
|
||||||
switch(*argv[argstart])
|
switch(*argv[termstart])
|
||||||
{
|
{
|
||||||
case 'a':
|
case 'a':
|
||||||
if ((pptr - argv[argstart]) == 2)
|
if ((pptr - argv[termstart]) == 2)
|
||||||
devtmp.dev_area = atoi(pptr);
|
devtmp.dev_area = (int)(0.5 + (float)atoi(pptr)
|
||||||
|
* locScale * locScale);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pn = *(argv[argstart] + 1) - '0';
|
/* Check for a0, a1, a2, ... If a0, handle like "a".
|
||||||
|
* Otherwise, don't handle it here.
|
||||||
|
*/
|
||||||
|
pn = *(argv[termstart] + 1) - '0';
|
||||||
if (pn == 0)
|
if (pn == 0)
|
||||||
devtmp.dev_area = (int)(0.5 + (float)atoi(pptr)
|
devtmp.dev_area = (int)(0.5 + (float)atoi(pptr)
|
||||||
* locScale * locScale);
|
* locScale * locScale);
|
||||||
/* Otherwise, punt */
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
if ((pptr - argv[argstart]) == 2)
|
if ((pptr - argv[termstart]) == 2)
|
||||||
devtmp.dev_perim = atoi(pptr);
|
devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pn = *(argv[argstart] + 1) - '0';
|
/* Check for p0, p1, p2, ... If p0, handle like "p".
|
||||||
|
* Otherwise, don't handle it here.
|
||||||
|
*/
|
||||||
|
pn = *(argv[termstart] + 1) - '0';
|
||||||
if (pn == 0)
|
if (pn == 0)
|
||||||
devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale);
|
devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale);
|
||||||
/* Otherwise, use verbatim */
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
|
if ((pptr - argv[termstart]) == 2)
|
||||||
devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale);
|
devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Check for l0, l1, l2, ... If l0, handle like "l".
|
||||||
|
* Otherwise, save it verbatim like an unknown parameter,
|
||||||
|
* because its value will not be calculated from terminal
|
||||||
|
* values like "a1, a2, ..." or "p1, p2, ...".
|
||||||
|
*/
|
||||||
|
|
||||||
|
pn = *(argv[termstart] + 1) - '0';
|
||||||
|
if (pn == 0)
|
||||||
|
devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Copy the whole string into dev_params */
|
||||||
|
newparm = (DevParam *)mallocMagic(sizeof(DevParam));
|
||||||
|
newparm->parm_name = StrDup((char **)NULL, argv[termstart]);
|
||||||
|
newparm->parm_next = devtmp.dev_params;
|
||||||
|
devtmp.dev_params = newparm;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'w':
|
case 'w':
|
||||||
|
if ((pptr - argv[termstart]) == 2)
|
||||||
devtmp.dev_width = (int)(0.5 + (float)atoi(pptr) * locScale);
|
devtmp.dev_width = (int)(0.5 + (float)atoi(pptr) * locScale);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Check for w0, w1, w2, ... If w0, handle like "w".
|
||||||
|
* Otherwise, save it verbatim like an unknown parameter,
|
||||||
|
* because its value will not be calculated from terminal
|
||||||
|
* values like "a1, a2, ..." or "p1, p2, ...".
|
||||||
|
*/
|
||||||
|
|
||||||
|
pn = *(argv[termstart] + 1) - '0';
|
||||||
|
if (pn == 0)
|
||||||
|
devtmp.dev_width = (int)(0.5 + (float)atoi(pptr) * locScale);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Copy the whole string into dev_params */
|
||||||
|
newparm = (DevParam *)mallocMagic(sizeof(DevParam));
|
||||||
|
newparm->parm_name = StrDup((char **)NULL, argv[termstart]);
|
||||||
|
newparm->parm_next = devtmp.dev_params;
|
||||||
|
devtmp.dev_params = newparm;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
devtmp.dev_cap = (float)atof(pptr);
|
devtmp.dev_cap = (float)atof(pptr);
|
||||||
|
|
@ -966,7 +1054,7 @@ efBuildDevice(
|
||||||
devtmp.dev_res = (float)atof(pptr);
|
devtmp.dev_res = (float)atof(pptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
argstart++;
|
termstart++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for optional substrate node */
|
/* Check for optional substrate node */
|
||||||
|
|
@ -974,6 +1062,7 @@ efBuildDevice(
|
||||||
{
|
{
|
||||||
case DEV_RES:
|
case DEV_RES:
|
||||||
case DEV_CAP:
|
case DEV_CAP:
|
||||||
|
case DEV_BJT:
|
||||||
case DEV_CAPREV:
|
case DEV_CAPREV:
|
||||||
case DEV_RSUBCKT:
|
case DEV_RSUBCKT:
|
||||||
case DEV_CSUBCKT:
|
case DEV_CSUBCKT:
|
||||||
|
|
@ -984,22 +1073,22 @@ efBuildDevice(
|
||||||
case DEV_DIODE:
|
case DEV_DIODE:
|
||||||
case DEV_NDIODE:
|
case DEV_NDIODE:
|
||||||
case DEV_PDIODE:
|
case DEV_PDIODE:
|
||||||
n = argc - argstart;
|
n = argc - termstart;
|
||||||
if ((n % 3) == 1)
|
if ((n % 3) == 1)
|
||||||
{
|
{
|
||||||
if (strncmp(argv[argstart], "None", 4) != 0)
|
if (strncmp(argv[termstart], "None", 4) != 0)
|
||||||
devtmp.dev_subsnode = efBuildDevNode(def, argv[argstart], TRUE);
|
devtmp.dev_subsnode = efBuildDevNode(def, argv[termstart], TRUE);
|
||||||
|
|
||||||
argstart++;
|
termstart++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Between argstart and argc, we should only have terminal triples */
|
/* Between termstart and argc, we should only have terminal triples */
|
||||||
if (((argc - argstart) % 3) != 0)
|
if (((argc - termstart) % 3) != 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nterminals = (argc - argstart) / 3;
|
nterminals = (argc - termstart) / 3;
|
||||||
|
|
||||||
dev_type = efBuildAddStr(EFDevTypes, &EFDevNumTypes, TT_MAXTYPES, type);
|
dev_type = efBuildAddStr(EFDevTypes, &EFDevNumTypes, TT_MAXTYPES, type);
|
||||||
|
|
||||||
|
|
@ -1162,17 +1251,17 @@ efBuildDevice(
|
||||||
case DEV_ASYMMETRIC:
|
case DEV_ASYMMETRIC:
|
||||||
case DEV_BJT:
|
case DEV_BJT:
|
||||||
/* "None" in the place of the substrate name means substrate is ignored */
|
/* "None" in the place of the substrate name means substrate is ignored */
|
||||||
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0))
|
if ((termstart == 3) && (strncmp(argv[2], "None", 4) != 0))
|
||||||
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
|
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
|
||||||
break;
|
break;
|
||||||
case DEV_RES:
|
case DEV_RES:
|
||||||
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0))
|
if ((termstart == 3) && (strncmp(argv[2], "None", 4) != 0))
|
||||||
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
|
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case DEV_CAP:
|
case DEV_CAP:
|
||||||
case DEV_CAPREV:
|
case DEV_CAPREV:
|
||||||
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0))
|
if ((termstart == 3) && (strncmp(argv[2], "None", 4) != 0))
|
||||||
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
|
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -1182,7 +1271,7 @@ efBuildDevice(
|
||||||
#define TERM_PERIM 1
|
#define TERM_PERIM 1
|
||||||
#define TERM_ATTRS 2
|
#define TERM_ATTRS 2
|
||||||
|
|
||||||
for (av = &argv[argstart], n = 0; n < nterminals; n++, av += 3)
|
for (av = &argv[termstart], n = 0; n < nterminals; n++, av += 3)
|
||||||
{
|
{
|
||||||
term = &newdev->dev_terms[n];
|
term = &newdev->dev_terms[n];
|
||||||
term->dterm_node = efBuildDevNode(def, av[TERM_NAME], FALSE);
|
term->dterm_node = efBuildDevNode(def, av[TERM_NAME], FALSE);
|
||||||
|
|
@ -1546,7 +1635,25 @@ efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac)
|
||||||
unsigned size = sizeof (Connection)
|
unsigned size = sizeof (Connection)
|
||||||
+ (efNumResistClasses - 1) * sizeof (EFPerimArea);
|
+ (efNumResistClasses - 1) * sizeof (EFPerimArea);
|
||||||
|
|
||||||
if ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE)
|
/* If one of the nodes has been generated from the
|
||||||
|
* other by "extract unique", then this is a case where
|
||||||
|
* the "extract unique" algorithm is blind to shorts
|
||||||
|
* through subcell hierarchy and has made a name unique
|
||||||
|
* unnecessarily. In that case, merge the node instead
|
||||||
|
* of generating a short.
|
||||||
|
*/
|
||||||
|
char *uniqstr1, *uniqstr2;
|
||||||
|
bool isuniq;
|
||||||
|
|
||||||
|
uniqstr1 = strstr(nodeName1, "_uq");
|
||||||
|
uniqstr2 = strstr(nodeName2, "_uq");
|
||||||
|
if (uniqstr1) *uniqstr1 = '\0';
|
||||||
|
if (uniqstr2) *uniqstr2 = '\0';
|
||||||
|
isuniq = !strcmp(nodeName1, nodeName2);
|
||||||
|
if (uniqstr1) *uniqstr1 = '_';
|
||||||
|
if (uniqstr2) *uniqstr2 = '_';
|
||||||
|
|
||||||
|
if (!isuniq && ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE))
|
||||||
{
|
{
|
||||||
/* Handle the case where two ports on different nets get merged.
|
/* Handle the case where two ports on different nets get merged.
|
||||||
* If "extract short resistor" or "extract short voltage" has
|
* If "extract short resistor" or "extract short voltage" has
|
||||||
|
|
@ -1949,8 +2056,10 @@ efNodeMerge(node1ptr, node2ptr)
|
||||||
if (*node1ptr == *node2ptr)
|
if (*node1ptr == *node2ptr)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Keep the node with the greater number of entries, and merge */
|
/*
|
||||||
/* the node with fewer entries into it. */
|
* Keep the node with the greater number of entries, and merge
|
||||||
|
* the node with fewer entries into it.
|
||||||
|
*/
|
||||||
|
|
||||||
if ((*node1ptr)->efnode_num >= (*node2ptr)->efnode_num)
|
if ((*node1ptr)->efnode_num >= (*node2ptr)->efnode_num)
|
||||||
{
|
{
|
||||||
|
|
@ -1990,7 +2099,7 @@ efNodeMerge(node1ptr, node2ptr)
|
||||||
/* Make all EFNodeNames point to "keeping" */
|
/* Make all EFNodeNames point to "keeping" */
|
||||||
if (removing->efnode_name)
|
if (removing->efnode_name)
|
||||||
{
|
{
|
||||||
bool topportk, topportr;
|
bool topportk, topportr, bestname;
|
||||||
|
|
||||||
for (nn = removing->efnode_name; nn; nn = nn->efnn_next)
|
for (nn = removing->efnode_name; nn; nn = nn->efnn_next)
|
||||||
{
|
{
|
||||||
|
|
@ -2002,9 +2111,9 @@ efNodeMerge(node1ptr, node2ptr)
|
||||||
topportr = (removing->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
|
topportr = (removing->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
|
||||||
|
|
||||||
/* Concatenate list of EFNodeNames, taking into account precedence */
|
/* Concatenate list of EFNodeNames, taking into account precedence */
|
||||||
if ((!keeping->efnode_name) || (!topportk && (topportr
|
if ((!keeping->efnode_name) || (!topportk && topportr)
|
||||||
|| EFHNBest(removing->efnode_name->efnn_hier,
|
|| EFHNBest(removing->efnode_name->efnn_hier,
|
||||||
keeping->efnode_name->efnn_hier))))
|
keeping->efnode_name->efnn_hier))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* New official name is that of "removing".
|
* New official name is that of "removing".
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue