diff --git a/VERSION b/VERSION index d898cef..6b03f2a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.297 +1.5.298 diff --git a/base/netcmp.c b/base/netcmp.c index dfa3359..6fe8af5 100644 --- a/base/netcmp.c +++ b/base/netcmp.c @@ -8481,6 +8481,182 @@ int EquivalentElement(char *name, struct nlist *circuit, struct objlist **retobj return retval; } +/*------------------------------------------------------*/ +/* Structure and definitins used by derivedprops() */ +/*------------------------------------------------------*/ + +enum DerivedType {area_type, perimeter_type}; + +typedef struct _derivedpropdata { + struct nlist *cell; + int fnum; + char *pwidth; + char *plength; + enum DerivedType type; +} DerivedPropData; + +/*------------------------------------------------------*/ +/* derivedprops --- Callback function for a recursive */ +/* search over all cells with a pointer clientdata. */ +/* The pointer is a DerivedPropData structure that */ +/* contains the information needed to determine how to */ +/* generate an "area" or "perimeter" property based on */ +/* the device length and width. */ +/*------------------------------------------------------*/ + +struct nlist *derivedprops(struct hashlist *p, void *clientdata) +{ + struct nlist *ptr; + struct objlist *ob; + struct valuelist *vl, *newvlist; + struct nlist *tc; + struct property *prop; + int i; + double valuew, valuel, valuea = 0.0, valuep = 0.0; + int haswidth = FALSE, haslength = FALSE; + int hasarea = FALSE, hasperimeter = FALSE; + + DerivedPropData *dpd = (DerivedPropData *)clientdata; + + tc = dpd->cell; + ptr = (struct nlist *)(p->ptr); + if (ptr->file != tc->file) return NULL; + + /* Search all instances in the cell for properties, find those matching + * the cell class to be modified, and create a new derived property for + * area or perimeter for that instance. + */ + + for (ob = ptr->cell; ob; ob = ob->next) { + if (ob->type == PROPERTY) { + if ((*matchfunc)(ob->model.class, tc->name)) { + for (i = 0;; i++) { + vl = &(ob->instance.props[i]); + if (vl->type == PROP_ENDLIST) break; + prop = (struct property *)HashLookup(vl->key, &(tc->propdict)); + if (prop != NULL) { + if ((*matchfunc)(vl->key, dpd->pwidth)) { + haswidth = TRUE; + if (vl->type == PROP_DOUBLE) + valuew = vl->value.dval; + else if (vl->type == PROP_INTEGER) + valuew = (double)vl->value.ival; + else + haswidth = FALSE; + } + else if ((*matchfunc)(vl->key, dpd->plength)) { + haslength = TRUE; + if (vl->type == PROP_DOUBLE) + valuel = vl->value.dval; + else if (vl->type == PROP_INTEGER) + valuel = (double)vl->value.ival; + else + haslength = FALSE; + } + else if ((dpd->type == area_type) + && ((*matchfunc)(vl->key, "area"))) { + hasarea = TRUE; + } + else if ((dpd->type == perimeter_type) + && ((*matchfunc)(vl->key, "perimeter"))) { + hasperimeter = TRUE; + } + } + } + if (haslength && haswidth) { + + /* Once the property names for device width and length have + * been found, and the values recorded, add the area or + * perimeter value to the property list for the instance, + * unless the instance already has the property. + */ + newvlist = (struct valuelist *)CALLOC(i + 1, sizeof(struct valuelist)); + vl = &newvlist[i]; + vl->key = NULL; + vl->type = PROP_ENDLIST; + vl->value.ival = 0; + + vl = &newvlist[--i]; + if ((dpd->type == area_type) && (!hasarea)) { + valuea = valuew * valuel; + vl->key = strsave("area"); + vl->type = PROP_DOUBLE; + vl->value.dval = valuea; + + } else if ((dpd->type == perimeter_type) && (!hasperimeter)) { + valuep = 2 * (valuew + valuel); + vl->key = strsave("perimeter"); + vl->type = PROP_DOUBLE; + vl->value.dval = valuep; + } + for (--i; i >= 0; i--) { + vl = &newvlist[i]; + vl->key = ob->instance.props[i].key; + vl->type = ob->instance.props[i].type; + vl->value = ob->instance.props[i].value; + } + FREE(ob->instance.props); + ob->instance.props = newvlist; + } + } + } + } +} + +/*------------------------------------------------------*/ +/* Create a new "area" or "perimeter" property in all */ +/* instances of a given device, based on the specified */ +/* names for the width and length parameters. */ +/*------------------------------------------------------*/ + +void +DeriveProperty(struct nlist *tc, int fnum, char *pwidth, char *plength, + enum DerivedType type) +{ + DerivedPropData dpd; + + dpd.pwidth = pwidth; + dpd.plength = plength; + dpd.fnum = fnum; + dpd.cell = tc; + dpd.type = type; + + /* Create the new derived property in the cell. */ + if (type == area_type) + PropertyDouble(tc->name, fnum, "area", 0.01, 0.0); + else if (type == perimeter_type) + PropertyDouble(tc->name, fnum, "perimeter", 0.01, 0.0); + else + return; + + /* Find all instances of the cell and add the derived property */ + RecurseCellHashTable2(derivedprops, (void *)(&dpd)); +} + +/*------------------------------------------------------*/ +/* Create a new "area" property in all instances of a */ +/* given device, based on the specified width and */ +/* length parameter names. */ +/*------------------------------------------------------*/ + +void +DeriveAreaProperty(struct nlist *tp, int fnum, char *pwidth, char *plength) +{ + DeriveProperty(tp, fnum, pwidth, plength, area_type); +} + +/*------------------------------------------------------*/ +/* Create a new "perimeter" property in all instances */ +/* of a given device, based on the specified width and */ +/* length parameter names. */ +/*------------------------------------------------------*/ + +void +DerivePerimeterProperty(struct nlist *tp, int fnum, char *pwidth, char *plength) +{ + DeriveProperty(tp, fnum, pwidth, plength, perimeter_type); +} + /*------------------------------------------------------*/ /* Flatten the two cells at the top of the compare */ /* queue. */ diff --git a/base/netcmp.h b/base/netcmp.h index 6d90178..a0f646a 100644 --- a/base/netcmp.h +++ b/base/netcmp.h @@ -70,6 +70,8 @@ extern int remove_group_tags(struct objlist *ob); #ifdef TCL_NETGEN extern int EquivalentNode(); extern int EquivalentElement(); +extern void DeriveAreaProperty(); +extern void DerivePerimeterProperty(); extern void enable_interrupt(); extern void disable_interrupt(); diff --git a/tcltk/netgen.tcl.in b/tcltk/netgen.tcl.in index 2d5c13c..c413f44 100644 --- a/tcltk/netgen.tcl.in +++ b/tcltk/netgen.tcl.in @@ -594,6 +594,9 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} { lappend properr [lindex $endval 0] } elseif {$uresult == -2} { ;# unmatched pins set doCheckFlatten 1 + } elseif {$uresult == -4} { ;# unmatched pins and properties + lappend properr [lindex $endval 0] + set doCheckFlatten 1 } } else { # not equivalent diff --git a/tcltk/tclnetgen.c b/tcltk/tclnetgen.c index 5071a02..04274f6 100644 --- a/tcltk/tclnetgen.c +++ b/tcltk/tclnetgen.c @@ -2572,6 +2572,7 @@ _netcmp_run(ClientData clientData, /* 0: not verified */ /* -1: no elements or nodes */ /* -3: verified with property error */ +/* -4: verified with property and port errors */ /* equiv option */ /* -2: pin mismatch */ /* */ @@ -2673,8 +2674,12 @@ _netcmp_verify(ClientData clientData, else if (automorphisms == -2) { if (index == EQUIV_IDX) Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); - else if (index == UNIQUE_IDX) - Tcl_SetObjResult(interp, Tcl_NewIntObj(-2)); + else if (index == UNIQUE_IDX) { + if (PropertyErrorDetected == 0) + Tcl_SetObjResult(interp, Tcl_NewIntObj(-2)); + else + Tcl_SetObjResult(interp, Tcl_NewIntObj(-4)); + } else if (index > 0) Fprintf(stdout, "Circuits match uniquely with port errors.\n"); } @@ -3428,13 +3433,21 @@ _netcmp_property(ClientData clientData, double dval; int ival, argstart; + char *topoptions[] = { + "default", "series", "serial", "parallel", "topology", NULL + }; + enum TopOptionIdx { + TOP_DEFAULT_IDX, TOP_SERIES_IDX, TOP_SERIAL_IDX, TOP_PARALLEL_IDX, + TOP_TOPOLOGY_IDX + }; + char *options[] = { "add", "create", "remove", "delete", "tolerance", "merge", "serial", - "series", "parallel", "associate", "topology", NULL + "series", "parallel", "associate", "derive", NULL }; enum OptionIdx { ADD_IDX, CREATE_IDX, REMOVE_IDX, DELETE_IDX, TOLERANCE_IDX, MERGE_IDX, - SERIAL_IDX, SERIES_IDX, PARALLEL_IDX, ASSOCIATE_IDX, TOPOLOGY_IDX + SERIAL_IDX, SERIES_IDX, PARALLEL_IDX, ASSOCIATE_IDX, DERIVE_IDX }; int result, index, idx2; @@ -3469,6 +3482,14 @@ _netcmp_property(ClientData clientData, COMB_NONE_IDX, COMB_PAR_IDX, COMB_ADD_IDX, COMB_CRITICAL_IDX }; + char *deriveoptions[] = { + "area", "perimeter", NULL + }; + + enum DeriveOptionIdx { + AREA_IDX, PERIMETER_IDX + }; + char *yesno[] = { "on", "yes", "true", "enable", "allow", "off", "no", "false", "disable", "prohibit", NULL @@ -3483,8 +3504,13 @@ _netcmp_property(ClientData clientData, "strict", "relaxed", NULL }; + /* Don't need to check return value */ + index = -1; + Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)topoptions, + "option", 0, &index); + /* Check for special command "property default" */ - if ((objc == 2) && (!strcmp(Tcl_GetString(objv[1]), "default"))) { + if ((objc == 2) && (index == TOP_DEFAULT_IDX)) { /* For each FET device, do "merge {w add_critical}" and */ /* "remove as ad ps pd". This allows parallel devices */ @@ -3531,7 +3557,7 @@ _netcmp_property(ClientData clientData, } return TCL_OK; } - else if ((objc == 3) && (!strcmp(Tcl_GetString(objv[1]), "parallel"))) { + else if ((objc == 3) && (index == TOP_PARALLEL_IDX)) { if (!strcmp(Tcl_GetString(objv[2]), "none")) { GlobalParallelNone = TRUE; SetParallelCombine(FALSE); @@ -3553,8 +3579,7 @@ _netcmp_property(ClientData clientData, } return TCL_OK; } - else if ((objc == 3) && ((!strcmp(Tcl_GetString(objv[1]), "series")) || - (!strcmp(Tcl_GetString(objv[1]), "serial")))) { + else if ((objc == 3) && ((index == TOP_SERIES_IDX) || (index == TOP_SERIAL_IDX))) { if (!strcmp(Tcl_GetString(objv[2]), "none")) { SetSeriesCombine(FALSE); } @@ -3568,7 +3593,7 @@ _netcmp_property(ClientData clientData, } return TCL_OK; } - else if ((objc > 1) && (!strcmp(Tcl_GetString(objv[1]), "topology"))) { + else if ((objc > 1) && (index == TOP_TOPOLOGY_IDX)) { if (objc == 2) { if (ExactTopology) Tcl_SetResult(interp, "Strict topology property matching.", @@ -4014,6 +4039,32 @@ _netcmp_property(ClientData clientData, } break; + case DERIVE_IDX: + /* Create a derived property. For now, this just creates + * "area" or "perimeter" properties. There may not (?) + * be enough cause to make other ones. Unlike other + * "property" options, this option causes the whole circuit + * database to be searched for the device in question, and + * the new property is added. + */ + if (objc < 6) { + Tcl_WrongNumArgs(interp, 2, objv, "{area|perimeter width length}"); + return TCL_ERROR; + } + result = Tcl_GetIndexFromObj(interp, objv[3], + (CONST84 char **)deriveoptions, + "area|perimeter", 0, &idx2); + if (result != TCL_OK) return result; + switch (idx2) { + case AREA_IDX: + DeriveAreaProperty(tp, fnum, Tcl_GetString(objv[4]), + Tcl_GetString(objv[5])); + break; + case PERIMETER_IDX: + DerivePerimeterProperty(tp, fnum, Tcl_GetString(objv[4]), + Tcl_GetString(objv[5])); + break; + } } } return TCL_OK;