(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 property *kl;
|
||||||
struct valuelist *vl, *sl;
|
struct valuelist *vl, *sl;
|
||||||
int i, p, sval, merge_type;
|
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;
|
obn = ob1->next;
|
||||||
for (i = 0; i < idx1; i++) obn = obn->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;
|
obp = obn;
|
||||||
sval = 1;
|
sval = 1;
|
||||||
cval = slop = 0.0;
|
pval = aval = oval = 0.0;
|
||||||
for (i = 0; i < run; i++) {
|
for (i = 0; i < run; i++) {
|
||||||
sl = NULL;
|
has_crit = FALSE;
|
||||||
merge_type = MERGE_NONE;
|
merge_type = MERGE_NONE;
|
||||||
|
ca = co = (char)0;
|
||||||
|
|
||||||
for (p = 0;; p++) {
|
for (p = 0;; p++) {
|
||||||
vl = &(obp->instance.props[p]);
|
vl = &(obp->instance.props[p]);
|
||||||
if (vl->type == PROP_ENDLIST) break;
|
if (vl->type == PROP_ENDLIST) break;
|
||||||
if (vl->key == NULL) continue;
|
if (vl->key == NULL) continue;
|
||||||
if ((*matchfunc)(vl->key, "S")) {
|
if ((*matchfunc)(vl->key, "S")) {
|
||||||
sval = vl->value.ival;
|
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 {
|
else {
|
||||||
kl = (struct property *)HashLookup(vl->key, &(tp1->propdict));
|
tval = vl->value.dval;
|
||||||
if (kl && (kl->merge & (MERGE_S_ADD | MERGE_S_PAR))) {
|
tslop = kl->slop.dval;
|
||||||
if (vl->type == PROP_INTEGER) {
|
}
|
||||||
cval = (double)vl->value.ival;
|
|
||||||
slop = (double)kl->slop.ival;
|
if (kl->merge & MERGE_S_CRIT) {
|
||||||
}
|
has_crit = TRUE;
|
||||||
else {
|
pval = tval;
|
||||||
cval = vl->value.dval;
|
pslop = tslop;
|
||||||
slop = kl->slop.dval;
|
}
|
||||||
}
|
else if (kl->merge & (MERGE_S_ADD | MERGE_S_PAR)) {
|
||||||
merge_type = 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) {
|
if (has_crit == TRUE) {
|
||||||
proplist[i].value = cval * (double)sval;
|
/* If there is a critical value, then sort first */
|
||||||
proplist[i].slop = slop;
|
/* by critical value */
|
||||||
proplist[i].avalue = 0;
|
proplist[i].value = pval;
|
||||||
if (sl) sl->value.ival = 1;
|
proplist[i].slop = pslop;
|
||||||
}
|
|
||||||
else if (merge_type == MERGE_S_PAR) {
|
/* then sort on additive value times S */
|
||||||
proplist[i].value = cval / (double)sval;
|
/* or on non-additive value. */
|
||||||
proplist[i].slop = slop;
|
if (merge_type == MERGE_S_ADD)
|
||||||
proplist[i].avalue = 0;
|
proplist[i].avalue = aval * (double)sval;
|
||||||
if (sl) sl->value.ival = 1;
|
else if (merge_type == MERGE_S_PAR)
|
||||||
|
proplist[i].avalue = aval / (double)sval;
|
||||||
|
else
|
||||||
|
proplist[i].avalue = (double)sval;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Components which declare no series addition method stay unsorted */
|
if (merge_type != MERGE_NONE) {
|
||||||
proplist[i].value = (double)0;
|
proplist[i].value = aval;
|
||||||
proplist[i].avalue = (double)0;
|
proplist[i].slop = aslop;
|
||||||
proplist[i].slop = (double)1E-6;
|
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].idx = i;
|
||||||
proplist[i].ob = obp;
|
proplist[i].ob = obp;
|
||||||
obp = obp->next;
|
obp = obp->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
obn = obp; /* Link from last property */
|
obn = obp; /* Link from last property */
|
||||||
|
|
||||||
qsort(&proplist[0], run, sizeof(propsort), compsort);
|
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 */
|
/* and manage the topology. Note that at this point devices have */
|
||||||
/* already been combined if all critical properties match, so any */
|
/* already been combined if all critical properties match, so any */
|
||||||
/* parallel devices remaining are not considered mergeable unless as */
|
/* parallel devices remaining are not considered mergeable unless as */
|
||||||
/* a last resort. Parallel devices need to be checked for swapping, */
|
/* a last resort. Devices also need to be checked for swapping. */
|
||||||
/* however. So the steps are: */
|
/* So the steps are: */
|
||||||
/* 1) Find parallel devices with more elements in one circuit than */
|
/* 1) Find parallel devices with more elements in one circuit than */
|
||||||
/* in the other. If non-summing parameters of interest match, */
|
/* in the other. If non-summing parameters of interest match, */
|
||||||
/* then merge all devices that can be merged until both sides */
|
/* 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. Check if critical parameters match between the */
|
||||||
/* circuits. If not, check if swapping devices in circuit1 */
|
/* circuits. If not, check if swapping devices in circuit1 */
|
||||||
/* makes a better match to circuit2. */
|
/* 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 */
|
/* Case 1: Parallel devices with more elements in one circuit */
|
||||||
|
|
||||||
|
|
@ -5317,13 +5364,14 @@ void
|
||||||
#endif
|
#endif
|
||||||
PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||||
char *inst1, struct objlist *tp2, struct nlist *tc2,
|
char *inst1, struct objlist *tp2, struct nlist *tc2,
|
||||||
char *inst2, int do_print, int do_list, int *count,
|
char *inst2, struct Element *E1, struct Element *E2,
|
||||||
int *rval)
|
int do_print, int do_list, int *count, int *rval)
|
||||||
{
|
{
|
||||||
int mismatches = 0;
|
int mismatches = 0;
|
||||||
int len2, *check2;
|
int len2, *check2;
|
||||||
struct property *kl1, *kl2, *klt;
|
struct property *kl1, *kl2, *klt;
|
||||||
struct valuelist *vl1, *vl2;
|
struct valuelist *vl1, *vl2;
|
||||||
|
char *vl1key;
|
||||||
int i, j;
|
int i, j;
|
||||||
int islop;
|
int islop;
|
||||||
int ival1, ival2;
|
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. */
|
/* Find the matching property in vl2. */
|
||||||
|
|
||||||
for (j = 0;; j++) {
|
for (j = 0;; j++) {
|
||||||
vl2 = &(tp2->instance.props[j]);
|
vl2 = &(tp2->instance.props[j]);
|
||||||
if (vl2->type == PROP_ENDLIST) break;
|
if (vl2->type == PROP_ENDLIST) break;
|
||||||
if (check2[j] == 0)
|
if (check2[j] == 0)
|
||||||
if ((*matchfunc)(vl1->key, vl2->key)) break;
|
if ((*matchfunc)(vl1key, vl2->key)) break;
|
||||||
}
|
}
|
||||||
if (vl2->type == PROP_ENDLIST) {
|
if (vl2->type == PROP_ENDLIST) {
|
||||||
/* Check against M and S records; a missing M or S */
|
/* Check against M and S records; a missing M or S */
|
||||||
/* record is equivalent to M = 1 or S = 1. */
|
/* record is equivalent to M = 1 or S = 1. */
|
||||||
|
|
||||||
if (vl1 != &mvl)
|
if (vl1 != &mvl)
|
||||||
if ((*matchfunc)(vl1->key, mvl.key)) vl2 = &mvl;
|
if ((*matchfunc)(vl1key, mvl.key)) vl2 = &mvl;
|
||||||
if (vl1 != &svl)
|
if (vl1 != &svl)
|
||||||
if ((*matchfunc)(vl1->key, svl.key)) vl2 = &svl;
|
if ((*matchfunc)(vl1key, svl.key)) vl2 = &svl;
|
||||||
}
|
}
|
||||||
if (vl2->type == PROP_ENDLIST) {
|
if (vl2->type == PROP_ENDLIST) {
|
||||||
/* vl1 had a property of interest that was not found */
|
/* vl1 had a property of interest that was not found */
|
||||||
|
|
@ -5451,7 +5548,7 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||||
if (do_print) {
|
if (do_print) {
|
||||||
Fprintf(stdout, "%s vs. %s:\n", inst1, inst2);
|
Fprintf(stdout, "%s vs. %s:\n", inst1, inst2);
|
||||||
Fprintf(stdout, "Property %s in circuit1 has no matching "
|
Fprintf(stdout, "Property %s in circuit1 has no matching "
|
||||||
"property in circuit2\n", vl1->key);
|
"property in circuit2\n", vl1key);
|
||||||
}
|
}
|
||||||
#ifdef TCL_NETGEN
|
#ifdef TCL_NETGEN
|
||||||
if (do_list) {
|
if (do_list) {
|
||||||
|
|
@ -6095,7 +6192,7 @@ PropertyMatch(struct Element *E1, struct Element *E2,
|
||||||
else {
|
else {
|
||||||
int multmatch, count;
|
int multmatch, count;
|
||||||
PropertyCheckMismatch(tp1, tc1, inst1, tp2, tc2,
|
PropertyCheckMismatch(tp1, tc1, inst1, tp2, tc2,
|
||||||
inst2, FALSE, FALSE, &multmatch, NULL);
|
inst2, E1, E2, FALSE, FALSE, &multmatch, NULL);
|
||||||
if (multmatch == 1) {
|
if (multmatch == 1) {
|
||||||
/* Final attempt: Reduce M to 1 on both devices */
|
/* Final attempt: Reduce M to 1 on both devices */
|
||||||
run1 = run2 = 0;
|
run1 = run2 = 0;
|
||||||
|
|
@ -6116,7 +6213,7 @@ PropertyMatch(struct Element *E1, struct Element *E2,
|
||||||
mlist =
|
mlist =
|
||||||
#endif
|
#endif
|
||||||
PropertyCheckMismatch(tp1, tc1, inst1, tp2, tc2,
|
PropertyCheckMismatch(tp1, tc1, inst1, tp2, tc2,
|
||||||
inst2, do_print, do_list, &count, &rval);
|
inst2, E1, E2, do_print, do_list, &count, &rval);
|
||||||
mismatches += count;
|
mismatches += count;
|
||||||
#ifdef TCL_NETGEN
|
#ifdef TCL_NETGEN
|
||||||
if (do_list && (mlist != NULL)) {
|
if (do_list && (mlist != NULL)) {
|
||||||
|
|
|
||||||
|
|
@ -984,6 +984,51 @@ PropertyDelete(char *name, int fnum, char *key)
|
||||||
return 0;
|
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. */
|
/* 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 void SetSeriesCombine(int value);
|
||||||
extern int PropertyTolerance(char *name, int fnum, char *key, int ival,
|
extern int PropertyTolerance(char *name, int fnum, char *key, int ival,
|
||||||
double dval);
|
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,
|
extern int PropertyMerge(char *name, int fnum, char *key, int merge_type,
|
||||||
int merge_mask);
|
int merge_mask);
|
||||||
extern void ResolveProperties(char *name1, int file1, char *name2, int file2);
|
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));
|
kl = (struct property *)CALLOC(1,sizeof(struct property));
|
||||||
if (kl == NULL) Fprintf(stderr,"NewProperty: Core allocation error\n");
|
if (kl == NULL) Fprintf(stderr,"NewProperty: Core allocation error\n");
|
||||||
|
kl->pin = (char *)NULL;
|
||||||
return (kl);
|
return (kl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,7 @@ struct property {
|
||||||
unsigned char idx; /* index into valuelist */
|
unsigned char idx; /* index into valuelist */
|
||||||
unsigned char type; /* string, integer, double, value, expression */
|
unsigned char type; /* string, integer, double, value, expression */
|
||||||
unsigned char merge; /* how property changes when devices are merged */
|
unsigned char merge; /* how property changes when devices are merged */
|
||||||
|
char *pin; /* associated pin (or NULL if not associated) */
|
||||||
union {
|
union {
|
||||||
char *string;
|
char *string;
|
||||||
double dval;
|
double dval;
|
||||||
|
|
|
||||||
|
|
@ -3377,6 +3377,7 @@ _netcmp_equate(ClientData clientData,
|
||||||
/* add --- add new property */
|
/* add --- add new property */
|
||||||
/* remove --- delete existing property */
|
/* remove --- delete existing property */
|
||||||
/* tolerance --- set property tolerance */
|
/* tolerance --- set property tolerance */
|
||||||
|
/* associate --- associate property with a pin */
|
||||||
/* merge --- (deprecated) */
|
/* merge --- (deprecated) */
|
||||||
/* or */
|
/* or */
|
||||||
/* netgen::property default */
|
/* netgen::property default */
|
||||||
|
|
@ -3415,11 +3416,11 @@ _netcmp_property(ClientData clientData,
|
||||||
|
|
||||||
char *options[] = {
|
char *options[] = {
|
||||||
"add", "create", "remove", "delete", "tolerance", "merge", "serial",
|
"add", "create", "remove", "delete", "tolerance", "merge", "serial",
|
||||||
"series", "parallel", NULL
|
"series", "parallel", "associate", NULL
|
||||||
};
|
};
|
||||||
enum OptionIdx {
|
enum OptionIdx {
|
||||||
ADD_IDX, CREATE_IDX, REMOVE_IDX, DELETE_IDX, TOLERANCE_IDX, MERGE_IDX,
|
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;
|
int result, index, idx2;
|
||||||
|
|
||||||
|
|
@ -3842,6 +3843,29 @@ _netcmp_property(ClientData clientData,
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case TOLERANCE_IDX:
|
||||||
if (objc == 3) {
|
if (objc == 3) {
|
||||||
Tcl_WrongNumArgs(interp, 1, objv, "{property_key tolerance} ...");
|
Tcl_WrongNumArgs(interp, 1, objv, "{property_key tolerance} ...");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue