Overhauled the extresist code (again), this time to (1) correct for

a long-standing error (introduced with the "extresist geometry"
option) that can cause nets not to be extracted (due to the first
record not having extraction data, which was itself a long-standing
error in the code but which was not fixed correctly);  (2) handle
"device mosfet" type transistors (previously only handled the old
"fet" type extraction devices);  and (3) correct for the res.ext
file having a different scalefactor relative to the .ext file.  The
latter item was solved by forcing all input to scale like
ExtCurStyle->exts_unitsPerLambda, locally correcting all input as
needed.  Note that extresist still needs to handle other extraction
devices (e.g., resistors and capacitors) but those will require
additional handling in the routines which analyze the current path
to determine how to break up wires into paths.
This commit is contained in:
Tim Edwards 2019-12-08 17:37:48 -05:00
parent 31612b593f
commit fd737dbf80
11 changed files with 4226 additions and 103 deletions

View File

@ -122,55 +122,161 @@ cifPaintFunc(tile, table)
* Always returns 0 to keep the search alive.
*
* Side effects:
* Scales the tile by cifScale, then expands its area by the
* remainder of the distance to meet the minimum dimension, as
* defined by the grid distance (growDistance) in the current
* CIFOp, then paints this area into cifNewPlane using the table
* passed as parameter.
* May paint into cifNewPlane
*
* Algorithm (based on maximum horizontal stripes rule):
* Scan top and bottom boundaries from left to right. For any
* distance (including distance zero) sharing the same type (0 or 1)
* on both the tile top and bottom, find the diagonal length. If
* less than co_distance, then expand this area and paint.
* NOTE: This algorithm does not cover a number of geometry cases
* and needs to be reworked. It should be restricted to cases of
* layers that have "rect_only" DRC rules. Since the rule is usually
* needed for implants on FET gates to maintain the implant width for
* small gates, the "rect_only" requirement is not particularly
* constraining.
*
* ----------------------------------------------------------------------------
*/
int
cifGrowMinFunc(tile, plane)
cifGrowMinFunc(tile, table)
Tile *tile;
Plane *plane;
PaintResultType *table; /* Table to be used for painting. */
{
Rect area, *maxr;
int locDist, width, height;
TileTypeBitMask mask;
TileType type;
Rect area, parea;
int locDist, width, height, h;
TileType type, tptype;
Tile *tp, *tp2;
TiToRect(tile, &area);
type = TiGetType(tile);
TTMaskZero(&mask);
TTMaskSetType(&mask, type);
area.r_xbot *= cifScale;
area.r_xtop *= cifScale;
area.r_ybot *= cifScale;
area.r_ytop *= cifScale;
maxr = FindMaxRectangle2(&area, tile, plane, &mask);
if (maxr == NULL) return 0; /* Should not happen */
parea = area;
maxr->r_xbot *= cifScale;
maxr->r_xtop *= cifScale;
maxr->r_ybot *= cifScale;
maxr->r_ytop *= cifScale;
width = maxr->r_xtop - maxr->r_xbot;
height = maxr->r_ytop - maxr->r_ybot;
locDist = (growDistance - width) / 2;
if (locDist > 0)
/* Check whole tile for minimum width */
width = area.r_xtop - area.r_xbot;
if (width < growDistance)
{
maxr->r_xbot -= locDist;
maxr->r_xtop += locDist;
}
locDist = (growDistance - width) / 2;
area.r_xbot -= locDist;
area.r_xtop += locDist;
locDist = (growDistance - height) / 2;
if (locDist > 0)
/* If there is another tile on top or bottom, and the height is */
/* less than minimum, then extend height in the direction of */
/* the bordering tile. Otherwise, if the height is less than */
/* minimum, then grow halfway in both directions. */
height = area.r_ytop - area.r_ybot;
if (height < growDistance)
{
bool freeTop, freeBot;
freeTop = freeBot = TRUE;
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
if (TiGetTopType(tp) == TiGetBottomType(tile))
{
freeBot = FALSE;
break;
}
for (tp2 = RT(tile); RIGHT(tp2) > LEFT(tile); tp2 = BL(tp2))
if (TiGetBottomType(tp2) == TiGetTopType(tile))
{
freeTop = FALSE;
break;
}
/* In the following, value h ensures that the euclidean */
/* distance between inside corners of the layer */
/* satisfies growDistance. */
if (freeTop == TRUE && freeBot == FALSE)
{
locDist = (growDistance - height) / 2;
h = (int)sqrt((double)(growDistance * growDistance) -
0.25 * (double)((growDistance + width) *
(growDistance + width)) + 0.5);
area.r_ybot -= h;
}
else if (freeTop == FALSE && freeBot == TRUE)
{
h = (int)sqrt((double)(growDistance * growDistance) -
0.25 * (double)((growDistance + width) *
(growDistance + width)) + 0.5);
area.r_ytop += h;
}
else {
locDist = (growDistance - height) / 2;
area.r_ybot -= locDist;
area.r_ytop += locDist;
}
}
}
DBPaintPlane(cifPlane, &area, table, (PaintUndoInfo *) NULL);
area = parea;
/* Scan bottom from left to right */
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
{
maxr->r_ybot -= locDist;
maxr->r_ytop += locDist;
}
tptype = TiGetTopType(tp);
/* Scan top from right to left across range of tp */
for (tp2 = RT(tile); RIGHT(tp2) > LEFT(tile); tp2 = BL(tp2))
if (TiGetBottomType(tp2) == tptype)
{
/* Set range to length of overlap */
if ((LEFT(tp2) <= RIGHT(tp)) && (LEFT(tp2) >= LEFT(tp)))
{
area.r_xbot = LEFT(tp2) < LEFT(tile) ? LEFT(tile) : LEFT(tp2);
area.r_xtop = RIGHT(tp) > RIGHT(tile) ? RIGHT(tile) : RIGHT(tp);
}
else if ((RIGHT(tp2) >= LEFT(tp)) && (RIGHT(tp2) <= RIGHT(tp)))
{
area.r_xbot = LEFT(tp) < LEFT(tile) ? LEFT(tile) : LEFT(tp);
area.r_xtop = RIGHT(tp2) > RIGHT(tile) ? RIGHT(tile) : RIGHT(tp2);
}
else continue;
DBPaintPlane(cifPlane, maxr, CIFPaintTable, (PaintUndoInfo *) NULL);
area.r_xbot *= cifScale;
area.r_xtop *= cifScale;
/* Does area violate minimum width requirement? */
width = area.r_xtop - area.r_xbot;
height = area.r_ytop - area.r_ybot;
/* Manhattan requirement (to-do: Euclidean) */
if (width < growDistance)
{
locDist = (growDistance - width) / 2;
parea.r_xbot = area.r_xbot - locDist;
parea.r_xtop = area.r_xtop + locDist;
}
else
{
parea.r_xbot = area.r_xbot;
parea.r_xtop = area.r_xtop;
}
if (height < growDistance)
{
locDist = (growDistance - height) / 2;
parea.r_ybot = area.r_ybot - locDist;
parea.r_ytop = area.r_ytop + locDist;
}
else
{
parea.r_ybot = area.r_ybot;
parea.r_ytop = area.r_ytop;
}
if ((width < growDistance) || (height < growDistance))
DBPaintPlane(cifPlane, &parea, table, (PaintUndoInfo *) NULL);
}
}
CIFTileOps += 1;
return 0;
@ -3199,7 +3305,7 @@ CIFGenLayer(op, area, cellDef, temps, clientdata)
cifPlane = nextPlane;
cifScale = 1;
(void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
&CIFSolidBits, cifGrowMinFunc, (ClientData)curPlane);
&CIFSolidBits, cifGrowMinFunc, (ClientData)CIFPaintTable);
temp = curPlane;
curPlane = nextPlane;
nextPlane = temp;

