Merge branch 'master' into magic-8.2

This commit is contained in:
Tim Edwards 2019-10-21 03:00:04 -04:00
commit f65a442c45
5 changed files with 498 additions and 64 deletions

View File

@ -29,8 +29,8 @@ EFvisit.o: EFvisit.c ../utils/magic.h ../utils/geometry.h \
../utils/geofast.h ../utils/hash.h ../utils/malloc.h ../utils/utils.h \
../extflat/extflat.h ../extflat/EFint.h ../extract/extract.h
EFantenna.o: EFantenna.c ../tcltk/tclmagic.h ../utils/magic.h \
../utils/geometry.h ../utils/hash.h ../utils/utils.h ../tiles/tile.h \
../database/database.h ../windows/windows.h ../textio/textio.h \
../dbwind/dbwind.h ../textio/txcommands.h ../extflat/extflat.h \
../extract/extract.h ../extract/extractInt.h ../extract/extDebugInt.h \
../utils/malloc.h
../utils/geometry.h ../utils/hash.h ../utils/utils.h ../utils/styles.h \
../tiles/tile.h ../database/database.h ../windows/windows.h \
../textio/textio.h ../dbwind/dbwind.h ../textio/txcommands.h \
../extflat/extflat.h ../extract/extract.h ../extract/extractInt.h \
../extract/extDebugInt.h ../utils/malloc.h

View File

