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;