(1) Fixed the series sorting, which needed to be modified to match
the parallel sorting routine. This fixes occasional property errors with series-connected devices such as resistors. (2) Added a method to associate properties with specific pins when pins are permutable. This allows netgen to properly check a value like source/drain area when the definition of source and drain has changed due to permutation of the device. (3) Added a "property" command extension "associate" to associate a property with a pin, for use with the method described in (2).
This commit is contained in:
parent
2292ab813b
commit
013fff9f37
177
base/netcmp.c
177
base/netcmp.c
|
|
@ -4214,7 +4214,11 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
|||
struct property *kl;
|
||||
struct valuelist *vl, *sl;
|
||||
int i, p, sval, merge_type;
|
||||
double cval, slop;
|
||||
// double cval, slop;
|
||||
int has_crit;
|
||||
char ca, co;
|
||||
double tval, tslop;
|
||||
double aval, pval, oval, aslop, pslop;
|
||||
|
||||
obn = ob1->next;
|
||||
for (i = 0; i < idx1; i++) obn = obn->next;
|
||||
|
|
@ -4227,55 +4231,94 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
|||
|
||||
obp = obn;
|
||||
sval = 1;
|
||||
cval = slop = 0.0;
|
||||
pval = aval = oval = 0.0;
|
||||
for (i = 0; i < run; i++) {
|
||||
sl = NULL;
|
||||
has_crit = FALSE;
|
||||
merge_type = MERGE_NONE;
|
||||
ca = co = (char)0;
|
||||
|
||||
for (p = 0;; p++) {
|
||||
vl = &(obp->instance.props[p]);
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
if (vl->key == NULL) continue;
|
||||
if ((*matchfunc)(vl->key, "S")) {
|
||||
sval = vl->value.ival;
|
||||
sl = vl;
|
||||
continue;
|
||||
}
|
||||
kl = (struct property *)HashLookup(vl->key, &(tp1->propdict));
|
||||
if (kl == NULL) continue; /* Ignored property */
|
||||
|
||||
/* Get the property value and slop. Promote if needed. Save */
|
||||
/* property and slop as type double so they can be sorted. */
|
||||
|
||||
if ((vl->type == PROP_STRING || vl->type == PROP_EXPRESSION) &&
|
||||
(kl->type != vl->type))
|
||||
PromoteProperty(kl, vl, obp, tp1);
|
||||
if (vl->type == PROP_INTEGER) {
|
||||
tval = (double)vl->value.ival;
|
||||
tslop = (double)kl->slop.ival;
|
||||
}
|
||||
else if (vl->type == PROP_STRING) {
|
||||
/* This is unlikely---no method to merge string properties! */
|
||||
tval = (double)vl->value.string[0]
|
||||
+ (double)vl->value.string[1] / 10.0;
|
||||
tslop = (double)0;
|
||||
}
|
||||
else {
|
||||
kl = (struct property *)HashLookup(vl->key, &(tp1->propdict));
|
||||
if (kl && (kl->merge & (MERGE_S_ADD | MERGE_S_PAR))) {
|
||||
if (vl->type == PROP_INTEGER) {
|
||||
cval = (double)vl->value.ival;
|
||||
slop = (double)kl->slop.ival;
|
||||
}
|
||||
else {
|
||||
cval = vl->value.dval;
|
||||
slop = kl->slop.dval;
|
||||
}
|
||||
merge_type = kl->merge & (MERGE_S_ADD | MERGE_S_PAR);
|
||||
tval = vl->value.dval;
|
||||
tslop = kl->slop.dval;
|
||||
}
|
||||
|
||||
if (kl->merge & MERGE_S_CRIT) {
|
||||
has_crit = TRUE;
|
||||
pval = tval;
|
||||
pslop = tslop;
|
||||
}
|
||||
else if (kl->merge & (MERGE_S_ADD | MERGE_S_PAR)) {
|
||||
if ((ca == (char)0) || (toupper(vl->key[0]) > ca)) {
|
||||
merge_type = kl->merge & (MERGE_S_ADD | MERGE_S_PAR);
|
||||
aval = tval;
|
||||
aslop = tslop;
|
||||
ca = toupper(vl->key[0]);
|
||||
}
|
||||
}
|
||||
else if ((co == (char)0) || (toupper(vl->key[0]) > co)) {
|
||||
oval = tval;
|
||||
co = toupper(vl->key[0]);
|
||||
}
|
||||
}
|
||||
if (merge_type == MERGE_S_ADD) {
|
||||
proplist[i].value = cval * (double)sval;
|
||||
proplist[i].slop = slop;
|
||||
proplist[i].avalue = 0;
|
||||
if (sl) sl->value.ival = 1;
|
||||
}
|
||||
else if (merge_type == MERGE_S_PAR) {
|
||||
proplist[i].value = cval / (double)sval;
|
||||
proplist[i].slop = slop;
|
||||
proplist[i].avalue = 0;
|
||||
if (sl) sl->value.ival = 1;
|
||||
if (has_crit == TRUE) {
|
||||
/* If there is a critical value, then sort first */
|
||||
/* by critical value */
|
||||
proplist[i].value = pval;
|
||||
proplist[i].slop = pslop;
|
||||
|
||||
/* then sort on additive value times S */
|
||||
/* or on non-additive value. */
|
||||
if (merge_type == MERGE_S_ADD)
|
||||
proplist[i].avalue = aval * (double)sval;
|
||||
else if (merge_type == MERGE_S_PAR)
|
||||
proplist[i].avalue = aval / (double)sval;
|
||||
else
|
||||
proplist[i].avalue = (double)sval;
|
||||
}
|
||||
else {
|
||||
/* Components which declare no series addition method stay unsorted */
|
||||
proplist[i].value = (double)0;
|
||||
proplist[i].avalue = (double)0;
|
||||
proplist[i].slop = (double)1E-6;
|
||||
if (merge_type != MERGE_NONE) {
|
||||
proplist[i].value = aval;
|
||||
proplist[i].slop = aslop;
|
||||
proplist[i].avalue = (double)sval;
|
||||
}
|
||||
else {
|
||||
proplist[i].value = (double)sval;
|
||||
proplist[i].slop = (double)0;
|
||||
proplist[i].avalue = oval;
|
||||
}
|
||||
}
|
||||
proplist[i].idx = i;
|
||||
proplist[i].ob = obp;
|
||||
obp = obp->next;
|
||||
}
|
||||
|
||||
obn = obp; /* Link from last property */
|
||||
|
||||
qsort(&proplist[0], run, sizeof(propsort), compsort);
|
||||
|
|
@ -4598,8 +4641,8 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
|||
/* and manage the topology. Note that at this point devices have */
|
||||
/* already been combined if all critical properties match, so any */
|
||||
/* parallel devices remaining are not considered mergeable unless as */
|
||||
/* a last resort. Parallel devices need to be checked for swapping, */
|
||||
/* however. So the steps are: */
|
||||
/* a last resort. Devices also need to be checked for swapping. */
|
||||
/* So the steps are: */
|
||||
/* 1) Find parallel devices with more elements in one circuit than */
|
||||
/* in the other. If non-summing parameters of interest match, */
|
||||
/* then merge all devices that can be merged until both sides */
|
||||
|
|
@ -4612,6 +4655,10 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
|||
/* circuits. Check if critical parameters match between the */
|
||||
/* circuits. If not, check if swapping devices in circuit1 */
|
||||
/* makes a better match to circuit2. */
|
||||
/* 4) Find series devices that have the same number in both */
|
||||
/* circuits. Check if critical parameters match between the */
|
||||
/* circuits. If not, check if swapping devices in circuit1 */
|
||||
/* makes a better match to circuit2. */
|
||||
|
||||
/* Case 1: Parallel devices with more elements in one circuit */
|
||||
|
||||
|
|
@ -5317,13 +5364,14 @@ void
|
|||
#endif
|
||||
PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
char *inst1, struct objlist *tp2, struct nlist *tc2,
|
||||
char *inst2, int do_print, int do_list, int *count,
|
||||
int *rval)
|
||||
char *inst2, struct Element *E1, struct Element *E2,
|
||||
int do_print, int do_list, int *count, int *rval)
|
||||
{
|
||||
int mismatches = 0;
|
||||
int len2, *check2;
|
||||
struct property *kl1, *kl2, *klt;
|
||||
struct valuelist *vl1, *vl2;
|
||||
char *vl1key;
|
||||
int i, j;
|
||||
int islop;
|
||||
int ival1, ival2;
|
||||
|
|
@ -5427,22 +5475,71 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
|||
}
|
||||
}
|
||||
|
||||
/* If the property is associated with a pin, then */
|
||||
/* determine if the pin is permutable; If so, then */
|
||||
/* determine if the pins are swapped between the two */
|
||||
/* elements. If so, then swap the property keys. */
|
||||
|
||||
vl1key = vl1->key;
|
||||
if (kl1->pin != NULL) {
|
||||
struct objlist *tob1, *tob2;
|
||||
struct NodeList *nl1, *nl2;
|
||||
struct property *kla;
|
||||
struct valuelist *vla;
|
||||
int k;
|
||||
|
||||
nl1 = E1->nodelist;
|
||||
for (tob1 = tc1->cell; tob1 && tob1->type == PORT; tob1 = tob1->next) {
|
||||
if ((*matchfunc)(tob1->name, kl1->pin)) break;
|
||||
nl1 = nl1->next;
|
||||
}
|
||||
if (tob1->type == PORT) {
|
||||
/* Found the node list record corresponding to the given pin. */
|
||||
/* Now find the pin corresponding to the matching node. */
|
||||
nl2 = E2->nodelist;
|
||||
for (tob2 = tc1->cell; tob2 && tob2->type == PORT; tob2 = tob2->next) {
|
||||
if (nl2->node->nodeclass == nl1->node->nodeclass) break;
|
||||
nl2 = nl2->next;
|
||||
}
|
||||
if (nl2->node->nodeclass == nl1->node->nodeclass) {
|
||||
if (tob2 != tob1) { /* Element pins were swapped */
|
||||
/* Find the other property to swap with */
|
||||
for (k = 0;; k++) {
|
||||
vla = &(tp1->instance.props[k]);
|
||||
if (vla->type == PROP_ENDLIST) break;
|
||||
if (vla != vl1) {
|
||||
kla = (struct property *)HashLookup(vla->key,
|
||||
&(tc1->propdict));
|
||||
if (kla && kla->pin)
|
||||
if ((*matchfunc)(tob2->name, kla->pin))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (vla->type != PROP_ENDLIST) {
|
||||
/* Swap vla->key and vl1->key */
|
||||
vl1key = vla->key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the matching property in vl2. */
|
||||
|
||||
for (j = 0;; j++) {
|
||||
vl2 = &(tp2->instance.props[j]);
|
||||
if (vl2->type == PROP_ENDLIST) break;
|
||||
if (check2[j] == 0)
|
||||
if ((*matchfunc)(vl1->key, vl2->key)) break;
|
||||
if ((*matchfunc)(vl1key, vl2->key)) break;
|
||||
}
|
||||
if (vl2->type == PROP_ENDLIST) {
|
||||
/* Check against M and S records; a missing M or S */
|
||||
/* record is equivalent to M = 1 or S = 1. */
|
||||
|
||||
if (vl1 != &mvl)
|
||||
if ((*matchfunc)(vl1->key, mvl.key)) vl2 = &mvl;
|
||||
if ((*matchfunc)(vl1key, mvl.key)) vl2 = &mvl;
|
||||
if (vl1 != &svl)
|
||||
if ((*matchfunc)(vl1->key, svl.key)) vl2 = &svl;
|
||||
if ((*matchfunc)(vl1key, svl.key)) vl2 = &svl;
|
||||
}
|
||||
if (vl2->type == PROP_ENDLIST) {
|
||||
/* vl1 had a property of interest that was not found */
|
||||
|
|
@ -5451,7 +5548,7 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
|||
if (do_print) {
|
||||
Fprintf(stdout, "%s vs. %s:\n", inst1, inst2);
|
||||
Fprintf(stdout, "Property %s in circuit1 has no matching "
|
||||
"property in circuit2\n", vl1->key);
|
||||
"property in circuit2\n", vl1key);
|
||||
}
|
||||
#ifdef TCL_NETGEN
|
||||
if (do_list) {
|
||||
|
|
@ -6095,7 +6192,7 @@ PropertyMatch(struct Element *E1, struct Element *E2,
|
|||
else {
|
||||
int multmatch, count;
|
||||
PropertyCheckMismatch(tp1, tc1, inst1, tp2, tc2,
|
||||
inst2, FALSE, FALSE, &multmatch, NULL);
|
||||
inst2, E1, E2, FALSE, FALSE, &multmatch, NULL);
|
||||
if (multmatch == 1) {
|
||||
/* Final attempt: Reduce M to 1 on both devices */
|
||||
run1 = run2 = 0;
|
||||
|
|
@ -6116,7 +6213,7 @@ PropertyMatch(struct Element *E1, struct Element *E2,
|
|||
mlist =
|
||||
#endif
|
||||
PropertyCheckMismatch(tp1, tc1, inst1, tp2, tc2,
|
||||
inst2, do_print, do_list, &count, &rval);
|
||||
inst2, E1, E2, do_print, do_list, &count, &rval);
|
||||
mismatches += count;
|
||||
#ifdef TCL_NETGEN
|
||||
if (do_list && (mlist != NULL)) {
|
||||
|
|
|
|||
|
|
@ -984,6 +984,51 @@ PropertyDelete(char *name, int fnum, char *key)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Associate a property with a specific pin */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
PropertyAssociatePin(char *name, int fnum, char *key, char *pin)
|
||||
{
|
||||
struct property *kl = NULL;
|
||||
struct nlist *tc;
|
||||
struct objlist *ob;
|
||||
int result;
|
||||
|
||||
if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
|
||||
result = PropertyAssociatePin(name, Circuit1->file, key, pin);
|
||||
result = PropertyAssociatePin(name, Circuit2->file, key, pin);
|
||||
return result;
|
||||
}
|
||||
|
||||
tc = LookupCellFile(name, fnum);
|
||||
if (tc == NULL) {
|
||||
Printf("No device %s found for PropertyAssociatePin()\n", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
kl = (struct property *)HashLookup(key, &(tc->propdict));
|
||||
if (kl == NULL) {
|
||||
Printf("No property %s found for device %s\n", key, name);
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
for (ob = tc->cell; ob != NULL; ob = ob->next) {
|
||||
if (ob->type != PORT) break;
|
||||
else if ((*matchfunc)(ob->name, pin)) {
|
||||
kl->pin = ob->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ob == NULL) {
|
||||
Printf("No pin %s found for device %s\n", pin, name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Set the tolerance of a property in the master cell record. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ extern void SetParallelCombine(int value);
|
|||
extern void SetSeriesCombine(int value);
|
||||
extern int PropertyTolerance(char *name, int fnum, char *key, int ival,
|
||||
double dval);
|
||||
extern int PropertyAssociatePin(char *name, int fnum, char *key, char *pin);
|
||||
extern int PropertyMerge(char *name, int fnum, char *key, int merge_type,
|
||||
int merge_mask);
|
||||
extern void ResolveProperties(char *name1, int file1, char *name2, int file2);
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ struct property *NewProperty(void)
|
|||
|
||||
kl = (struct property *)CALLOC(1,sizeof(struct property));
|
||||
if (kl == NULL) Fprintf(stderr,"NewProperty: Core allocation error\n");
|
||||
kl->pin = (char *)NULL;
|
||||
return (kl);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ struct property {
|
|||
unsigned char idx; /* index into valuelist */
|
||||
unsigned char type; /* string, integer, double, value, expression */
|
||||
unsigned char merge; /* how property changes when devices are merged */
|
||||
char *pin; /* associated pin (or NULL if not associated) */
|
||||
union {
|
||||
char *string;
|
||||
double dval;
|
||||
|
|
|
|||
|
|
@ -3377,6 +3377,7 @@ _netcmp_equate(ClientData clientData,
|
|||
/* add --- add new property */
|
||||
/* remove --- delete existing property */
|
||||
/* tolerance --- set property tolerance */
|
||||
/* associate --- associate property with a pin */
|
||||
/* merge --- (deprecated) */
|
||||
/* or */
|
||||
/* netgen::property default */
|
||||
|
|
@ -3415,11 +3416,11 @@ _netcmp_property(ClientData clientData,
|
|||
|
||||
char *options[] = {
|
||||
"add", "create", "remove", "delete", "tolerance", "merge", "serial",
|
||||
"series", "parallel", NULL
|
||||
"series", "parallel", "associate", NULL
|
||||
};
|
||||
enum OptionIdx {
|
||||
ADD_IDX, CREATE_IDX, REMOVE_IDX, DELETE_IDX, TOLERANCE_IDX, MERGE_IDX,
|
||||
SERIAL_IDX, SERIES_IDX, PARALLEL_IDX
|
||||
SERIAL_IDX, SERIES_IDX, PARALLEL_IDX, ASSOCIATE_IDX
|
||||
};
|
||||
int result, index, idx2;
|
||||
|
||||
|
|
@ -3842,6 +3843,29 @@ _netcmp_property(ClientData clientData,
|
|||
}
|
||||
break;
|
||||
|
||||
case ASSOCIATE_IDX:
|
||||
if (objc == 3) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "{property_key pin_name} ...");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
for (i = 3; i < objc; i++) {
|
||||
// Each value must be a duplet
|
||||
result = Tcl_ListObjLength(interp, objv[i], &llen);
|
||||
if ((result != TCL_OK) || (llen != 2)) {
|
||||
Tcl_SetResult(interp, "Not a {key pin} pair list.",
|
||||
NULL);
|
||||
}
|
||||
else {
|
||||
result = Tcl_ListObjIndex(interp, objv[i], 0, &tobj1);
|
||||
if (result != TCL_OK) return result;
|
||||
result = Tcl_ListObjIndex(interp, objv[i], 1, &tobj2);
|
||||
if (result != TCL_OK) return result;
|
||||
PropertyAssociatePin(tp->name, fnum, Tcl_GetString(tobj1),
|
||||
Tcl_GetString(tobj2));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TOLERANCE_IDX:
|
||||
if (objc == 3) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "{property_key tolerance} ...");
|
||||
|
|
|
|||
Loading…
Reference in New Issue