@ -14,18 +14,20 @@
#include <stdlib.h> /* for atof() */
#include <string.h>
#include <ctype.h>
#include <math.h> /* for INFINITY */
#include "tcltk/tclmagic.h"
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/hash.h"
#include "utils/utils.h"
#include "utils/styles.h"
#include "tiles/tile.h"
#ifdef MAGIC_WRAPPER
#include "database/database.h"
#include "windows/windows.h"
#include "textio/textio.h"
#include "dbwind/dbwind.h" /* for DBWclientID */
#include "dbwind/dbwind.h"
#include "textio/txcommands.h"
#endif
#include "extflat/extflat.h"
@ -70,6 +72,34 @@ typedef struct {
((nodeClientHier *) (node)->efnode_client)->visitMask = (long) 0; \
}
/* Diagnostic */
int efGates;
static int efAntennaDebug = FALSE;
/* The extract file is designed to be independent of the magic database, */
/* but that means that the device types do not match magic database types. */
/* A lookup table is needed to cross-reference the device types. */
TileType *EFDeviceTypes;
typedef struct _aas {
int *accum; /* Pointer to array of accumulated areas per type */
int pNum; /* Plane of check */
Rect r; /* Holds any one visited rectangle */
CellDef *def; /* CellDef for adding feedback */
} AntennaAccumStruct;
typedef struct _gdas {
int accum; /* Accumulated area of all gates/diff */
Rect r; /* Holds any one visited rectangle */
CellDef *def; /* CellDef for adding feedback */
} GateDiffAccumStruct;
typedef struct _ams {
int pNum; /* Plane of check */
CellDef *def; /* CellDef for adding feedback */
} AntennaMarkStruct;
/*
* ----------------------------------------------------------------------------
@ -80,16 +110,18 @@ typedef struct {
*/
#define ANTENNACHECK_RUN 0
#define ANTENNACHECK_HELP 1
#define ANTENNACHECK_DEBUG 1
#define ANTENNACHECK_HELP 2
void
CmdAntennaCheck(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
int i,flatFlags;
int i, flatFlags;
char *inName;
FILE *f;
TileType t;
int option = ANTENNACHECK_RUN;
int value;
@ -109,6 +141,7 @@ CmdAntennaCheck(w, cmd)
static char *cmdAntennaCheckOption[] = {
"[run] [options] run antennacheck on current cell\n"
" use \"run -help\" to get standard options",
"debug print detailed information about each error",
"help print help information",
NULL
};
@ -125,6 +158,9 @@ CmdAntennaCheck(w, cmd)
case ANTENNACHECK_RUN:
goto runantennacheck;
break;
case ANTENNACHECK_DEBUG:
efAntennaDebug = TRUE;
break;
case ANTENNACHECK_HELP:
usage:
for (msg = &(cmdAntennaCheckOption[0]); *msg != NULL; msg++)
@ -179,6 +215,7 @@ runantennacheck:
*/
/* Read the hierarchical description of the input circuit */
TxPrintf("Reading extract file.\n");
if (EFReadFile(inName, FALSE, FALSE, FALSE) == FALSE)
{
EFDone();
@ -187,13 +224,24 @@ runantennacheck:
/* Convert the hierarchical description to a flat one */
flatFlags = EF_FLATNODES;
TxPrintf("Building flattened netlist.\n");
EFFlatBuild(inName, flatFlags);
/* Build device lookup table */
EFDeviceTypes = (TileType *)mallocMagic(MAXDEVTYPES * sizeof(TileType));
for (i = 0; i < MAXDEVTYPES; i++)
if (EFDevTypes[i])
EFDeviceTypes[i] = extGetDevType(EFDevTypes[i]);
efGates = 0;
TxPrintf("Running antenna checks.\n");
EFVisitDevs(antennacheckVisit, (ClientData)editUse);
EFFlatDone();
EFDone();
TxPrintf("antennacheck finished.\n");
freeMagic(EFDeviceTypes);
efAntennaDebug = FALSE;
}
@ -296,28 +344,30 @@ antennacheckVisit(dev, hierName, scale, trans, editUse)
CellUse *editUse; /* ClientData is edit cell use */
{
DevTerm *gate;
TileType t, conType;
int pos, pNum, pNum2, pmax, p, i, j, gatearea, diffarea, total;
double difftotal;
double anttotal;
float saveRatio;
int *antennaarea;
Rect r;
Rect r, gaterect;
EFNode *gnode;
SearchContext scx;
TileTypeBitMask gatemask;
TileTypeBitMask gatemask, saveConMask;
bool antennaError;
extern CellDef *extPathDef; /* see extract/ExtLength.c */
extern CellUse *extPathUse; /* see extract/ExtLength.c */
extern int areaAccumFunc(), antennaAccumFunc();
extern int areaAccumFunc(), antennaAccumFunc(), areaMarkFunc();
antennaarea = (int *)mallocMagic(DBNumTypes * sizeof(int));
for (i = 0; i < DBNumTypes; i++) antennaarea[i] = 0;
switch(dev->dev_class)
{
case DEV_FET:
case DEV_MOSFET:
GeoTransRect(trans, &dev->dev_rect, &r);
case DEV_MSUBCKT:
case DEV_ASYMMETRIC:
/* Procedure:
*
@ -336,16 +386,23 @@ antennacheckVisit(dev, hierName, scale, trans, editUse)
* layer being searched.
*/
GeoTransRect(trans, &dev->dev_rect, &r);
gate = &dev->dev_terms[0];
gnode = AntennaGetNode(hierName, gate->dterm_node->efnode_name->efnn_hier);
if (gnode->efnode_client == (ClientData) NULL)
initNodeClient(gnode);
if (beenVisited((nodeClient *)gnode->efnode_client, 0))
return 0;
else
markVisited((nodeClient *)gnode->efnode_client, 0);
/* Diagnostic stuff */
efGates++;
if (efGates % 100 == 0) TxPrintf(" %d gates analyzed.\n", efGates);
/* Find the plane of the gate type */
pNum = DBPlane(dev->dev_type);
t = EFDeviceTypes[dev->dev_type];
pNum = DBPlane(t);
pos = ExtCurStyle->exts_planeOrder[pNum];
pmax = ++pos;
@ -354,10 +411,15 @@ antennacheckVisit(dev, hierName, scale, trans, editUse)
if (ExtCurStyle->exts_planeOrder[p] > pmax)
pmax = ExtCurStyle->exts_planeOrder[p];
/* Create the yank cell if it doesn't already exist */
if (extPathDef == (CellDef *) NULL)
DBNewYank("__PATHYANK__", &extPathUse, &extPathDef);
/* Use the cellDef reserved for extraction */
DBCellClearDef(extPathDef);
/* DBCellClearDef(extPathDef); */ /* See below */
scx.scx_use = editUse;
scx.scx_trans = GeoIdentityTransform;
scx.scx_area = r;
/* gatemask is a mask of all gate types for MOSFET devices */
@ -387,53 +449,203 @@ antennacheckVisit(dev, hierName, scale, trans, editUse)
for (; pos <= pmax; pos++)
{
GateDiffAccumStruct gdas;
AntennaAccumStruct aas;
AntennaMarkStruct ams;
/* Find the plane of pos */
for (p = 0; p < DBNumPlanes; p++)
if (ExtCurStyle->exts_planeOrder[p] == pos)
pNum2 = p;
/* Find the tiletype which is a contact and whose base is pNum2 */
/* (NOTE: Need to extend to all such contacts, as there may be */
/* more than one.) (Also should find these types up top, not */
/* within the loop.) */
/* Modify DBConnectTbl to limit connectivity to the plane */
/* of the antenna check and below */
/* To be completed */
conType = -1;
for (i = 0; i < DBNumTypes; i++)
if (DBIsContact(i) && DBPlane(i) == pNum2)
{
conType = i;
TTMaskZero(&saveConMask);
TTMaskSetMask(&saveConMask, &DBConnectTbl[i]);
TTMaskZero(&DBConnectTbl[i]);
for (j = 0; j < DBNumTypes; j++)
if (TTMaskHasType(&saveConMask, j) &&
(DBPlane(j) <= pNum2))
TTMaskSetType(&DBConnectTbl[i], j);
break;
}
DBTreeCopyConnect(&scx, &DBConnectTbl[dev->dev_type], 0,
for (i = 0; i < DBNumTypes; i++) antennaarea[i] = 0;
gatearea = 0;
diffarea = 0;
/* Note: Ideally, the addition of material in the next */
/* metal plane is additive. But that requires enumerating */
/* all the vias and using those as starting points for the */
/* next connectivity search, which needs to be coded. */
DBCellClearDef(extPathDef);
/* To do: Mark tiles so area count can be progressive */
DBTreeCopyConnect(&scx, &DBConnectTbl[t], 0,
DBConnectTbl, &TiPlaneRect, extPathUse);
/* Search plane of gate type and accumulate all (new) gate area */
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[pNum],
&TiPlaneRect, &gatemask, areaAccumFunc, (ClientData)&gatearea);
/* Search planes of tie type and accumulate all (new) tiedown areas */
/* Search planes of tie types and accumulate all tiedown areas */
gdas.accum = 0;
for (p = 0; p < DBNumPlanes; p++)
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p],
&TiPlaneRect, &ExtCurStyle->exts_antennaTieTypes,
areaAccumFunc, (ClientData)&diffarea);
areaAccumFunc, (ClientData)&gdas);
diffarea = gdas.accum;
/* Search metal planes and accumulate all (new) antenna areas */
/* Search plane of gate type and accumulate all gate area */
gdas.accum = 0;
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[pNum],
&TiPlaneRect, &gatemask, areaAccumFunc, (ClientData)&gdas);
gatearea = gdas.accum;
/* Search metal planes and accumulate all antenna areas */
for (p = 0; p < DBNumPlanes; p++)
{
if (ExtCurStyle->exts_planeOrder[p] == pos)
{
pNum2 = p;
}
if (ExtCurStyle->exts_antennaModel & ANTENNAMODEL_PARTIAL)
if (p != pNum2) continue;
aas.pNum = p;
aas.accum = &antennaarea[0];
if (ExtCurStyle->exts_planeOrder[p] <= pos)
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p],
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
antennaAccumFunc, (ClientData)&antennaarea);
antennaAccumFunc, (ClientData)&aas);
}
/* To be elaborated. . . this encodes only one of several */
/* methods of calculating antenna violations. */
antennaError = FALSE;
if (diffarea == 0)
{
difftotal = 0.0;
anttotal = 0.0;
saveRatio = 0.0;
for (i = 0; i < DBNumTypes; i++)
difftotal += antennaarea[i] / ExtCurStyle->exts_antennaRatio[i];
{
if (ExtCurStyle->exts_antennaRatio[i].ratioGate > 0)
{
anttotal += (double)antennaarea[i] /
(double)ExtCurStyle->exts_antennaRatio[i].ratioGate;
}
if (ExtCurStyle->exts_antennaRatio[i].ratioGate > saveRatio)
saveRatio = ExtCurStyle->exts_antennaRatio[i].ratioGate;
}
if (difftotal > gatearea)
TxError("Antenna violation detected at plane %s "
"(violation to be elaborated)",
DBPlaneLongNameTbl[pNum2]);
if (anttotal > (double)gatearea)
{
antennaError = TRUE;
if (efAntennaDebug == TRUE)
{
TxError("Antenna violation detected at plane %s\n",
DBPlaneLongNameTbl[pNum2]);
TxError("Effective antenna ratio %g > limit %g\n",
saveRatio * (float)anttotal / (float)gatearea,
saveRatio);
TxError("Gate rect (%d %d) to (%d %d)\n",
gdas.r.r_xbot, gdas.r.r_ybot,
gdas.r.r_xtop, gdas.r.r_ytop);
TxError("Antenna rect (%d %d) to (%d %d)\n",
aas.r.r_xbot, aas.r.r_ybot,
aas.r.r_xtop, aas.r.r_ytop);
}
}
}
else
{
anttotal = 0.0;
saveRatio = 0.0;
for (i = 0; i < DBNumTypes; i++)
if (ExtCurStyle->exts_antennaRatio[i].ratioDiff != INFINITY)
{
if (ExtCurStyle->exts_antennaRatio[i].ratioDiff > 0)
anttotal += (double)antennaarea[i] /
(double)ExtCurStyle->exts_antennaRatio[i].ratioDiff;
if (ExtCurStyle->exts_antennaRatio[i].ratioDiff > saveRatio)
saveRatio = ExtCurStyle->exts_antennaRatio[i].ratioDiff;
}
if (anttotal > (double)gatearea)
{
antennaError = TRUE;
if (efAntennaDebug == TRUE)
{
TxError("Antenna violation detected at plane %s\n",
DBPlaneLongNameTbl[pNum2]);
TxError("Effective antenna ratio %g > limit %g\n",
saveRatio * (float)anttotal / (float)gatearea,
saveRatio);
TxError("Gate rect (%d %d) to (%d %d)\n",
gdas.r.r_xbot, gdas.r.r_ybot,
gdas.r.r_xtop, gdas.r.r_ytop);
TxError("Antenna rect (%d %d) to (%d %d)\n",
aas.r.r_xbot, aas.r.r_ybot,
aas.r.r_xtop, aas.r.r_ytop);
}
}
}
if (antennaError)
{
/* Search plane of gate type and mark all gate areas */
ams.def = editUse->cu_def;
ams.pNum = pNum2;
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[pNum],
&TiPlaneRect, &gatemask, areaMarkFunc, (ClientData)&ams);
/* Search metal planes and accumulate all antenna areas */
for (p = 0; p < DBNumPlanes; p++)
{
if (ExtCurStyle->exts_antennaModel & ANTENNAMODEL_PARTIAL)
if (p != pNum2) continue;
if (ExtCurStyle->exts_planeOrder[p] <= pos)
DBSrPaintArea((Tile *)NULL, extPathUse->cu_def->cd_planes[p],
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
areaMarkFunc, (ClientData)&ams);
}
}
/* Put the connect table back the way it was */
if (conType >= 0)
TTMaskSetMask(&DBConnectTbl[conType], &saveConMask);
}
}
freeMagic(antennaarea);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* areaMarkFunc --
*
* Mark the tile areas searched with feedback entries
*
* ----------------------------------------------------------------------------
*/
int
areaMarkFunc(tile, ams)
Tile *tile;
AntennaMarkStruct *ams;
{
Rect rect;
char msg[200];
TiToRect(tile, &rect);
sprintf(msg, "Antenna error at plane %s\n", DBPlaneLongNameTbl[ams->pNum]);
DBWFeedbackAdd(&rect, msg, ams->def, 1, STYLE_PALEHIGHLIGHTS);
return 0;
}
@ -448,19 +660,16 @@ antennacheckVisit(dev, hierName, scale, trans, editUse)
*/
int
areaAccumFunc(tile, totalarea)
areaAccumFunc(tile, gdas)
Tile *tile;
int *totalarea;
GateDiffAccumStruct *gdas;
{
Rect rect;
int area;
TiToRect(tile, &rect);
area += (rect.r_xtop - rect.r_xbot) * (rect.r_ytop - rect.r_ybot);
*totalarea += area;
Rect *rect = &(gdas->r);
int area, type;
TiToRect(tile, rect);
area = (rect->r_xtop - rect->r_xbot) * (rect->r_ytop - rect->r_ybot);
gdas->accum += area;
return 0;
}
@ -470,27 +679,164 @@ areaAccumFunc(tile, totalarea)
* antennaAccumFunc --
*
* Accumulate the total tile area searched, keeping an individual
* count for each tile type.
* count for each tile type. If the antenna model is SIDEWALL, then
* calculate the area of the tile sidewall (tile perimeter * layer
* thickness), rather than the drawn tile area.
*
* ----------------------------------------------------------------------------
*/
int
antennaAccumFunc(tile, typeareas)
antennaAccumFunc(tile, aaptr)
Tile *tile;
int **typeareas;
AntennaAccumStruct *aaptr;
{
Rect rect;
Rect *rect = &(aaptr->r);
int area;
int type;
int *typeareas = aaptr->accum;
int plane = aaptr->pNum;
float thick;
type = TiGetType(tile);
TiToRect(tile, &rect);
TiToRect(tile, rect);
area += (rect.r_xtop - rect.r_xbot) * (rect.r_ytop - rect.r_ybot);
if (ExtCurStyle->exts_antennaModel & ANTENNAMODEL_SIDEWALL)
{
/* Accumulate perimeter of tile where tile abuts space */
*typeareas[type] += area;
Tile *tp;
int perimeter = 0, pmax, pmin;
/* Top */
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
{
if (TiGetBottomType(tp) == TT_SPACE)
{
pmin = MAX(LEFT(tile), LEFT(tp));
pmax = MIN(RIGHT(tile), RIGHT(tp));
perimeter += (pmax - pmin);
}
}
/* Bottom */
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
{
if (TiGetTopType(tp) == TT_SPACE)
{
pmin = MAX(LEFT(tile), LEFT(tp));
pmax = MIN(RIGHT(tile), RIGHT(tp));
perimeter += (pmax - pmin);
}
}
/* Left */
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
{
if (TiGetRightType(tp) == TT_SPACE)
{
pmin = MAX(BOTTOM(tile), BOTTOM(tp));
pmax = MIN(TOP(tile), TOP(tp));
perimeter += (pmax - pmin);
}
}
/* Right */
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
{
if (TiGetLeftType(tp) == TT_SPACE)
{
pmin = MAX(BOTTOM(tile), BOTTOM(tp));
pmax = MIN(TOP(tile), TOP(tp));
perimeter += (pmax - pmin);
}
}
if (DBIsContact(type))
{
int cperim;
TileType ttype;
TileTypeBitMask sMask;
float thick;
cperim = ((rect->r_xtop - rect->r_xbot) + (rect->r_ytop - rect->r_ybot)) << 1;
/* For contacts, add the area of the perimeter to the */
/* residue (metal) type on the plane being searched. */
/* Then, if the plane is the same as the base type of */
/* the contact, add the entire perimeter area of the */
/* tile to the total for the contact type itself. */
DBFullResidueMask(type, &sMask);
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
if (TTMaskHasType(&sMask, ttype))
if (DBTypeOnPlane(ttype, plane))
{
thick = ExtCurStyle->exts_thick[ttype];
typeareas[ttype] += (int)((float)perimeter * thick);
}
if (type >= DBNumUserLayers)
{
DBResidueMask(type, &sMask);
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
if (TTMaskHasType(&sMask, ttype))
if (DBTypeOnPlane(ttype, plane))
{
thick = ExtCurStyle->exts_thick[ttype];
typeareas[ttype] += (int)((float)perimeter * thick);
break;
}
}
else
{
thick = ExtCurStyle->exts_thick[type];
typeareas[type] += (int)((float)perimeter * thick);
}
}
else
{
/* Area is perimeter times layer thickness */
thick = ExtCurStyle->exts_thick[type];
typeareas[type] += (int)((float)perimeter * thick);
}
}
else
{
/* Simple tile area calculation */
area = (rect->r_xtop - rect->r_xbot) * (rect->r_ytop - rect->r_ybot);
/* If type is a contact, then add area to both residues as well */
/* as the contact type. */
/* NOTE: Restrict area counts per plane so areas of contacts */
/* are not double-counted. */
if (DBIsContact(type))
{
TileType ttype;
TileTypeBitMask sMask;
DBFullResidueMask(type, &sMask);
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
if (TTMaskHasType(&sMask, ttype))
if (DBTypeOnPlane(ttype, plane))
typeareas[ttype] += area;
if (type >= DBNumUserLayers)
{
DBResidueMask(type, &sMask);
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
if (TTMaskHasType(&sMask, ttype))
if (DBTypeOnPlane(ttype, plane))
{
typeareas[ttype] += area;
break;
}
}
else
typeareas[type] += area;
}
else
typeareas[type] += area;
}
return 0;
}