3980
cif/CIFgen.c.test Normal file

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,7 @@ EFread.o: EFread.c ../tcltk/tclmagic.h ../utils/magic.h ../utils/malloc.h \
../utils/geometry.h ../utils/hash.h ../utils/utils.h ../tiles/tile.h \
../commands/commands.h ../windows/windows.h ../database/database.h \
../extflat/extflat.h ../extflat/EFint.h ../extract/extract.h \
../utils/paths.h
../extract/extractInt.h ../extract/extDebugInt.h ../utils/paths.h
EFsym.o: EFsym.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

View File

@ -63,6 +63,8 @@ void efNodeMerge();
bool efConnBuildName();
bool efConnInitSubs();
extern float locScale;
/*
* ----------------------------------------------------------------------------
@ -177,10 +179,10 @@ efBuildNode(def, isSubsnode, nodeName, nodeCap, x, y, layerName, av, ac)
newnode->efnode_flags = (isSubsnode == TRUE) ? EF_SUBS_NODE : 0;
newnode->efnode_cap = nodeCap;
newnode->efnode_attrs = (EFAttr *) NULL;
newnode->efnode_loc.r_xbot = x;
newnode->efnode_loc.r_ybot = y;
newnode->efnode_loc.r_xtop = x + 1;
newnode->efnode_loc.r_ytop = y + 1;
newnode->efnode_loc.r_xbot = (int)(0.5 + (float)x * locScale);
newnode->efnode_loc.r_ybot = (int)(0.5 + (float)y * locScale);
newnode->efnode_loc.r_xtop = newnode->efnode_loc.r_xbot + 1;
newnode->efnode_loc.r_ytop = newnode->efnode_loc.r_ybot + 1;
newnode->efnode_client = (ClientData) NULL;
if (layerName) newnode->efnode_type =
efBuildAddStr(EFLayerNames, &EFLayerNumNames, MAXTYPES, layerName);
@ -686,7 +688,8 @@ efBuildDevice(def, class, type, r, argc, argv)
{
pn = *(argv[argstart] + 1) - '0';
if (pn == 0)
devtmp.dev_area = atoi(pptr);
devtmp.dev_area = (int)(0.5 + (float)atoi(pptr)
* locScale * locScale);
/* Otherwise, punt */
}
break;
@ -697,15 +700,15 @@ efBuildDevice(def, class, type, r, argc, argv)
{
pn = *(argv[argstart] + 1) - '0';
if (pn == 0)
devtmp.dev_perim = atoi(pptr);
devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale);
/* Otherwise, use verbatim */
}
break;
case 'l':
devtmp.dev_length = atoi(pptr);
devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale);
break;
case 'w':
devtmp.dev_width = atoi(pptr);
devtmp.dev_width = (int)(0.5 + (float)atoi(pptr) * locScale);
break;
case 'c':
devtmp.dev_cap = (float)atof(pptr);
@ -1248,8 +1251,9 @@ efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac)
conn->conn_next = def->def_conns;
for (n = 0; n < efNumResistClasses && ac > 1; n++, ac -= 2)
{
conn->conn_pa[n].pa_area = atoi(*av++);
conn->conn_pa[n].pa_perim = atoi(*av++);
conn->conn_pa[n].pa_area = (int)(0.5 + (float)atoi(*av++)
* locScale * locScale);
conn->conn_pa[n].pa_perim = (int)(0.5 + (float)atoi(*av++) * locScale);
}
for ( ; n < efNumResistClasses; n++)
conn->conn_pa[n].pa_area = conn->conn_pa[n].pa_perim = 0;

