diff --git a/base/flatten.c b/base/flatten.c index 3a61b72..14b3b25 100644 --- a/base/flatten.c +++ b/base/flatten.c @@ -249,6 +249,7 @@ void flattenCell(char *name, int file) int flattenInstancesOf(char *name, int fnum, char *instance) { struct objlist *ParentParams; + struct objlist *ParentProps; struct objlist *NextObj; struct objlist *ChildObjList; struct nlist *ThisCell; @@ -308,6 +309,14 @@ int flattenInstancesOf(char *name, int fnum, char *instance) if (ChildCell->class != CLASS_SUBCKT) continue; if (ChildCell == ThisCell) continue; // Avoid infinite loop + /* Does the parent cell have properties? If so, save a pointer to them */ + for (ParentProps = ParentParams->next; ParentProps && + ParentProps->type != FIRSTPIN; + ParentProps = ParentProps->next) { + if (ParentProps->type == PROPERTY) break; + } + if (ParentProps && (ParentProps->type != PROPERTY)) ParentProps = NULL; + /* not primitive, so need to flatten this instance */ notdone = 1; /* if this is a new instance, flatten it */ @@ -406,7 +415,9 @@ int flattenInstancesOf(char *name, int fnum, char *instance) prefixlength = strlen(tmpstr); #endif for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next) { - if (tmp->type == PROPERTY) continue; + if (tmp->type == PROPERTY) + continue; + else if (IsGlobal(tmp)) { /* Keep the name but search for node of same name in parent */ /* and replace the node number, if found. */ @@ -455,6 +466,31 @@ int flattenInstancesOf(char *name, int fnum, char *instance) HashPtrInstall(tmp->instance.name, tmp, ThisCell->insttab, OBJHASHSIZE); } + /* 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. */ + + 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 */ + } + } + } + } + } + } + /* splice instance out of parent */ if (ParentParams == ThisCell->cell) { /* ParentParams are the very first thing in the list */ @@ -468,6 +504,7 @@ int flattenInstancesOf(char *name, int fnum, char *instance) for (ob2->next = ChildObjList; ob2->next != NULL; ob2 = ob2->next) ; } /* now, ob2 is last element in child list, so skip and reclaim parent */ + tmp = ParentParams; do { tmp = tmp->next; diff --git a/base/netcmp.c b/base/netcmp.c index 12b02fd..0dc987c 100644 --- a/base/netcmp.c +++ b/base/netcmp.c @@ -3327,8 +3327,8 @@ int PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print) } } if (vl2->type != PROP_ENDLIST) { - if (do_print) Fprintf(stdout, "Circuit 2 %s instance %s does not" - " define required properties.\n", + if (do_print) Fprintf(stdout, "Circuit 2 %s instance %s missing" + " required properties.\n", Circuit2->name, ob2->instance.name); return -1; } @@ -3352,8 +3352,8 @@ int PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print) } } if (vl1->type != PROP_ENDLIST) { - if (do_print) Fprintf(stdout, "Circuit 1 %s instance %s does not" - " define required properties.\n", + if (do_print) Fprintf(stdout, "Circuit 1 %s instance %s missing" + " required properties.\n", Circuit1->name, ob1->instance.name); return -1; } @@ -3389,6 +3389,14 @@ int PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print) kl2 = (struct property *)HashLookup(vl2->key, tc2->proptab, OBJHASHSIZE); if (kl2 == NULL) continue; + /* Watch out for uninitialized entries in cell def */ + if (vl1->type == vl2->type) { + if (kl1->type == PROP_STRING && kl1->pdefault.string == NULL) + SetPropertyDefault(kl1, vl1); + if (kl2->type == PROP_STRING && kl2->pdefault.string == NULL) + SetPropertyDefault(kl2, vl2); + } + if (vl1->type != vl2->type) { if (kl1->type != vl1->type) PromoteProperty(kl1, vl1); if (kl2->type != vl2->type) PromoteProperty(kl2, vl2); diff --git a/base/netgen.c b/base/netgen.c index 9558019..0eef7e3 100644 --- a/base/netgen.c +++ b/base/netgen.c @@ -193,28 +193,27 @@ int TokGetValue(char *estr, struct nlist *parent, int glob, double *dval) spiceparams, OBJHASHSIZE); if (kl != NULL) { result = ConvertStringToFloat(kl->pdefault.string, dval); + return ((result == 0) ? -1 : 1); } } } - else { - /* Check local parameters */ - kl = (struct property *)HashLookup(estr, - parent->proptab, OBJHASHSIZE); - 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; - } + + /* Check local parameters */ + kl = (struct property *)HashLookup(estr, parent->proptab, OBJHASHSIZE); + 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); @@ -1924,10 +1923,6 @@ void DeleteProperties(struct keyvalue **topptr) /* to relate them to the cell that is being instanced. Because this */ /* is used to link the same properties multiple times for parallel */ /* devices, copy the list (a refcount would work better. . .) */ -/* */ -/* If "isdefault" is "true", then the record is installed in the */ -/* object hash under the name "defaults"; otherwise, it gets the */ -/* name "properties" and is not added to the object hash. */ /*----------------------------------------------------------------------*/ struct objlist *LinkProperties(char *model, struct keyvalue *topptr) @@ -1953,10 +1948,6 @@ struct objlist *LinkProperties(char *model, struct keyvalue *topptr) return NULL; } cell = LookupCellFile(model, filenum); - if (cell == NULL) { - Printf("No cell '%s' found to link properties to.\n", model); - return NULL; - } tp = GetObject(); tp->type = PROPERTY; @@ -1977,6 +1968,27 @@ struct objlist *LinkProperties(char *model, struct keyvalue *topptr) /* No promotion to types other than string at this point */ newkv->type = PROP_STRING; newkv->value.string = strsave(kv->value); + + if (cell != NULL) { + struct property *kl = NULL; + + /* If there is a matching cell, make sure that the property */ + /* key exists. If not, create it and flag a warning. */ + + kl = (struct property *)HashLookup(newkv->key, cell->proptab, OBJHASHSIZE); + if (kl == NULL) { + Fprintf(stderr, "Warning: Property %s passed to cell %s which " + "does not define a default.\n", + newkv->key, cell->name); + kl = NewProperty(); + kl->key = strsave(newkv->key); + kl->idx = 0; + kl->type = PROP_STRING; + kl->slop.ival = 0; + kl->pdefault.string = NULL; + HashPtrInstall(kl->key, kl, cell->proptab, OBJHASHSIZE); + } + } } /* Final entry marks the end of the list */ @@ -1989,6 +2001,40 @@ struct objlist *LinkProperties(char *model, struct keyvalue *topptr) return tp; } +/*----------------------------------------------------------------------*/ +/* SetPropertyDefault() --- */ +/* */ +/* If a cell does not set property defaults, but an instance of that */ +/* cell passes a property to it, then there will be a default value */ +/* with a string type and a NULL value. Set the default to be equal */ +/* to the instance type and value. */ +/*----------------------------------------------------------------------*/ + +int SetPropertyDefault(struct property *prop, struct valuelist *vl) +{ + if (prop == NULL || vl == NULL) return -1; + if (prop->type != PROP_STRING || prop->pdefault.string != NULL) return 1; + + prop->type = vl->type; + + switch (vl->type) { + case PROP_STRING: + prop->pdefault.string = strsave(vl->value.string); + break; + case PROP_INTEGER: + prop->pdefault.ival = vl->value.ival; + break; + case PROP_DOUBLE: + case PROP_VALUE: + prop->pdefault.dval = vl->value.dval; + break; + case PROP_EXPRESSION: + prop->pdefault.stack = CopyTokStack(vl->value.stack); + break; + } + return 1; +} + /*----------------------------------------------------------------------*/ /* PromoteProperty() --- */ /* */ diff --git a/base/netgen.h b/base/netgen.h index 9d6ea5a..58312ec 100644 --- a/base/netgen.h +++ b/base/netgen.h @@ -40,6 +40,7 @@ extern int PropertyTolerance(char *name, int fnum, char *key, int ival, extern void ResolveProperties(char *name1, int file1, char *name2, int file2); 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); diff --git a/base/spice.c b/base/spice.c index 88136ec..d5de1c6 100644 --- a/base/spice.c +++ b/base/spice.c @@ -903,9 +903,9 @@ skip_ends: if (!strcasecmp(nexttok, "M")) sscanf(eqptr + 1, "%d", &ndev); else if (!strcasecmp(nexttok, "L")) - AddProperty(&kvlist, "length", eqptr + 1); + AddProperty(&kvlist, "L", eqptr + 1); else if (!strcasecmp(nexttok, "W")) - AddProperty(&kvlist, "width", eqptr + 1); + AddProperty(&kvlist, "W", eqptr + 1); else AddProperty(&kvlist, nexttok, eqptr + 1); } diff --git a/tcltk/tclnetgen.c b/tcltk/tclnetgen.c index 5991ab0..ff8ff5a 100644 --- a/tcltk/tclnetgen.c +++ b/tcltk/tclnetgen.c @@ -3206,11 +3206,16 @@ _netcmp_property(ClientData clientData, if (result != TCL_OK) return result; result = Tcl_GetIntFromObj(interp, tobj2, &ival); - if (result != TCL_OK) Tcl_ResetResult(interp); - if ((result = Tcl_GetDoubleFromObj(interp, tobj2, &dval)) - != TCL_OK) - return result; - + if (result != TCL_OK) { + Tcl_ResetResult(interp); + if (!strncasecmp(Tcl_GetString(tobj2), "inf", 3)) { + ival = 1<<30; + dval = 1.0E+300; + } + else if ((result = Tcl_GetDoubleFromObj(interp, tobj2, &dval)) + != TCL_OK) + return result; + } PropertyTolerance(tp->name, fnum, Tcl_GetString(tobj1), ival, dval); }