From 758b5a249a436ea4e2528574bb776d83262492e6 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 23 Jun 2016 22:27:34 -0400 Subject: [PATCH] Extended the prematching phase to include matching of devices based on properties that can be traded with number of devices, such as MOSFET width, by merging. This initial implementation is somewhat limited, only dealing with properties that merge by summing. Only devices that do not match at all in the other circuit will be considered for merging. The feature includes a command option "property ... merge ..." that allows control over which devices can and cannot be merged. --- base/flatten.c | 232 +++++++++++++++++++++++++++++++++++++++++++------ base/netcmp.c | 6 ++ base/netgen.c | 117 +++++++++++++++++-------- base/netgen.h | 4 +- base/objlist.c | 9 +- base/objlist.h | 2 +- base/spice.c | 26 +++--- 7 files changed, 314 insertions(+), 82 deletions(-) diff --git a/base/flatten.c b/base/flatten.c index 86b6bf1..c1d1132 100644 --- a/base/flatten.c +++ b/base/flatten.c @@ -24,6 +24,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include +#include #ifdef IBMPC #include @@ -39,6 +40,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "print.h" #include "netcmp.h" +extern struct hashdict spiceparams; + #define OLDPREFIX 1 void flattenCell(char *name, int file) @@ -95,7 +98,7 @@ void flattenCell(char *name, int file) if (ChildCell->dumped == 0) flattenCell(ParentParams->model.class, ChildCell->file); - ChildObjList = CopyObjList(ChildCell->cell); + ChildObjList = CopyObjList(ChildCell->cell, 1); /* update node numbers in child to unique numbers */ oldmax = 0; @@ -322,7 +325,7 @@ int flattenInstancesOf(char *name, int fnum, char *instance) /* if this is a new instance, flatten it */ /* if (ChildCell->dumped == 0) flattenCell(ParentParams->model.class, file); */ - ChildObjList = CopyObjList(ChildCell->cell); + ChildObjList = CopyObjList(ChildCell->cell, 1); numflat++; /* update node numbers in child to unique numbers */ @@ -466,28 +469,19 @@ int flattenInstancesOf(char *name, int fnum, char *instance) HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict)); } - /* do property inheritance */ + /* Do property inheritance */ + if (ParentProps) { for (ob2 = ChildObjList; ob2 != NULL; ob2=ob2->next) { /* If the parent cell has properties to declare, then */ - /* pass them on to children. */ + /* pass them on to children. Use globals only if the */ + /* spiceparams dictionary is active (during file reading */ + /* only). */ - if (ob2->type == PROPERTY) { - struct valuelist *vl; - int i; - for (i == 0;; i++) { - vl = &(ob2->instance.props[i]); - if (vl->type == PROP_ENDLIST) break; - else if (vl->type == PROP_EXPRESSION) { - /* Only expressions take substitutions */ - struct tokstack *token; - for (token = vl->value.stack; token; token = token->next) { - /* WIP */ - } - } - } - } + if (ob2->type == PROPERTY) + ReduceExpressions(ob2, ParentProps, ChildCell, + (spiceparams.hashtab == NULL) ? 0 : 1); } } @@ -508,7 +502,7 @@ int flattenInstancesOf(char *name, int fnum, char *instance) tmp = ParentParams; do { tmp = tmp->next; - } while ((tmp != NULL) && (tmp->type > FIRSTPIN)); + } while ((tmp != NULL) && ((tmp->type > FIRSTPIN) || (tmp->type == PROPERTY))); if (ob2) ob2->next = tmp; while (ParentParams != tmp) { ob2 = ParentParams->next; @@ -526,8 +520,8 @@ int flattenInstancesOf(char *name, int fnum, char *instance) void Flatten(char *name, int file) { - ClearDumpedList(); /* keep track of flattened cells */ - flattenCell(name, file); + ClearDumpedList(); /* keep track of flattened cells */ + flattenCell(name, file); } @@ -1304,6 +1298,88 @@ typedef struct ecomplist { ECompListPtr next; } ECompList; +/*------------------------------------------------------*/ +/* Split a device into multiple devices based on a */ +/* critical property; e.g., MOSFET width. Devices with */ +/* property name equal to kl->key and value "value" */ +/* will be split into "ndev" devices with the property */ +/* of each divided down by "ndev". */ +/*------------------------------------------------------*/ + +void +SplitDevice(struct nlist *tc, struct nlist *cell, struct property *kl, + double value, int ndev, int file1, int file2, int which) +{ + struct objlist *ob, *ob2, *newdevs, *ob3, *lastob, *nob; + struct nlist *tsub; + unsigned char found; + int file = (which == 0) ? file1 : file2; + + newdevs = NULL; /* Linked list of the copied devices */ + + for (ob = tc->cell; ob; ob = ob->next) { + if (ob->type == FIRSTPIN) { + tsub = LookupCellFile(ob->model.class, file); + if (tsub == cell) { + + // Advance ob to property list + found = 0; + for (ob2 = ob->next; ob2 && ob2->type != FIRSTPIN; ob2 = ob2->next) { + if (ob2->type == PROPERTY) { + struct valuelist *kv; + int i; + double dval = 0.0; + for (i = 0; ; i++) { + kv = &(ob2->instance.props[i]); + if (kv->type == PROP_ENDLIST) break; + if ((*matchfunc)(kv->key, kl->key)) { + switch(kv->type) { + case PROP_INTEGER: + dval = (double)kv->value.ival; + break; + case PROP_DOUBLE: + case PROP_VALUE: + dval = kv->value.dval; + break; + } + break; + } + } + + /* To-do: Account for slop */ + + if (dval == value) { + switch(kv->type) { + case PROP_INTEGER: + kv->value.ival /= ndev; + found = 1; + break; + case PROP_DOUBLE: + case PROP_VALUE: + kv->value.dval /= ndev; + found = 1; + break; + } + } + } + if (found) break; + } + if (found) { + int i; + for (i = 1; i < ndev; i++) { + ob3 = CopyObjList(ob, 0); // Make exact copy + for (nob = ob3; nob->next != NULL; nob = nob->next); + nob->next = newdevs; + newdevs = ob3; + } + } + } + } + lastob = ob; + } + lastob->next = newdevs; // Append new devices to list +} + /*------------------------------------------------------*/ /* Survey a specific device in a cell and sort into a */ /* hash by critical property. */ @@ -1353,6 +1429,8 @@ SurveyDevice(struct nlist *tc, struct hashdict *devdict, d2str += 2; // Advance ob to property list + // To-do: Quantize values according to slop + for (ob2 = ob->next; ob2 && ob2->type != FIRSTPIN; ob2 = ob2->next) { if (ob2->type == PROPERTY) { struct valuelist *kv; @@ -1811,6 +1889,9 @@ PrematchLists(char *name1, int file1, char *name2, int file2) // and merge devices where merging makes a better match. struct property *kl1, *kl2; + double slop = 0.0; + + // Look for a mergeable property in cell1 kl1 = (struct property *)HashFirst(&(ecomp->cell1->propdict)); while (kl1 != NULL) { @@ -1818,13 +1899,63 @@ PrematchLists(char *name1, int file1, char *name2, int file2) break; kl1 = (struct property *)HashNext(&(ecomp->cell1->propdict)); } + + // Look for the equivalent property in cell2 (mergeable or not). + // If cell1 had no mergeable properties, then look for one is cell2. + kl2 = (struct property *)HashFirst(&(ecomp->cell2->propdict)); while (kl2 != NULL) { - if (kl2->merge == MERGE_ADD_CRIT || kl2->merge == MERGE_PAR_CRIT) + if (kl1 != NULL) { + if ((*matchfunc)(kl1->key, kl2->key)) + break; + } + else if (kl2->merge == MERGE_ADD_CRIT || kl2->merge == MERGE_PAR_CRIT) break; - kl2 = (struct property *)HashNext(&(ecomp->cell1->propdict)); + kl2 = (struct property *)HashNext(&(ecomp->cell2->propdict)); } - if (kl1 != NULL || kl2 != NULL) { + if (kl2 != NULL) { + // Get slop value + switch (kl2->type) { + case PROP_INTEGER: + slop = (double)kl2->slop.ival; + break; + case PROP_DOUBLE: + case PROP_VALUE: + slop = kl2->slop.dval; + break; + } + } + + // If cell2 had a mergeable property but cell1 didn't, then look + // through cell1 again to find the equivalent property. + + if ((kl1 == NULL) && (kl2 != NULL)) { + kl1 = (struct property *)HashFirst(&(ecomp->cell1->propdict)); + while (kl1 != NULL) { + if ((*matchfunc)(kl1->key, kl2->key)) + break; + kl1 = (struct property *)HashNext(&(ecomp->cell1->propdict)); + } + } + if (kl1 != NULL) { + // Get slop value + switch (kl1->type) { + case PROP_INTEGER: + slop = MAX(slop, (double)kl1->slop.ival); + break; + case PROP_DOUBLE: + case PROP_VALUE: + slop = MAX(slop, kl1->slop.dval); + break; + } + } + + if ((kl1 != NULL) && (kl2 != NULL)) { + + double dval, dval1, dval2, mindev, pd, df, dr; + unsigned char dosplit; + char *valptr; + int ndev; // Create the device hash table @@ -1833,20 +1964,65 @@ PrematchLists(char *name1, int file1, char *name2, int file2) // Populate the device hash table SurveyDevice(tc1, &devdict, ecomp->cell1, kl1, file1, file2, 0); - SurveyDevice(tc2, &devdict, ecomp->cell2, kl2, file1, file2, 0); + SurveyDevice(tc2, &devdict, ecomp->cell2, kl2, file1, file2, 1); // Scan the device hash table. If devices can be merged // and this improves the matching between cells, then do // the merge. + mindev = 1E20; + dval1 = dval2 = 0.0; + dcomp = (ECompare *)HashFirst(&devdict); while (dcomp != NULL) { - if (dcomp->num1 != dcomp->num2) { - /* XXX WIP WIP WIP XXX */ + if ((dcomp->num1 == 0) || (dcomp->num2 == 0)) { + valptr = strstr(devdict.hashfirstptr->name, "::"); + if (sscanf(valptr + 2, "%lg", &dval) == 1) { + if (dval < mindev) mindev = dval; + if (dcomp->num1 == 0) + dval2 += (dval * dcomp->num2) / dcomp->refcount; + else + dval1 += (dval * dcomp->num1) / dcomp->refcount; + } } dcomp = (ECompare *)HashNext(&devdict); } + // If dval2 and dval1 agree within slop, and both are + // divisible by mindev, then break up all devices into + // sizes of mindev. + + dosplit = 0; + pd = 2 * fabs(dval1 - dval2) / (dval1 + dval2); + if (pd < slop) { + df = dval1 / mindev; + dr = round(df); + pd = 2 * fabs(df - dr) / (df + dr); + if (pd < slop) dosplit = 1; + } + + if (dosplit) { + dcomp = (ECompare *)HashFirst(&devdict); + while (dcomp != NULL) { + if (dcomp->num1 == 0 || dcomp->num2 == 0) { + valptr = strstr(devdict.hashfirstptr->name, "::"); + sscanf(valptr + 2, "%lg", &dval); + ndev = (int)round(dval / mindev); + } + if (dcomp->num1 == 0) { + SplitDevice(tc2, ecomp->cell2, kl2, dval, ndev, + file1, file2, 1); + modified++; + } + else if (dcomp->num2 == 0) { + SplitDevice(tc1, ecomp->cell1, kl1, dval, ndev, + file1, file2, 0); + modified++; + } + dcomp = (ECompare *)HashNext(&devdict); + } + } + // Free the device hash table dcomp = (ECompare *)HashFirst(&devdict); diff --git a/base/netcmp.c b/base/netcmp.c index 55abf65..b663553 100644 --- a/base/netcmp.c +++ b/base/netcmp.c @@ -4476,6 +4476,11 @@ int reorderpins(struct hashlist *p, int file) } ob = ob->next; ob2 = ob2->next; + if (ob == NULL) { + Fprintf(stderr, "Instance of %s has only %d of %d ports\n", + tc2->name, i + 1, numports); + break; + } } ob = firstpin; @@ -4491,6 +4496,7 @@ int reorderpins(struct hashlist *p, int file) HashPtrInstall(ob->name, ob, &(ptr->objdict)); ob = ob->next; names[i] = NULL; + if (ob == NULL) break; // Error message already output } } else diff --git a/base/netgen.c b/base/netgen.c index f9f0dc5..9d40349 100644 --- a/base/netgen.c +++ b/base/netgen.c @@ -168,12 +168,18 @@ struct tokstack *CopyTokStack(struct tokstack *stack) /* value was successfully converted, 0 if there was no value to */ /* convert (empty string), and -1 if unable to convert the */ /* string to a value (e.g., unknown parameter name). */ +/* */ +/* Inheritance is taken from "parprops" (instanced property */ +/* values) if available, and from parent->propdict if not, or */ +/* if the property is not instanced. */ /*--------------------------------------------------------------*/ -int TokGetValue(char *estr, struct nlist *parent, int glob, double *dval) +int TokGetValue(char *estr, struct nlist *parent, struct objlist *parprops, + int glob, double *dval) { struct property *kl = NULL; - int result; + struct valuelist *kv; + int i, result; if (*estr == '\0') return 0; @@ -195,22 +201,50 @@ int TokGetValue(char *estr, struct nlist *parent, int glob, double *dval) } } - /* Check local parameters */ - kl = (struct property *)HashLookup(estr, &(parent->propdict)); - if (kl != NULL) { - switch(kl->type) { - case PROP_STRING: - result = ConvertStringToFloat(kl->pdefault.string, dval); - break; - case PROP_DOUBLE: - case PROP_VALUE: - *dval = kl->pdefault.dval; - result = 1; - break; - case PROP_INTEGER: - *dval = (double)kl->pdefault.ival; - result = 1; + /* Check local instanced parameters */ + result = 0; + if ((parprops != NULL) && (parprops->type == PROPERTY)) { + for (i = 0; ; i++) { + kv = &(parprops->instance.props[i]); + if (kv->type == PROP_ENDLIST) break; + else if ((*matchfunc)(estr, kv->key)) { + switch (kv->type) { + case PROP_STRING: + result = ConvertStringToFloat(kv->value.string, dval); + break; + case PROP_DOUBLE: + case PROP_VALUE: + *dval = kv->value.dval; + result = 1; + break; + case PROP_INTEGER: + *dval = (double)kv->value.ival; + result = 1; + break; + } break; + } + } + } + + /* Check local parent parameters */ + if (result == 0) { + kl = (struct property *)HashLookup(estr, &(parent->propdict)); + if (kl != NULL) { + switch(kl->type) { + case PROP_STRING: + result = ConvertStringToFloat(kl->pdefault.string, dval); + break; + case PROP_DOUBLE: + case PROP_VALUE: + *dval = kl->pdefault.dval; + result = 1; + break; + case PROP_INTEGER: + *dval = (double)kl->pdefault.ival; + result = 1; + break; + } } } return ((result == 0) ? -1 : 1); @@ -228,14 +262,14 @@ int TokGetValue(char *estr, struct nlist *parent, int glob, double *dval) /* single value, then replace the property type. */ /*--------------------------------------------------------------*/ -int ReduceExpressions(struct objlist *instprop, +int ReduceExpressions(struct objlist *instprop, struct objlist *parprops, struct nlist *parent, int glob) { struct tokstack *expstack, *stackptr, *lptr, *nptr; struct valuelist *kv; struct property *kl = NULL; char *estr, *tstr, *sstr; - int toktype, functype, i, result, modified, numlast; + int toktype, functype, i, result, modified, numlast, savetok; double dval; if (instprop == NULL) return 0; // Nothing to do @@ -245,7 +279,9 @@ int ReduceExpressions(struct objlist *instprop, kv = &(instprop->instance.props[i]); - if (kv->type == PROP_EXPRESSION) { + if (kv->type == PROP_ENDLIST) + break; + else if (kv->type == PROP_EXPRESSION) { expstack = kv->value.stack; } else if (kv->type == PROP_STRING) { @@ -269,7 +305,7 @@ int ReduceExpressions(struct objlist *instprop, } /* Not a number, so must be arithmetic */ *tstr = '\0'; - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); else if (result == -1) PushTok(TOK_STRING, estr, &expstack); PushTok(TOK_PLUS, NULL, &expstack); @@ -289,7 +325,7 @@ int ReduceExpressions(struct objlist *instprop, } /* Not a number, so must be arithmetic */ *tstr = '\0'; - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); else if (result == -1) PushTok(TOK_STRING, estr, &expstack); PushTok(TOK_MINUS, NULL, &expstack); @@ -310,7 +346,7 @@ int ReduceExpressions(struct objlist *instprop, case '/': *tstr = '\0'; - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); else if (result == -1) PushTok(TOK_STRING, estr, &expstack); PushTok(TOK_DIVIDE, NULL, &expstack); @@ -320,7 +356,7 @@ int ReduceExpressions(struct objlist *instprop, case '*': *tstr = '\0'; - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); else if (result == -1) PushTok(TOK_STRING, estr, &expstack); PushTok(TOK_MULTIPLY, NULL, &expstack); @@ -339,7 +375,7 @@ int ReduceExpressions(struct objlist *instprop, else { /* Treat as a parenthetical grouping */ - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); else if (result == -1) PushTok(TOK_STRING, estr, &expstack); PushTok(TOK_FUNC_OPEN, NULL, &expstack); @@ -350,8 +386,15 @@ int ReduceExpressions(struct objlist *instprop, case ')': *tstr = '\0'; + if (expstack == NULL) break; - switch (expstack->toktype) { + savetok = expstack->toktype; + + result = TokGetValue(estr, parent, parprops, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + + switch (savetok) { case TOK_FUNC_THEN: PushTok(TOK_FUNC_ELSE, NULL, &expstack); break; @@ -365,7 +408,7 @@ int ReduceExpressions(struct objlist *instprop, case '\'': *tstr = '\0'; - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); else if (result == -1) PushTok(TOK_STRING, estr, &expstack); PushTok(TOK_SGL_QUOTE, NULL, &expstack); @@ -375,7 +418,7 @@ int ReduceExpressions(struct objlist *instprop, case '"': *tstr = '\0'; - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); else if (result == -1) PushTok(TOK_STRING, estr, &expstack); PushTok(TOK_DBL_QUOTE, NULL, &expstack); @@ -385,7 +428,7 @@ int ReduceExpressions(struct objlist *instprop, case '{': *tstr = '\0'; - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); else if (result == -1) PushTok(TOK_STRING, estr, &expstack); PushTok(TOK_GROUP_OPEN, NULL, &expstack); @@ -395,7 +438,7 @@ int ReduceExpressions(struct objlist *instprop, case '}': *tstr = '\0'; - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); PushTok(TOK_GROUP_CLOSE, NULL, &expstack); estr = tstr + 1; @@ -405,7 +448,7 @@ int ReduceExpressions(struct objlist *instprop, case '!': if (*(tstr + 1) == '=') { *tstr = '\0'; - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); else if (result == -1) PushTok(TOK_STRING, estr, &expstack); PushTok(TOK_NE, NULL, &expstack); @@ -416,7 +459,7 @@ int ReduceExpressions(struct objlist *instprop, case '=': if (*(tstr + 1) == '=') { *tstr = '\0'; - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); else if (result == -1) PushTok(TOK_STRING, estr, &expstack); PushTok(TOK_EQ, NULL, &expstack); @@ -426,7 +469,7 @@ int ReduceExpressions(struct objlist *instprop, case '>': *tstr = '\0'; - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); else if (result == -1) PushTok(TOK_STRING, estr, &expstack); @@ -442,7 +485,7 @@ int ReduceExpressions(struct objlist *instprop, case '<': *tstr = '\0'; - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); else if (result == -1) PushTok(TOK_STRING, estr, &expstack); @@ -458,7 +501,7 @@ int ReduceExpressions(struct objlist *instprop, case ',': *tstr = '\0'; - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); else if (result == -1) PushTok(TOK_STRING, estr, &expstack); if (expstack == NULL) break; @@ -483,7 +526,7 @@ int ReduceExpressions(struct objlist *instprop, } tstr++; } - result = TokGetValue(estr, parent, glob, &dval); + result = TokGetValue(estr, parent, parprops, glob, &dval); if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); else if (result == -1) PushTok(TOK_STRING, estr, &expstack); @@ -754,7 +797,7 @@ int ReduceExpressions(struct objlist *instprop, switch (stackptr->toktype) { case TOK_STRING: result = TokGetValue(stackptr->data.string, parent, - glob, &dval); + parprops, glob, &dval); if (result == 1) { stackptr->toktype = TOK_DOUBLE; FREE(stackptr->data.string); diff --git a/base/netgen.h b/base/netgen.h index 602ef62..c156053 100644 --- a/base/netgen.h +++ b/base/netgen.h @@ -43,8 +43,8 @@ extern void CopyProperties(struct objlist *obj_to, struct objlist *obj_from); extern int PromoteProperty(struct property *, struct valuelist *); extern int SetPropertyDefault(struct property *, struct valuelist *); extern struct objlist *LinkProperties(char *model, struct keyvalue *topptr); -extern int ReduceExpressions(struct objlist *instprop, struct nlist *parent, - int glob); +extern int ReduceExpressions(struct objlist *instprop, struct objlist *parprops, + struct nlist *parent, int glob); extern void Node(char *name); extern void Global(char *name); extern void UniqueGlobal(char *name); diff --git a/base/objlist.c b/base/objlist.c index 3f50548..804a963 100644 --- a/base/objlist.c +++ b/base/objlist.c @@ -843,7 +843,7 @@ int ListLength(char *list_template) -struct objlist *CopyObjList(struct objlist *oldlist) +struct objlist *CopyObjList(struct objlist *oldlist, unsigned char doforall) /* copies list pointed to by oldlist, creating a list whose head pointer is returned */ { @@ -880,6 +880,13 @@ struct objlist *CopyObjList(struct objlist *oldlist) tail->next = newob; tail = newob; tmp = tmp->next; + + // If "doforall" is 0, then only copy one object; otherwise, + // copy to the end of the list. + if (!doforall) { + if ((tmp == NULL) || ((tmp->type <= FIRSTPIN) && (tmp->type != PROPERTY))) + break; + } } return (head); } diff --git a/base/objlist.h b/base/objlist.h index 943408d..1794c7c 100644 --- a/base/objlist.h +++ b/base/objlist.h @@ -232,7 +232,7 @@ extern int ListLength(char *list_template); extern struct nlist *LookupPrematchedClass(struct nlist *, int); extern struct objlist *LookupObject(char *name, struct nlist *WhichCell); extern struct objlist *LookupInstance(char *name, struct nlist *WhichCell); -extern struct objlist *CopyObjList(struct objlist *oldlist); +extern struct objlist *CopyObjList(struct objlist *oldlist, unsigned char doforall); extern void UpdateNodeNumbers(struct objlist *lst, int from, int to); /* Function pointer to List or ListExact, allowing regular expressions */ diff --git a/base/spice.c b/base/spice.c index b3b863b..f41d369 100644 --- a/base/spice.c +++ b/base/spice.c @@ -860,7 +860,7 @@ skip_ends: if (multi) snprintf(instname, 255, "%s%s.%d", model, inst, ndev); Cell(instname, model, collector, base, emitter); pobj = LinkProperties(model, kvlist); - ReduceExpressions(pobj, CurrentCell, TRUE); + ReduceExpressions(pobj, NULL, CurrentCell, TRUE); ndev--; } DeleteProperties(&kvlist); @@ -927,8 +927,8 @@ skip_ends: Port("gate"); Port("source"); Port("bulk"); - PropertyDouble(model, filenum, "length", 0.01, 0.0); - PropertyDouble(model, filenum, "width", 0.01, 0.0); + PropertyDouble(model, filenum, "L", 0.01, 0.0); + PropertyDouble(model, filenum, "W", 0.01, 0.0); SetClass(CLASS_FET); EndCell(); ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */ @@ -946,7 +946,7 @@ skip_ends: if (multi) snprintf(instname, 255, "%s%s.%d", model, inst, ndev); Cell(instname, model, drain, gate, source, bulk); pobj = LinkProperties(model, kvlist); - ReduceExpressions(pobj, CurrentCell, TRUE); + ReduceExpressions(pobj, NULL, CurrentCell, TRUE); ndev--; } DeleteProperties(&kvlist); @@ -1049,7 +1049,7 @@ skip_ends: else Cap((*CellStackPtr)->cellname, instname, ctop, cbot); pobj = LinkProperties(model, kvlist); - ReduceExpressions(pobj, CurrentCell, TRUE); + ReduceExpressions(pobj, NULL, CurrentCell, TRUE); ndev--; } DeleteProperties(&kvlist); @@ -1151,7 +1151,7 @@ skip_ends: else Res((*CellStackPtr)->cellname, instname, rtop, rbot); pobj = LinkProperties(model, kvlist); - ReduceExpressions(pobj, CurrentCell, TRUE); + ReduceExpressions(pobj, NULL, CurrentCell, TRUE); ndev--; } DeleteProperties(&kvlist); @@ -1215,7 +1215,7 @@ skip_ends: if (multi) snprintf(instname, 255, "%s%s.%d", model, inst, ndev); Cell(instname, model, anode, cathode); pobj = LinkProperties(model, kvlist); - ReduceExpressions(pobj, CurrentCell, TRUE); + ReduceExpressions(pobj, NULL, CurrentCell, TRUE); ndev--; } DeleteProperties(&kvlist); @@ -1307,7 +1307,7 @@ skip_ends: XLine((*CellStackPtr)->cellname, instname, node1, node2, node3, node4); pobj = LinkProperties(model, kvlist); - ReduceExpressions(pobj, CurrentCell, TRUE); + ReduceExpressions(pobj, NULL, CurrentCell, TRUE); ndev--; } DeleteProperties(&kvlist); @@ -1397,7 +1397,7 @@ skip_ends: else Inductor((*CellStackPtr)->cellname, instname, end_a, end_b); pobj = LinkProperties(model, kvlist); - ReduceExpressions(pobj, CurrentCell, TRUE); + ReduceExpressions(pobj, NULL, CurrentCell, TRUE); ndev--; } DeleteProperties(&kvlist); @@ -1457,7 +1457,7 @@ skip_ends: } Cell(instname, model, pos, neg); pobj = LinkProperties(model, kvlist); - ReduceExpressions(pobj, CurrentCell, TRUE); + ReduceExpressions(pobj, NULL, CurrentCell, TRUE); DeleteProperties(&kvlist); } else if (toupper(nexttok[0]) == 'I') { /* current source */ @@ -1510,7 +1510,7 @@ skip_ends: } Cell(instname, model, pos, neg); pobj = LinkProperties(model, kvlist); - ReduceExpressions(pobj, CurrentCell, TRUE); + ReduceExpressions(pobj, NULL, CurrentCell, TRUE); DeleteProperties(&kvlist); } else if (toupper(nexttok[0]) == 'E') { /* controlled voltage source */ @@ -1574,7 +1574,7 @@ skip_ends: } Cell(instname, model, pos, neg, ctrlp, ctrln); pobj = LinkProperties(model, kvlist); - ReduceExpressions(pobj, CurrentCell, TRUE); + ReduceExpressions(pobj, NULL, CurrentCell, TRUE); DeleteProperties(&kvlist); } @@ -1720,7 +1720,7 @@ skip_ends: } Instance(subcktname, instancename); pobj = LinkProperties(subcktname, kvlist); - ReduceExpressions(pobj, CurrentCell, TRUE); + ReduceExpressions(pobj, NULL, CurrentCell, TRUE); ndev--; /* (Diagnostic) */