Finished first cut at an implementation of antenna rule violation
checks. Added new command "antennacheck" and a routine that adds feedback entries where violations are found. Extended the syntax of the extraction section of the techfile to support the antenna ratios and antenna calculation methods.
This commit is contained in:
parent
b8c34cb10b
commit
77e8ff437b
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ extern void ExtSetStyle();
|
|||
extern void ExtPrintStyle();
|
||||
extern void ExtCell();
|
||||
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
extern bool ExtGetDevInfo();
|
||||
extern bool ExtCompareStyle();
|
||||
|
|
|
|||
|
|
@ -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 ------------------------ */
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue