More corrections to extresist, which now appears to work if used

with ext2spice without the hierarchy option.  More work needed to
produce correct hierarchical output and to support extraction
devices other than the old "fet" record.
This commit is contained in:
Tim Edwards 2019-10-28 13:10:16 -04:00
parent 0e966af926
commit a4ea827d1e
9 changed files with 208 additions and 120 deletions

View File

@ -1771,7 +1771,8 @@ esHierVisit(hc, cdata)
if (def != topdef)
{
if ((def->def_devs == NULL) && (HashGetNumEntries(&def->def_uses) == 0))
if ((HashGetNumEntries(&def->def_devs) == 0) &&
(HashGetNumEntries(&def->def_uses) == 0))
{
if (locDoSubckt == AUTO)
{

View File

@ -591,23 +591,28 @@ efBuildDevice(def, class, type, r, argc, argv)
Rect *r; /* Coordinates of 1x1 rectangle entirely inside device */
int argc; /* Size of argv */
char *argv[]; /* Tokens for the rest of the dev line.
* The first depend on the type of device. The rest
* are taken in groups of 3, one for each terminal.
* Each group of 3 consists of the node name to which
* the terminal connects, the length of the terminal,
* and an attribute list (or the token 0).
* Starts with the last two position values, used to
* hash the device record. The next arguments depend
* on the type of device. The rest are taken in groups
* of 3, one for each terminal. Each group of 3 consists
* of the node name to which the terminal connects, the
* length of the terminal, and an attribute list (or the
* token 0).
*/
{
int n, nterminals, pn;
HashEntry *he;
DevTerm *term;
Dev *newdev, devtmp;
DevParam *newparm, *devp, *sparm;
char ptype, *pptr, **av;
char devhash[24];
int argstart = 1; /* start of terminal list in argv[] */
bool hasModel = strcmp(type, "None") ? TRUE : FALSE;
int area, perim; /* Total area, perimeter of primary type (i.e., channel) */
newdev = (Dev *)NULL;
devtmp.dev_subsnode = NULL;
devtmp.dev_cap = 0.0;
devtmp.dev_res = 0.0;
@ -713,7 +718,6 @@ efBuildDevice(def, class, type, r, argc, argv)
}
/* Check for optional substrate node */
switch (class)
{
case DEV_RES:
@ -743,93 +747,149 @@ efBuildDevice(def, class, type, r, argc, argv)
nterminals = (argc - argstart) / 3;
newdev = (Dev *) mallocMagic((unsigned) DevSize(nterminals));
newdev->dev_subsnode = devtmp.dev_subsnode;
newdev->dev_cap = devtmp.dev_cap;
newdev->dev_res = devtmp.dev_res;
newdev->dev_area = devtmp.dev_area;
newdev->dev_perim = devtmp.dev_perim;
newdev->dev_length = devtmp.dev_length;
newdev->dev_width = devtmp.dev_width;
newdev->dev_params = devtmp.dev_params;
/* Determine if this device has been seen before */
newdev->dev_nterm = nterminals;
newdev->dev_rect = *r;
newdev->dev_type = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, type);
newdev->dev_class = class;
sprintf(devhash, "%dx%d", r->r_xbot, r->r_ybot);
he = HashFind(&def->def_devs, devhash);
newdev = (Dev *)HashGetValue(he);
if (newdev)
{
/* Duplicate device. Duplicates will only appear in res.ext files
* where a device has nodes changed. Merge all properties of the
* original device with nodes from the new device. Keep the
* original device and discard the new one.
*
* Check that the device is actually the same device type and number
* of terminals. If not, throw an error and abandon the new device.
*/
if ((newdev->dev_class != class) ||
(strcmp(EFDevTypes[newdev->dev_type], type)))
{
TxError("Device %s %s at (%d, %d) overlaps incompatible device %s %s!\n",
extDevTable[class], type, r->r_xbot, r->r_ybot,
extDevTable[newdev->dev_class], EFDevTypes[newdev->dev_type]);
return 0;
}
else if (newdev->dev_nterm != nterminals)
{
TxError("Device %s %s at (%d, %d) overlaps device with incompatible"
" number of terminals (%d vs. %d)!\n",
extDevTable[class], type, r->r_xbot, r->r_ybot, nterminals,
newdev->dev_nterm);
return 0;
}
}
else
{
newdev = (Dev *) mallocMagic((unsigned) DevSize(nterminals));
/* Add this dev to the hash table for def */
HashSetValue(he, (ClientData)newdev);
newdev->dev_cap = devtmp.dev_cap;
newdev->dev_res = devtmp.dev_res;
newdev->dev_area = devtmp.dev_area;
newdev->dev_perim = devtmp.dev_perim;
newdev->dev_length = devtmp.dev_length;
newdev->dev_width = devtmp.dev_width;
newdev->dev_params = devtmp.dev_params;
newdev->dev_nterm = nterminals;
newdev->dev_rect = *r;
newdev->dev_type = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, type);
newdev->dev_class = class;
switch (class)
{
case DEV_FET: /* old-style "fet" record */
newdev->dev_area = atoi(argv[0]);
newdev->dev_perim = atoi(argv[1]);
break;
case DEV_MOSFET: /* new-style "device mosfet" record */
case DEV_ASYMMETRIC:
case DEV_BJT:
newdev->dev_length = atoi(argv[0]);
newdev->dev_width = atoi(argv[1]);
break;
case DEV_RES:
if (hasModel && StrIsInt(argv[0]) && StrIsInt(argv[1]))
{
newdev->dev_length = atoi(argv[0]);
newdev->dev_width = atoi(argv[1]);
}
else if (StrIsNumeric(argv[0]))
{
newdev->dev_res = (float)atof(argv[0]);
}
else
{
if (hasModel)
{
efReadError("Error: expected L and W, got %s %s\n", argv[0],
argv[1]);
newdev->dev_length = 0;
newdev->dev_width = 0;
}
else
{
efReadError("Error: expected resistance value, got %s\n",
argv[0]);
newdev->dev_res = 0.0;
}
}
break;
case DEV_CAP:
case DEV_CAPREV:
if (hasModel && StrIsInt(argv[0]) && StrIsInt(argv[1]))
{
newdev->dev_length = atoi(argv[0]);
newdev->dev_width = atoi(argv[1]);
}
else if (StrIsNumeric(argv[0]))
{
newdev->dev_cap = (float)atof(argv[0]);
}
else
{
if (hasModel)
{
efReadError("Error: expected L and W, got %s %s\n", argv[0],
argv[1]);
newdev->dev_length = 0;
newdev->dev_width = 0;
}
else
{
efReadError("Error: expected capacitance value, got %s\n",
argv[0]);
newdev->dev_cap = 0.0;
}
}
break;
}
}
newdev->dev_subsnode = devtmp.dev_subsnode;
switch (class)
{
case DEV_FET: /* old-style "fet" record */
newdev->dev_area = atoi(argv[0]);
newdev->dev_perim = atoi(argv[1]);
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
break;
case DEV_MOSFET: /* new-style "device mosfet" record */
case DEV_ASYMMETRIC:
case DEV_BJT:
newdev->dev_length = atoi(argv[0]);
newdev->dev_width = atoi(argv[1]);
/* "None" in the place of the substrate name means substrate is ignored */
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0))
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
break;
case DEV_RES:
if (hasModel && StrIsInt(argv[0]) && StrIsInt(argv[1]))
{
newdev->dev_length = atoi(argv[0]);
newdev->dev_width = atoi(argv[1]);
}
else if (StrIsNumeric(argv[0]))
{
newdev->dev_res = (float)atof(argv[0]);
}
else
{
if (hasModel)
{
efReadError("Error: expected L and W, got %s %s\n", argv[0],
argv[1]);
newdev->dev_length = 0;
newdev->dev_width = 0;
}
else
{
efReadError("Error: expected resistance value, got %s\n", argv[0]);
newdev->dev_res = 0.0;
}
}
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0))
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
break;
case DEV_CAP:
case DEV_CAPREV:
if (hasModel && StrIsInt(argv[0]) && StrIsInt(argv[1]))
{
newdev->dev_length = atoi(argv[0]);
newdev->dev_width = atoi(argv[1]);
}
else if (StrIsNumeric(argv[0]))
{
newdev->dev_cap = (float)atof(argv[0]);
}
else
{
if (hasModel)
{
efReadError("Error: expected L and W, got %s %s\n", argv[0],
argv[1]);
newdev->dev_length = 0;
newdev->dev_width = 0;
}
else
{
efReadError("Error: expected capacitance value, got %s\n", argv[0]);
newdev->dev_cap = 0.0;
}
}
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0))
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
@ -859,10 +919,6 @@ efBuildDevice(def, class, type, r, argc, argv)
#undef TERM_PERIM
#undef TERM_ATTRS
/* Add this dev to the list for def */
newdev->dev_next = def->def_devs;
def->def_devs = newdev;
return 0;
}
@ -1696,6 +1752,36 @@ efFreeUseTable(table)
}
}
/*
* ----------------------------------------------------------------------------
*
* efFreeDevTable --
*
* Free the device records allocated for each entry in the device hash table,
* the memory allocated by the device, leaving the hash entry null.
*
* ----------------------------------------------------------------------------
*/
void
efFreeDevTable(table)
HashTable *table;
{
Dev *dev;
HashSearch hs;
HashEntry *he;
int n;
HashStartSearch(&hs);
while (he = HashNext(table, &hs))
{
dev = (Dev *)HashGetValue(he);
for (n = 0; n < (int)dev->dev_nterm; n++)
if (dev->dev_terms[n].dterm_attrs)
freeMagic((char *) dev->dev_terms[n].dterm_attrs);
freeMagic((char *) dev);
}
}
/*
* ----------------------------------------------------------------------------

View File

@ -103,7 +103,6 @@ EFDone()
Kill *kill;
Def *def;
Use *use;
Dev *dev;
int n;
HashStartSearch(&hs);
@ -114,22 +113,18 @@ EFDone()
efFreeNodeTable(&def->def_nodes);
efFreeNodeList(&def->def_firstn);
efFreeUseTable(&def->def_uses);
efFreeDevTable(&def->def_devs);
HashKill(&def->def_nodes);
HashKill(&def->def_dists);
HashKill(&def->def_uses);
HashKill(&def->def_devs);
for (conn = def->def_conns; conn; conn = conn->conn_next)
efFreeConn(conn);
for (conn = def->def_caps; conn; conn = conn->conn_next)
efFreeConn(conn);
for (conn = def->def_resistors; conn; conn = conn->conn_next)
efFreeConn(conn);
for (dev = def->def_devs; dev; dev = dev->dev_next)
{
for (n = 0; n < (int)dev->dev_nterm; n++)
if (dev->dev_terms[n].dterm_attrs)
freeMagic((char *) dev->dev_terms[n].dterm_attrs);
freeMagic((char *) dev);
}
for (kill = def->def_kills; kill; kill = kill->kill_next)
{
freeMagic(kill->kill_name);
@ -151,13 +146,6 @@ EFDone()
EFTech = (char *)NULL;
}
/* Free up all HierNames that were stored in efFreeHashTable */
/*
HashStartSearch(&hs);
while (he = HashNext(&efFreeHashTable, &hs))
freeMagic(he->h_key.h_ptr);
*/
/* Free up the parameter name tables for each device */
HashStartSearch(&hs);
@ -244,7 +232,6 @@ efDefNew(name)
newdef->def_conns = (Connection *) NULL;
newdef->def_caps = (Connection *) NULL;
newdef->def_resistors = (Connection *) NULL;
newdef->def_devs = (Dev *) NULL;
newdef->def_kills = (Kill *) NULL;
/* Initialize circular list of nodes */
@ -257,6 +244,9 @@ efDefNew(name)
/* Initialize hash table of node names */
HashInit(&newdef->def_nodes, INITNODESIZE, HT_STRINGKEYS);
/* Initialize hash table of devices */
HashInit(&newdef->def_devs, INITNODESIZE, HT_STRINGKEYS);
/* Initialize hash table of distances */
HashInitClient(&newdef->def_dists, INITNODESIZE, HT_CLIENTKEYS,
efHNDistCompare, efHNDistCopy, efHNDistHash, efHNDistKill);