View File

@ -71,7 +71,7 @@ typedef enum
AREAC, CONTACT, CSCALE,
DEFAULTAREACAP, DEFAULTOVERLAP, DEFAULTPERIMETER, DEFAULTSIDEOVERLAP,
DEFAULTSIDEWALL,
DEVICE, FET, FETRESIST, HEIGHT, ANTENNA, TIEDOWN, LAMBDA, OVERC,
DEVICE, FET, FETRESIST, HEIGHT, ANTENNA, MODEL, TIEDOWN, LAMBDA, OVERC,
PERIMC, PLANEORDER, NOPLANEORDER, RESIST, RSCALE, SIDEHALO, SIDEOVERLAP,
SIDEWALL, STEP, STYLE, SUBSTRATE, UNITS, VARIANT
} Key;
@ -122,9 +122,12 @@ static keydesc keyTable[] = {
"height", HEIGHT, 4, 4,
"type height-above-subtrate thickness",
"antenna", ANTENNA, 3, 3,
"antenna", ANTENNA, 4, 4,
"type antenna-ratio",
"model", MODEL, 3, 3,
"partial-cumulative area-sidewall",
"tiedown", TIEDOWN, 2, 2,
"types",
@ -376,6 +379,35 @@ ExtGetDevInfo(idx, devnameptr, sd_rclassptr, sub_rclassptr, subnameptr)
#endif /* MAGIC_WRAPPER */
/*
* ----------------------------------------------------------------------------
*
* extGetDevType --
*
* Given an extraction model device name (devname), return the associated
* magic tiletype for the device.
*
* Results:
* Tile type that represents the device "devname" in the magic database.
*
* ----------------------------------------------------------------------------
*/
TileType
extGetDevType(devname)
char *devname;
{
TileType t;
ExtDevice *devptr;
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
for (devptr = ExtCurStyle->exts_device[t]; devptr; devptr = devptr->exts_next)
if (!strcmp(devptr->exts_deviceName, devname))
return t;
return -1;
}
#ifdef THREE_D
/*
@ -672,7 +704,8 @@ extTechStyleInit(style)
for (r = 0; r < DBNumTypes; r++)
{
style->exts_antennaRatio[r] = 0;
style->exts_antennaRatio[r].ratioGate = 0.0;
style->exts_antennaRatio[r].ratioDiff = 0.0;
style->exts_resistByResistClass[r] = 0;
TTMaskZero(&style->exts_typesByResistClass[r]);
style->exts_typesResistChanged[r] = DBAllButSpaceAndDRCBits;
@ -2321,17 +2354,53 @@ ExtTechLine(sectionName, argc, argv)
if (!StrIsNumeric(argv[2]))
{
TechError("Layer antenna ratio %s must be numeric\n", argv[2]);
TechError("Gate layer antenna ratio %s must be numeric\n", argv[2]);
break;
}
antennaratio = (float)strtod(argv[2], NULL);
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
if (TTMaskHasType(&types1, t))
{
ExtCurStyle->exts_antennaRatio[t] = antennaratio;
ExtCurStyle->exts_antennaRatio[t].ratioGate = antennaratio;
}
if (!StrIsNumeric(argv[3]))
{
if (!strcasecmp(argv[3], "none"))
antennaratio = INFINITY;
else
{
TechError("Diff layer antenna ratio %s must be numeric\n", argv[3]);
break;
}
}
else
antennaratio = (float)strtod(argv[3], NULL);
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
if (TTMaskHasType(&types1, t))
{
ExtCurStyle->exts_antennaRatio[t].ratioDiff = antennaratio;
}
}
break;
case MODEL:
if (!strcmp(argv[1], "partial"))
ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_PARTIAL;
else if (!strcmp(argv[1], "cumulative"))
ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_CUMULATIVE;
else
TxError("Unknown antenna model \"%s\": Use \"partial\" or "
"\"cumulative\"");
if (!strcmp(argv[2], "area"))
ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_AREA;
else if (!strcmp(argv[2], "sidewall"))
ExtCurStyle->exts_antennaModel |= ANTENNAMODEL_SIDEWALL;
else
TxError("Unknown antenna model \"%s\": Use \"area\" or "
"\"sidewall\"");
break;
case TIEDOWN:
TTMaskSetMask(&ExtCurStyle->exts_antennaTieTypes, &types1);
break;
@ -2973,6 +3042,10 @@ zinit:
ec = ec->ec_next)
ec->ec_cap *= 0.5;
}
/* Layer thickness and height are in microns, but are floating-point */
style->exts_thick[r] /= dscale;
style->exts_height[r] /= dscale;
}
/* side halo and step size are also in microns */