View File

@ -38,6 +38,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "extflat/extflat.h"
#include "extflat/EFint.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
#include "utils/paths.h"
#ifndef MAGIC_WRAPPER
@ -96,6 +97,7 @@ keyTable[] =
/* Data shared with EFerror.c */
char *efReadFileName; /* Name of file currently being read */
int efReadLineNum; /* Current line number in above file */
float locScale; /* Multiply values in the file by this on read-in */
/* Data local to this file */
static bool efReadDef();
@ -139,6 +141,7 @@ EFReadFile(name, dosubckt, resist, noscale)
if (def == NULL)
def = efDefNew(name);
locScale = 1.0;
rc = efReadDef(def, dosubckt, resist, noscale, TRUE);
if (EFArgTech) EFTech = StrDup((char **) NULL, EFArgTech);
if (EFScale == 0.0) EFScale = 1.0;
@ -265,6 +268,11 @@ readfile:
cscale = 1;
}
lscale = (float)atof(argv[3]);
if (lscale != ExtCurStyle->exts_unitsPerLambda)
{
locScale = lscale / ExtCurStyle->exts_unitsPerLambda;
lscale = ExtCurStyle->exts_unitsPerLambda;
}
if (lscale == 0.0)
{
efReadError("Bad linear scaling = 0; reset to 1.\n");
@ -283,10 +291,10 @@ readfile:
/* attr node xlo ylo xhi yhi type text */
case ATTR:
r.r_xbot = atoi(argv[2]);
r.r_ybot = atoi(argv[3]);
r.r_xtop = atoi(argv[4]);
r.r_ytop = atoi(argv[5]),
r.r_xbot = (int)(0.5 + (float)atoi(argv[2]) * locScale);
r.r_ybot = (int)(0.5 + (float)atoi(argv[3]) * locScale);
r.r_xtop = (int)(0.5 + (float)atoi(argv[4]) * locScale);
r.r_ytop = (int)(0.5 + (float)atoi(argv[5]) * locScale),
efBuildAttr(def, argv[1], &r, argv[6], argv[7]);
break;
@ -351,10 +359,10 @@ readfile:
break; /* we will deal with in efBuildDevice(). */
}
r.r_xbot = atoi(argv[3]);
r.r_ybot = atoi(argv[4]);
r.r_xtop = atoi(argv[5]);
r.r_ytop = atoi(argv[6]);
r.r_xbot = (int)(0.5 + (float)atoi(argv[3]) * locScale);
r.r_ybot = (int)(0.5 + (float)atoi(argv[4]) * locScale);
r.r_xtop = (int)(0.5 + (float)atoi(argv[5]) * locScale);
r.r_ytop = (int)(0.5 + (float)atoi(argv[6]) * locScale);
if (efBuildDevice(def, (char)n, argv[2], &r, argc - 7, &argv[7]) != 0)
{
@ -366,10 +374,10 @@ readfile:
/* for backwards compatibility */
/* fet type xlo ylo xhi yhi area perim substrate GATE T1 T2 ... */
case FET:
r.r_xbot = atoi(argv[2]);
r.r_ybot = atoi(argv[3]);
r.r_xtop = atoi(argv[4]);
r.r_ytop = atoi(argv[5]);
r.r_xbot = (int)(0.5 + (float)atoi(argv[2]) * locScale);
r.r_ybot = (int)(0.5 + (float)atoi(argv[3]) * locScale);
r.r_xtop = (int)(0.5 + (float)atoi(argv[4]) * locScale);
r.r_ytop = (int)(0.5 + (float)atoi(argv[5]) * locScale);
if (efBuildDevice(def, DEV_FET, argv[1], &r, argc - 6, &argv[6]) != 0)
{
efReadError("Incomplete terminal description for fet\n");
@ -563,8 +571,8 @@ resistChanged:
/* distance driver receiver min max */
case DIST:
efBuildDist(def, argv[1], argv[2],
(int)(lscale*atoi(argv[3])),
(int)(lscale*atoi(argv[4])));
(int)(lscale*atoi(argv[3])*locScale),
(int)(lscale*atoi(argv[4])*locScale));
break;
/* killnode nodename */

View File

@ -130,7 +130,6 @@ ResProcessJunction(tile, tp, xj, yj, NodeList)
return;
}
#endif
if (j2->tj_status & RES_TILE_DONE) return;
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
resptr->rn_te = (tElement *) NULL;