View File

@ -205,7 +205,7 @@ EFFlatBuildOneLevel(def, flags)
if (usecount > 0)
efHierSrUses(&efFlatContext, efFlatNodesDeviceless, (ClientData)&usecount);
if ((usecount == 0) && (efFlatRootUse.use_def->def_devs == NULL))
if ((usecount == 0) && (HashGetNumEntries(&efFlatRootUse.use_def->def_devs) == 0))
efFlatRootUse.use_def->def_flags |= DEF_NODEVICES;
/* Record all local nodes */
@ -372,7 +372,7 @@ efFlatNodesDeviceless(hc, cdata)
if (newcount > 0)
efHierSrUses(hc, efFlatNodesDeviceless, (ClientData)&newcount);
if ((hc->hc_use->use_def->def_devs == NULL) && (newcount == 0))
if ((HashGetNumEntries(&hc->hc_use->use_def->def_devs) == 0) && (newcount == 0))
{
/* Add all our own nodes to the table */
efAddNodes(hc, TRUE);

View File

@ -471,6 +471,8 @@ efHierVisitDevs(hc, ca)
{
Def *def = hc->hc_use->use_def;
Dev *dev;
HashSearch hs;
HashEntry *he;
float scale;
/*
@ -482,8 +484,10 @@ efHierVisitDevs(hc, ca)
scale = (efScaleChanged && def->def_scale != 1.0) ? def->def_scale : 1.0;
/* Visit all devices */
for (dev = def->def_devs; dev; dev = dev->dev_next)
HashStartSearch(&hs);
while (he = HashNext(&def->def_devs, &hs))
{
dev = (Dev *)HashGetValue(he);
if (efHierDevKilled(hc, dev, hc->hc_hierName))
continue;

View File

@ -156,6 +156,7 @@ typedef struct def
HashTable def_nodes; /* Map names into EFNodeNames */
HashTable def_dists; /* Map pairs of names into Distances */
HashTable def_uses; /* Hash children of this def by name */
HashTable def_devs; /* Devices (hash by position) */
EFNode def_firstn; /* Head of circular list of nodes */
/* The following are all NULL-terminated lists */
@ -163,7 +164,6 @@ typedef struct def
Connection *def_conns; /* Hierarchical connections/adjustments */
Connection *def_caps; /* Two-terminal capacitors */
Connection *def_resistors; /* Two-terminal resistors */
Dev *def_devs; /* Devices */
Kill *def_kills; /* Used to modify hierarchical structure
* using information present only in the
* parent, e.g, to kill an old node and

View File

@ -356,8 +356,7 @@ readfile:
r.r_xtop = atoi(argv[5]);
r.r_ytop = atoi(argv[6]);
if (efBuildDevice(def, (char)n, argv[2], &r, argc - 7,
&argv[7]) != 0)
if (efBuildDevice(def, (char)n, argv[2], &r, argc - 7, &argv[7]) != 0)
{
efReadError("Incomplete terminal description for device\n");
continue;

View File

@ -300,6 +300,8 @@ efVisitDevs(hc, ca)
Dev *dev;
float scale;
Transform t;
HashSearch hs;
HashEntry *he;
if (def->def_flags & DEF_SUBCIRCUIT) return 0;
@ -311,15 +313,17 @@ efVisitDevs(hc, ca)
t = hc->hc_trans;
/* Visit our own devices */
for (dev = def->def_devs; dev; dev = dev->dev_next)
HashStartSearch(&hs);
while (he = HashNext(&def->def_devs, &hs))
{
dev = (Dev *)HashGetValue(he);
if (efDevKilled(dev, hc->hc_hierName))
continue;
if ((*ca->ca_proc)(dev, hc->hc_hierName, scale, &t, ca->ca_cdata))
return 1;
}
return 0;
}

View File

@ -79,7 +79,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
ResSimNode *ResInitializeNode();
ResSimNode *ResOriginalNodes; /*Linked List of Nodes */
static float lambda=1.0; /* Scale factor */
static float resscale=1.0; /* Scale factor */
char RDEV_NOATTR[1]={'0'};
ResFixPoint *ResFixList;
@ -146,12 +146,8 @@ ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc)
case '|':
if (strcmp(line[NODEUNITS],"units:") == 0)
{
lambda = (float)atof(line[NODELAMBDA]);
if (lambda == 0.0) lambda = 1.0;
/* NOTE: units is derived from EFScale */
/* which needs a factor of 100 conversion */
/* to database units. */
lambda *= 100.0;
resscale = (float)atof(line[NODELAMBDA]);
if (resscale == 0.0) resscale = 1.0;
}
result=0;
break;
@ -231,6 +227,14 @@ ResReadNode(nodefile)
HashEntry *entry;
ResSimNode *node;
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.
*/
lambda = resscale * (float)ExtCurStyle->exts_unitsPerLambda;
fp = PaOpen(nodefile,"r",".nodes",".", (char *) NULL, (char **) NULL);
if (fp == NULL)
@ -243,17 +247,13 @@ ResReadNode(nodefile)
entry = HashFind(&ResNodeTable,line[NODENODENAME]);
node = ResInitializeNode(entry);
/* NOTE: Fixed 10/15/2019. No scalefactor is passed to EFNodeVisit()
* so there is no scaling by lambda. Values are in centimicrons always,
* and factor of 100 is required to get database units.
*/
node->location.p_x = (int)((float)atof(line[NODENODEX]) / 100.0);
node->location.p_y = (int)((float)atof(line[NODENODEY]) / 100.0);
node->location.p_x = (int)((float)atof(line[NODENODEX]) / lambda);
node->location.p_y = (int)((float)atof(line[NODENODEY]) / lambda);
#ifdef ARIEL
node->rs_bbox.r_xbot = (int)((float)atof(line[NODE_BBOX_LL_X]) / 100.0);
node->rs_bbox.r_ybot = (int)((float)atof(line[NODE_BBOX_LL_Y]) / 100.0);
node->rs_bbox.r_xtop = (int)((float)atof(line[NODE_BBOX_UR_X]) / 100.0);
node->rs_bbox.r_ytop = (int)((float)atof(line[NODE_BBOX_UR_Y]) / 100.0);
node->rs_bbox.r_xbot = (int)((float)atof(line[NODE_BBOX_LL_X]) / lambda);
node->rs_bbox.r_ybot = (int)((float)atof(line[NODE_BBOX_LL_Y]) / lambda);
node->rs_bbox.r_xtop = (int)((float)atof(line[NODE_BBOX_UR_X]) / lambda);
node->rs_bbox.r_ytop = (int)((float)atof(line[NODE_BBOX_UR_Y]) / lambda);
#endif
if (cp = strchr(line[NODETYPE], ';')) *cp = '\0';
node->type = DBTechNameType(line[NODETYPE]);
@ -340,6 +340,7 @@ ResSimDevice(line,rpersquare,ttype)
int rvalue,i,j,k;
char *newattr,tmpattr[MAXTOKEN];
static int nowarning = TRUE;
float lambda;
device = (RDev *) mallocMagic((unsigned) (sizeof(RDev)));
if ((line[RDEV_WIDTH][0] == '\0') || (line[RDEV_LENGTH][0] == '\0'))
@ -360,8 +361,11 @@ ResSimDevice(line,rpersquare,ttype)
device->tnumber = ++Maxtnumber;
device->status = FALSE;
device->nextDev = ResRDevList;
device->location.p_x = atoi(line[RDEV_DEVX]);
device->location.p_y = atoi(line[RDEV_DEVY]);
lambda = resscale * (float)ExtCurStyle->exts_unitsPerLambda;
device->location.p_x = (int)((float)atof(line[RDEV_DEVX]) / lambda);
device->location.p_y = (int)((float)atof(line[RDEV_DEVY]) / lambda);
device->rs_gattr=RDEV_NOATTR;
device->rs_sattr=RDEV_NOATTR;
device->rs_dattr=RDEV_NOATTR;