View File

@ -76,6 +76,7 @@ extern void ExtSetStyle();
extern void ExtPrintStyle();
extern void ExtCell();
#ifdef MAGIC_WRAPPER
extern bool ExtGetDevInfo();
extern bool ExtCompareStyle();

View File

@ -48,6 +48,17 @@ typedef int ResValue; /* Warning: in some places resistances are stored
* as ints. This is here for documentation only.
*/
typedef struct {
float ratioGate;
float ratioDiff;
} RatioValues;
/* Antenna models */
#define ANTENNAMODEL_PARTIAL 0x01
#define ANTENNAMODEL_CUMULATIVE 0x02
#define ANTENNAMODEL_AREA 0x04
#define ANTENNAMODEL_SIDEWALL 0x08
/* ------------------------ Parameter lists --------------------------- */
/* These lists keep track of what parameter names subcircuit definitions
@ -656,8 +667,10 @@ typedef struct extstyle
float exts_height[NT];
float exts_thick[NT];
char exts_antennaModel;
/* Antenna area ratio for each layer */
float exts_antennaRatio[NT];
RatioValues exts_antennaRatio[NT];
/* Mask of types that tie down antennas */
TileTypeBitMask exts_antennaTieTypes;
@ -1060,6 +1073,7 @@ extern NodeRegion *extBasic();
extern NodeRegion *extFindNodes();
extern ExtTree *extHierNewOne();
extern int extNbrPushFunc();
extern TileType extGetDevType();
/* --------------------- Miscellaneous globals ------------------------ */