View File

@ -135,20 +135,40 @@ ResPrintExtDev(outextfile, devices)
if (varsub != NULL) subsName = varsub;
}
#endif
/* Output according to device type and class. */
/* Code largely matches what's in ExtBasic.c extOutputDevices() */
/* Output according to device type */
if (devptr->exts_deviceClass != DEV_FET)
fprintf(outextfile,"device ");
/* fet type xl yl xh yh area perim sub gate t1 t2 */
fprintf(outextfile,"fet %s %d %d %d %d %d %d "
"%s \"%s\" %d %s \"%s\" %d %s \"%s\" %d %s\n",
fprintf(outextfile,"%s %s %d %d %d %d ",
extDevTable[devptr->exts_deviceClass],
devptr->exts_deviceName,
devices->layout->rd_inside.r_ll.p_x,
devices->layout->rd_inside.r_ll.p_y,
devices->layout->rd_inside.r_ll.p_x + 1,
devices->layout->rd_inside.r_ll.p_y + 1,
devices->layout->rd_area,
devices->layout->rd_perim,
subsName,
devices->layout->rd_inside.r_ll.p_y + 1);
switch (devptr->exts_deviceClass)
{
case DEV_FET:
fprintf(outextfile," %d %d",
devices->layout->rd_area,
devices->layout->rd_perim);
break;
case DEV_MOSFET:
case DEV_ASYMMETRIC:
case DEV_BJT:
fprintf(outextfile," %d %d",
devices->layout->rd_length,
devices->layout->rd_width);
break;
}
fprintf(outextfile, " \"%s\"", subsName);
fprintf(outextfile, " \"%s\" %d %s \"%s\" %d %s \"%s\" %d %s\n",
devices->gate->name,
devices->layout->rd_length * 2,
devices->rs_gattr,
@ -190,7 +210,7 @@ ResPrintExtNode(outextfile, nodelist, nodename)
ResSimNode *node,*ResInitializeNode();
bool DoKillNode = TRUE;
resNode *snode = nodelist;
/* If any of the subnode names match the original node name, then */
/* we don't want to rip out that node with a "killnode" statement. */

View File

@ -229,12 +229,12 @@ ResReadNode(nodefile)
char *cp;
float lambda;
/* NOTE: Units from the .sim file or the .nodes file are in centimicrons
* when multiplied by resscale (units from the .sim file 1st line).
* multiply resscale by the extract scale (exts_unitsPerLambda) used to
* generate .ext dimensions originally, to get back to database units.
/* NOTE: Units from the .nodes file are in centimicrons.
* Divide by the extract scale (exts_unitsPerLambda) to get back
* to database units. This assumes that exts_unitsPerLambda doesn't
* change between output and readback.
*/
lambda = resscale * (float)ExtCurStyle->exts_unitsPerLambda;
lambda = (float)ExtCurStyle->exts_unitsPerLambda;
fp = PaOpen(nodefile,"r",".nodes",".", (char *) NULL, (char **) NULL);
if (fp == NULL)
@ -358,11 +358,10 @@ ResSimDevice(line,rpersquare,ttype)
}
device->resistance = MagAtof(line[RDEV_LENGTH]) * rpersquare/MagAtof(line[RDEV_WIDTH]);
}
device->tnumber = ++Maxtnumber;
device->status = FALSE;
device->nextDev = ResRDevList;
lambda = resscale * (float)ExtCurStyle->exts_unitsPerLambda;
lambda = (float)ExtCurStyle->exts_unitsPerLambda / resscale;
device->location.p_x = (int)((float)atof(line[RDEV_DEVX]) / lambda);
device->location.p_y = (int)((float)atof(line[RDEV_DEVY]) / lambda);

