From a4ea827d1e0a30f40fb1ddb49e8de2eeabfc7831 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 28 Oct 2019 13:10:16 -0400 Subject: [PATCH] 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. --- ext2spice/ext2hier.c | 3 +- extflat/EFbuild.c | 238 +++++++++++++++++++++++++++++-------------- extflat/EFdef.c | 22 ++-- extflat/EFflat.c | 4 +- extflat/EFhier.c | 6 +- extflat/EFint.h | 2 +- extflat/EFread.c | 3 +- extflat/EFvisit.c | 8 +- resis/ResReadSim.c | 42 ++++---- 9 files changed, 208 insertions(+), 120 deletions(-) diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index 7348a0d6..3f660975 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -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) { diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index dd2c700e..6999f1af 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -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); + } +} /* * ---------------------------------------------------------------------------- diff --git a/extflat/EFdef.c b/extflat/EFdef.c index 0ef549f1..e0b7c30d 100644 --- a/extflat/EFdef.c +++ b/extflat/EFdef.c @@ -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); diff --git a/extflat/EFflat.c b/extflat/EFflat.c index 337c477e..49087720 100644 --- a/extflat/EFflat.c +++ b/extflat/EFflat.c @@ -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); diff --git a/extflat/EFhier.c b/extflat/EFhier.c index 2b38443e..cef6bd52 100644 --- a/extflat/EFhier.c +++ b/extflat/EFhier.c @@ -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; diff --git a/extflat/EFint.h b/extflat/EFint.h index 9c380528..a9cbf2c2 100644 --- a/extflat/EFint.h +++ b/extflat/EFint.h @@ -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 diff --git a/extflat/EFread.c b/extflat/EFread.c index b57477fb..c5901293 100644 --- a/extflat/EFread.c +++ b/extflat/EFread.c @@ -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; diff --git a/extflat/EFvisit.c b/extflat/EFvisit.c index 8d802edd..35de6766 100644 --- a/extflat/EFvisit.c +++ b/extflat/EFvisit.c @@ -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; } diff --git a/resis/ResReadSim.c b/resis/ResReadSim.c index 6d9dad10..4a447aa8 100644 --- a/resis/ResReadSim.c +++ b/resis/ResReadSim.c @@ -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;