View File

@ -35,21 +35,19 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#define INITFLATSIZE 1024
#define MAXNAME 1000
/* time constants are produced by multiplying attofarads by milliohms, */
/* Time constants are produced by multiplying attofarads by milliohms, */
/* giving zeptoseconds (yes, really. Look it up). This constant */
/* converts zeptoseconts to nanoseconds. */
/* converts zeptoseconds to nanoseconds. */
#define Z_TO_N 1e12
/* ResSimNode is a node read in from a sim file */
HashTable ResNodeTable; /* Hash table of sim file nodes */
RDev *ResRDevList; /* Linked list of Sim devices */
ResGlobalParams gparams; /* Junk passed between */
/* ResCheckSimNodes and */
/* ResExtractNet. */
int Maxtnumber; /*maximum device number */
extern ResSimNode *ResOriginalNodes; /*Linked List of Nodes */
int resNodeNum;
@ -104,7 +102,6 @@ ExtResisForDef(celldef, resisdata)
ResRDevList = NULL;
ResOriginalNodes = NULL;
Maxtnumber = 0;
HashInit(&ResNodeTable, INITFLATSIZE, HT_STRINGKEYS);
/* read in .sim file */
result = (ResReadSim(celldef->cd_name,
@ -870,6 +867,19 @@ ResCheckSimNodes(celldef, resisdata)
return;
}
/*
* Write a scale line at the top of the .res.ext file, as the
* scale may be different from the original .ext file.
*/
if (ResExtFile != NULL)
{
fprintf(ResExtFile, "scale %d %d %g\n",
ExtCurStyle->exts_resistScale,
ExtCurStyle->exts_capScale,
ExtCurStyle->exts_unitsPerLambda);
}
/*
* Write reference plane (substrate) definition and end statement
* to the FastHenry geometry file.

View File

@ -954,26 +954,25 @@ ResDoSimplify(tolerance,rctol,goodies)
{
RCDelayStuff *rc = (RCDelayStuff *) ResNodeList->rn_client;
if (rc != (RCDelayStuff *)NULL)
{
goodies->rg_nodecap = totalcap;
ResCalculateTDi(ResOriginNode,(resResistor *)NULL,
goodies->rg_nodecap = totalcap;
ResCalculateTDi(ResOriginNode,(resResistor *)NULL,
goodies->rg_bigdevres);
goodies->rg_Tdi = rc->rc_Tdi;
slownode = ResNodeList;
for (node = ResNodeList; node != NULL; node = node->rn_more)
{
rc = (RCDelayStuff *)node->rn_client;
if (rc && (goodies->rg_Tdi < rc->rc_Tdi))
{
slownode = node;
goodies->rg_Tdi = rc->rc_Tdi;
}
}
slownode->rn_status |= RN_MAXTDI;
}
if (rc != (RCDelayStuff *)NULL)
goodies->rg_Tdi = rc->rc_Tdi;
else
goodies->rg_Tdi = 0;
goodies->rg_Tdi = 0;
slownode = ResNodeList;
for (node = ResNodeList; node != NULL; node = node->rn_more)
{
rc = (RCDelayStuff *)node->rn_client;
if (rc && (goodies->rg_Tdi < rc->rc_Tdi))
{
slownode = node;
goodies->rg_Tdi = rc->rc_Tdi;
}
}
slownode->rn_status |= RN_MAXTDI;
}
else
{

View File

@ -296,7 +296,6 @@ typedef struct rdev
Point location; /* Location of lower left point of */
/* device. */
float resistance; /* "Resistance" of device. */
int tnumber; /* Device number */
int rs_ttype; /* device type */
char *rs_gattr; /* Gate attributes, if any */
char *rs_sattr;
@ -572,7 +571,6 @@ extern RDev *ResRDevList;
extern REcell *ResBigEventList;
extern int ResOptionsFlags;
extern char *ResCurrentNode;
extern int Maxtnumber;
extern ResSimNode *ResOriginalNodes;
#ifdef ARIEL
extern int ResMinEventTime;