mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-22 22:17:22 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
535b8285e9 | ||
|
|
28a2950439 | ||
|
|
1e1d506697 | ||
|
|
013fff9f37 | ||
|
|
4edaf0813d | ||
|
|
2292ab813b | ||
|
|
a4ae5ed989 | ||
|
|
7e8508db53 | ||
|
|
c9f7b24e0f | ||
|
|
d850586a14 | ||
|
|
95605ebbd4 |
+217
-74
@@ -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 */
|
||||
|
||||
@@ -5182,7 +5229,7 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed > 0) {
|
||||
if ((Debug == TRUE) && (changed > 0)) {
|
||||
if (series)
|
||||
Printf("Combined %d series devices.\n", changed);
|
||||
else
|
||||
@@ -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) {
|
||||
@@ -5788,14 +5885,15 @@ Tcl_Obj *
|
||||
#else
|
||||
void
|
||||
#endif
|
||||
PropertyMatch(struct objlist *ob1, int file1,
|
||||
struct objlist *ob2, int file2,
|
||||
PropertyMatch(struct Element *E1, struct Element *E2,
|
||||
int do_print, int do_list, int *retval)
|
||||
{
|
||||
struct nlist *tc1, *tc2;
|
||||
struct objlist *tp1, *tp2, *obn1, *obn2, *tpc;
|
||||
struct objlist *ob1, *ob2, *tp1, *tp2, *obn1, *obn2, *tpc;
|
||||
struct property *kl1, *kl2;
|
||||
struct valuelist *vl1, *vl2;
|
||||
struct NodeList *nl1, *nl2;
|
||||
int file1, file2;
|
||||
int t1type, t2type, run1, run2;
|
||||
int i, mismatches = 0, checked_one;
|
||||
int rval = 1;
|
||||
@@ -5804,6 +5902,12 @@ PropertyMatch(struct objlist *ob1, int file1,
|
||||
Tcl_Obj *proplist = NULL, *mpair, *mlist;
|
||||
#endif
|
||||
|
||||
ob1 = E1->object;
|
||||
ob2 = E2->object;
|
||||
|
||||
file1 = E1->graph;
|
||||
file2 = E2->graph;
|
||||
|
||||
tc1 = LookupCellFile(ob1->model.class, file1);
|
||||
tc2 = LookupCellFile(ob2->model.class, file2);
|
||||
|
||||
@@ -5891,12 +5995,14 @@ PropertyMatch(struct objlist *ob1, int file1,
|
||||
|
||||
/* Check for no-connect pins in merged devices on both sides. */
|
||||
/* Both sides should either have no-connects marked, or neither. */
|
||||
/* (Permutable pins may need to be handled correctly. . . */
|
||||
/* Permutable pins need to be handled correctly. */
|
||||
|
||||
for (tp1 = ob1, tp2 = ob2; (tp1 != NULL) && tp1->type >= FIRSTPIN &&
|
||||
(tp2 != NULL) && tp2->type >= FIRSTPIN; tp1 = tp1->next, tp2 = tp2->next) {
|
||||
for (tp1 = ob1, tp2 = ob2, nl1 = E1->nodelist; tp1 && tp2; tp1 = tp1->next, tp2 = tp2->next) {
|
||||
struct objlist *node1, *node2;
|
||||
|
||||
if ((tp1 != ob1) && (tp1->type <= FIRSTPIN)) break;
|
||||
if ((tp2 != ob2) && (tp2->type <= FIRSTPIN)) break;
|
||||
|
||||
if (file1 == Circuit1->file)
|
||||
node1 = Circuit1->nodename_cache[tp1->node];
|
||||
else
|
||||
@@ -5907,22 +6013,45 @@ PropertyMatch(struct objlist *ob1, int file1,
|
||||
else
|
||||
node2 = Circuit2->nodename_cache[tp2->node];
|
||||
|
||||
if (node1->flags != node2->flags) {
|
||||
struct objlist *tp2b;
|
||||
|
||||
/* Find if there is permutable pin node with matching flags */
|
||||
/* Note that this is not rigorous, and should be better handled. */
|
||||
|
||||
for (tp2b = ob2, nl2 = E2->nodelist; tp2b; tp2b = tp2b->next, nl2 = nl2->next) {
|
||||
if ((tp2b != ob2) && (tp2b->type <= FIRSTPIN)) break;
|
||||
if (tp2b == tp2) continue;
|
||||
if (nl2->pin_magic == nl1->pin_magic) {
|
||||
if (file2 == Circuit1->file)
|
||||
node2 = Circuit1->nodename_cache[tp2b->node];
|
||||
else
|
||||
node2 = Circuit2->nodename_cache[tp2b->node];
|
||||
}
|
||||
if (node1->flags == node2->flags) break;
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: A "no-connect" node (multiple no-connects represented by a
|
||||
* single node) has non-zero flags. A non-node entry in the cache
|
||||
* implies a node with zero flags.
|
||||
*/
|
||||
if (node1->flags != node1->flags) {
|
||||
Fprintf(stdout, " Parallelized instances disagree on pin connections.\n");
|
||||
Fprintf(stdout, " Circuit1 instance %s pin %s connections are %s (%d)\n",
|
||||
if (node1->flags != node2->flags) {
|
||||
if (do_print) {
|
||||
Fprintf(stdout, " Parallelized instances disagree on pin connections.\n");
|
||||
Fprintf(stdout, " Circuit1 instance %s pin %s connections are %s (%d)\n",
|
||||
tp1->instance.name, node1->name,
|
||||
(node1->flags == 0) ? "tied together" : "no connects",
|
||||
node1->flags);
|
||||
Fprintf(stdout, " Circuit2 instance %s pin %s connections are %s (%d)\n",
|
||||
Fprintf(stdout, " Circuit2 instance %s pin %s connections are %s (%d)\n",
|
||||
tp2->instance.name, node2->name,
|
||||
(node2->flags == 0) ? "tied together" : "no connects",
|
||||
node2->flags);
|
||||
}
|
||||
mismatches++;
|
||||
}
|
||||
|
||||
nl1 = nl1->next;
|
||||
}
|
||||
|
||||
// Attempt to organize devices by series and parallel combination
|
||||
@@ -5932,8 +6061,11 @@ PropertyMatch(struct objlist *ob1, int file1,
|
||||
// PropertySortAndCombine can move the first property, so recompute it
|
||||
// for each circuit.
|
||||
|
||||
for (tp1 = ob1; (tp1 != NULL) && tp1->type >= FIRSTPIN; tp1 = tp1->next);
|
||||
for (tp2 = ob2; (tp2 != NULL) && tp2->type >= FIRSTPIN; tp2 = tp2->next);
|
||||
tp1 = tp2 = NULL;
|
||||
if (t1type == PROPERTY)
|
||||
for (tp1 = ob1; (tp1 != NULL) && tp1->type >= FIRSTPIN; tp1 = tp1->next);
|
||||
if (t2type == PROPERTY)
|
||||
for (tp2 = ob2; (tp2 != NULL) && tp2->type >= FIRSTPIN; tp2 = tp2->next);
|
||||
|
||||
// Find name for printing, removing leading slash if needed.
|
||||
inst1 = ob1->instance.name;
|
||||
@@ -5963,12 +6095,16 @@ PropertyMatch(struct objlist *ob1, int file1,
|
||||
if (vl2->type == PROP_ENDLIST) break;
|
||||
if (vl2 == NULL) continue;
|
||||
if (vl2->key == NULL) continue;
|
||||
kl2 = (struct property *)HashLookup(vl2->key, &(tc2->propdict));
|
||||
if (kl2 != NULL) {
|
||||
// Allowed for one instance to be missing "M" or "S".
|
||||
if (!(*matchfunc)(vl2->key, "M") && !(*matchfunc)(vl2->key, "S"))
|
||||
|
||||
// Allowed for one instance to be missing "M" or "S" if the other
|
||||
// has value 1.
|
||||
if (!(*matchfunc)(vl2->key, "M") && !(*matchfunc)(vl2->key, "S")) {
|
||||
kl2 = (struct property *)HashLookup(vl2->key, &(tc2->propdict));
|
||||
if (kl2 != NULL)
|
||||
break; // Property is required
|
||||
}
|
||||
else if (vl2->value.ival != 1)
|
||||
break; // Property M != 1 or S != 1 is a mismatch.
|
||||
}
|
||||
if (vl2->type != PROP_ENDLIST) {
|
||||
mismatches++;
|
||||
@@ -6016,12 +6152,16 @@ PropertyMatch(struct objlist *ob1, int file1,
|
||||
if (vl1->type == PROP_ENDLIST) break;
|
||||
if (vl1 == NULL) continue;
|
||||
if (vl1->key == NULL) continue;
|
||||
kl1 = (struct property *)HashLookup(vl1->key, &(tc1->propdict));
|
||||
if (kl1 != NULL) {
|
||||
// Allowed for one instance to be missing "M" or "S".
|
||||
if (!(*matchfunc)(vl1->key, "M") && !(*matchfunc)(vl1->key, "S"))
|
||||
|
||||
// Allowed for one instance to be missing "M" or "S" if the other
|
||||
// has value 1.
|
||||
if (!(*matchfunc)(vl1->key, "M") && !(*matchfunc)(vl1->key, "S")) {
|
||||
kl1 = (struct property *)HashLookup(vl1->key, &(tc1->propdict));
|
||||
if (kl1 != NULL)
|
||||
break; // Property is required
|
||||
}
|
||||
else if (vl1->value.ival != 1)
|
||||
break; // Property M != 1 or S != 1 is a mismatch.
|
||||
}
|
||||
if (vl1->type != PROP_ENDLIST) {
|
||||
mismatches++;
|
||||
@@ -6052,7 +6192,7 @@ PropertyMatch(struct objlist *ob1, int file1,
|
||||
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;
|
||||
@@ -6073,7 +6213,7 @@ PropertyMatch(struct objlist *ob1, int file1,
|
||||
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)) {
|
||||
@@ -6146,11 +6286,9 @@ PropertyCheck(struct ElementClass *EC, int do_print, int do_list, int *rval)
|
||||
E2 = Etmp;
|
||||
}
|
||||
#ifdef TCL_NETGEN
|
||||
return PropertyMatch(E1->object, E1->graph, E2->object, E2->graph,
|
||||
do_print, do_list, rval);
|
||||
return PropertyMatch(E1, E2, do_print, do_list, rval);
|
||||
#else
|
||||
PropertyMatch(E1->object, E1->graph, E2->object, E2->graph,
|
||||
do_print, do_list, rval);
|
||||
PropertyMatch(E1, E2, do_print, do_list, rval);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -6321,7 +6459,7 @@ int ResolveAutomorphsByPin()
|
||||
int portnum;
|
||||
|
||||
/* Diagnostic */
|
||||
Fprintf(stdout, "Resolving automorphisms by pin name.\n");
|
||||
Fprintf(stdout, "Resolving symmetries by pin name.\n");
|
||||
|
||||
for (NC = NodeClasses; NC != NULL; NC = NC->next) {
|
||||
struct Node *N1, *N2;
|
||||
@@ -6346,6 +6484,8 @@ int ResolveAutomorphsByPin()
|
||||
for (N2 = N1->next; N2 != NULL; N2 = N2->next) {
|
||||
if ((N2->graph != N1->graph) &&
|
||||
(*matchfunc)(N2->object->name, N1->object->name)) {
|
||||
if (Debug == TRUE)
|
||||
Printf("Symmetry group broken by name match (pin %s)\n", N2->object->name);
|
||||
Magic(newhash);
|
||||
N1->hashval = newhash;
|
||||
N2->hashval = newhash;
|
||||
@@ -6381,7 +6521,7 @@ int ResolveAutomorphsByProperty()
|
||||
unsigned long orighash, newhash;
|
||||
|
||||
/* Diagnostic */
|
||||
Fprintf(stdout, "Resolving automorphisms by property value.\n");
|
||||
Fprintf(stdout, "Resolving symmetries by property value.\n");
|
||||
|
||||
for (EC = ElementClasses; EC != NULL; EC = EC->next) {
|
||||
struct Element *E1, *E2;
|
||||
@@ -6419,9 +6559,10 @@ int ResolveAutomorphsByProperty()
|
||||
badmatch = FALSE;
|
||||
for (E2 = E1->next; E2 != NULL; E2 = E2->next) {
|
||||
if (E2->hashval != orighash) continue;
|
||||
PropertyMatch(E1->object, E1->graph, E2->object, E2->graph,
|
||||
FALSE, FALSE, &result);
|
||||
PropertyMatch(E1, E2, FALSE, FALSE, &result);
|
||||
if (result == 0) {
|
||||
if (Debug == TRUE)
|
||||
Printf("Symmetry group split by property (element %s)\n", E2->object->model.class);
|
||||
E2->hashval = newhash;
|
||||
if (E2->graph == E1->graph)
|
||||
C1++;
|
||||
@@ -6488,6 +6629,7 @@ int ResolveAutomorphisms()
|
||||
struct NodeClass *NC;
|
||||
struct Node *N;
|
||||
int C1, C2;
|
||||
int automorphs;
|
||||
|
||||
for (EC = ElementClasses; EC != NULL; EC = EC->next) {
|
||||
struct Element *E1, *E2;
|
||||
@@ -6539,8 +6681,9 @@ int ResolveAutomorphisms()
|
||||
FractureElementClass(&ElementClasses);
|
||||
FractureNodeClass(&NodeClasses);
|
||||
ExhaustiveSubdivision = 1;
|
||||
while (!Iterate() && VerifyMatching() >= 0);
|
||||
return(VerifyMatching());
|
||||
while (!Iterate() && (VerifyMatching() >= 0));
|
||||
|
||||
return VerifyMatching();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
@@ -8115,7 +8258,7 @@ int Compare(char *cell1, char *cell2)
|
||||
|
||||
/* arbitrarily resolve automorphisms */
|
||||
Fprintf(stdout, "\n");
|
||||
Fprintf(stdout, "Resolving automorphisms by arbitrary symmetry breaking:\n");
|
||||
Fprintf(stdout, "Resolving symmetries by arbitrary symmetry breaking:\n");
|
||||
while ((automorphisms = ResolveAutomorphisms()) > 0) ;
|
||||
if (automorphisms == -1) {
|
||||
MatchFail(cell1, cell2);
|
||||
@@ -8214,7 +8357,7 @@ void NETCOMP(void)
|
||||
else {
|
||||
Printf("Netlists match with %d symmetries.\n", automorphisms);
|
||||
while ((automorphisms = ResolveAutomorphisms()) > 0)
|
||||
Printf(" automorphisms = %d.\n", automorphisms);
|
||||
Printf(" symmetries = %d.\n", automorphisms);
|
||||
if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n");
|
||||
else if (automorphisms == -2) Fprintf(stdout, "Port counts do not match.\n");
|
||||
else Printf("Circuits match correctly.\n");
|
||||
@@ -8281,7 +8424,7 @@ void NETCOMP(void)
|
||||
Printf("(c)reate internal data structure\n");
|
||||
Printf("do an (i)teration\n");
|
||||
Printf("(r)un to completion (convergence)\n");
|
||||
Printf("(R)un to completion (resolve automorphisms)\n");
|
||||
Printf("(R)un to completion (resolve symmetries)\n");
|
||||
Printf("(v)erify results\n");
|
||||
Printf("print (a)utomorphisms\n");
|
||||
Printf("equate two (d)evices\n");
|
||||
|
||||
@@ -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);
|
||||
|
||||
+30
-33
@@ -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);
|
||||
}
|
||||
|
||||
@@ -440,13 +441,6 @@ void RemoveShorted(char *class, int file)
|
||||
RecurseCellFileHashTable(removeshorted, file);
|
||||
}
|
||||
|
||||
/* Structure used to keep track of nodes needing checking */
|
||||
|
||||
struct linkednode {
|
||||
int node;
|
||||
struct linkednode *next;
|
||||
};
|
||||
|
||||
/* Remove instances of a deleted class from the database. */
|
||||
/* NOTE: This treats deleted classes as not existing, so it */
|
||||
/* needs to take care of disconnected ports in the same manner */
|
||||
@@ -457,13 +451,22 @@ struct linkednode {
|
||||
int deleteclass(struct hashlist *p, int file)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
struct objlist *ob, *lob, *nob;
|
||||
struct linkednode *checknodes = NULL, *newlnode, *chknode;
|
||||
struct objlist *ob, *lob, *nob, *portnode;
|
||||
unsigned char *checknodes;
|
||||
int i;
|
||||
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
|
||||
if ((file != -1) && (ptr->file != file)) return 0;
|
||||
|
||||
/* Note: This could be made faster by enumerating all times each
|
||||
* node is used during the full pass, then subtracting each time
|
||||
* the node is deleted in a child, then disconnecting all nodes
|
||||
* that ended up with a zero count.
|
||||
*/
|
||||
checknodes = (unsigned char *)CALLOC(ptr->nodename_cache_maxnodenum + 1,
|
||||
sizeof(unsigned char));
|
||||
|
||||
lob = NULL;
|
||||
for (ob = ptr->cell; ob != NULL;) {
|
||||
nob = ob->next;
|
||||
@@ -471,12 +474,8 @@ int deleteclass(struct hashlist *p, int file)
|
||||
if ((*matchfunc)(ob->model.class, OldCell->name)) {
|
||||
HashDelete(ob->instance.name, &(ptr->instdict));
|
||||
while (1) {
|
||||
if (ob->type >= FIRSTPIN) {
|
||||
newlnode = (struct linkednode *)MALLOC(sizeof(struct linkednode));
|
||||
newlnode->node = ob->node;
|
||||
newlnode->next = checknodes;
|
||||
checknodes = newlnode;
|
||||
}
|
||||
if (ob->type >= FIRSTPIN)
|
||||
checknodes[ob->node] = (unsigned char)1;
|
||||
FreeObjectAndHash(ob, ptr);
|
||||
ob = nob;
|
||||
if (ob == NULL) break;
|
||||
@@ -499,26 +498,24 @@ int deleteclass(struct hashlist *p, int file)
|
||||
}
|
||||
}
|
||||
|
||||
while (checknodes != NULL) {
|
||||
struct objlist *portnode = NULL;
|
||||
|
||||
chknode = checknodes;
|
||||
checknodes = checknodes->next;
|
||||
|
||||
for (ob = ptr->cell; ob != NULL; ob = ob->next) {
|
||||
if ((ob->type != PORT) && (portnode == NULL))
|
||||
break;
|
||||
else if ((ob->type == PORT) && (ob->node == chknode->node))
|
||||
portnode = ob;
|
||||
else if ((ob->type >= FIRSTPIN) && (ob->node == chknode->node))
|
||||
break;
|
||||
for (i = 0; i <= ptr->nodename_cache_maxnodenum; i++) {
|
||||
if (checknodes[i] != 0) {
|
||||
portnode = NULL;
|
||||
for (ob = ptr->cell; ob != NULL; ob = ob->next) {
|
||||
if ((ob->type != PORT) && (portnode == NULL))
|
||||
break;
|
||||
else if ((ob->type == PORT) && (ob->node == i))
|
||||
portnode = ob;
|
||||
else if ((ob->type >= FIRSTPIN) && (ob->node == i))
|
||||
break;
|
||||
}
|
||||
if ((ob == NULL) && (portnode != NULL)) {
|
||||
/* Port became disconnected when child was deleted */
|
||||
portnode->node = -1;
|
||||
}
|
||||
}
|
||||
if ((ob == NULL) && (portnode != NULL)) {
|
||||
/* Port became disconnected when child was deleted */
|
||||
portnode->node = -1;
|
||||
}
|
||||
FREE(chknode);
|
||||
}
|
||||
FREE(checknodes);
|
||||
}
|
||||
|
||||
/* Remove all instances of class "class" from the database */
|
||||
|
||||
+11
-9
@@ -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;
|
||||
@@ -206,7 +207,7 @@ struct nlist {
|
||||
char *name;
|
||||
int number; /* number of instances defined */
|
||||
int dumped; /* instance count, and general-purpose marker */
|
||||
unsigned char flags;
|
||||
unsigned short flags;
|
||||
unsigned char class;
|
||||
unsigned long classhash; /* randomized hash value for cell class */
|
||||
struct Permutation *permutes; /* list of permuting pins */
|
||||
@@ -222,17 +223,18 @@ struct nlist {
|
||||
|
||||
/* Defined nlist structure flags */
|
||||
|
||||
#define CELL_MATCHED 0x01 /* cell matched to another */
|
||||
#define CELL_NOCASE 0x02 /* cell is case-insensitive (e.g., SPICE) */
|
||||
#define CELL_TOP 0x04 /* cell is a top-level cell */
|
||||
#define CELL_PLACEHOLDER 0x08 /* cell is a placeholder cell */
|
||||
#define CELL_PROPSMATCHED 0x10 /* properties matched to matching cell */
|
||||
#define CELL_DUPLICATE 0x20 /* cell has a duplicate */
|
||||
#define CELL_MATCHED 0x001 /* cell matched to another */
|
||||
#define CELL_NOCASE 0x002 /* cell is case-insensitive (e.g., SPICE) */
|
||||
#define CELL_TOP 0x004 /* cell is a top-level cell */
|
||||
#define CELL_PLACEHOLDER 0x008 /* cell is a placeholder cell */
|
||||
#define CELL_PROPSMATCHED 0x010 /* properties matched to matching cell */
|
||||
#define CELL_DUPLICATE 0x020 /* cell has a duplicate */
|
||||
#define CELL_VERILOG 0x040 /* cell is verilog module */
|
||||
|
||||
/* Flags for combination allowances and prohibitions */
|
||||
|
||||
#define COMB_SERIES 0x40
|
||||
#define COMB_NO_PARALLEL 0x80
|
||||
#define COMB_SERIES 0x100
|
||||
#define COMB_NO_PARALLEL 0x200
|
||||
|
||||
extern struct nlist *CurrentCell;
|
||||
extern struct objlist *CurrentTail;
|
||||
|
||||
@@ -1783,6 +1783,18 @@ skip_ends:
|
||||
ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */
|
||||
update = 1;
|
||||
}
|
||||
else if (tp->flags & CELL_VERILOG) {
|
||||
if (tp->flags & CELL_PLACEHOLDER) {
|
||||
/* Flag this as an error. To do: Rearrange the verilog instance pins to */
|
||||
/* match the SPICE subcircuit pin order. */
|
||||
Fprintf(stderr, "Error: SPICE subcircuit %s should be read before verilog "
|
||||
"module using it, or pins may not match!\n", subcktname);
|
||||
}
|
||||
else {
|
||||
Fprintf(stderr, "Error: SPICE subcircuit %s redefines a verilog module!\n",
|
||||
subcktname);
|
||||
}
|
||||
}
|
||||
|
||||
/* nexttok is now NULL, scan->name points to class */
|
||||
|
||||
|
||||
+95
-17
@@ -803,6 +803,56 @@ extern void IncludeVerilog(char *, int, struct cellstack **, int);
|
||||
extern void PushStack(char *cellname, struct cellstack **top);
|
||||
extern void PopStack(struct cellstack **top);
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Callback routine for FindInstanceOf() */
|
||||
/* NOTE: This casts a (struct objlist) pointer to a */
|
||||
/* (struct nlist) pointer for the purpose of using */
|
||||
/* RecurseCellHashTable2(). FindInstanceOf() casts it */
|
||||
/* back into a (struct objlist) pointer. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
struct nlist *findInstance(struct hashlist *p, void *clientdata)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
struct objlist *ob;
|
||||
struct nlist *tref = (struct nlist *)clientdata;
|
||||
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
if (ptr->file != tref->file) return NULL;
|
||||
|
||||
ob = LookupInstance(tref->name, ptr);
|
||||
return (struct nlist *)ob;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Routine to find the first instance of a cell */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
struct objlist *FindInstanceOf(struct nlist *tc)
|
||||
{
|
||||
return (struct objlist *)RecurseCellHashTable2(findInstance, (void *)tc);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Given a reference cell pointer tref and a port name */
|
||||
/* portname, check if portname is a port of tref. If */
|
||||
/* not, then call Port() to add one. If tref is NULL, */
|
||||
/* then always add the port. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
void CheckPort(struct objlist *tref, char *portname)
|
||||
{
|
||||
struct objlist *ob;
|
||||
|
||||
if (tref != NULL) {
|
||||
for (ob = CurrentCell->cell; ob && (ob->type == PORT); ob = ob->next) {
|
||||
if ((*matchfunc)(ob->name, portname))
|
||||
return;
|
||||
}
|
||||
}
|
||||
Port(portname);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Read a verilog structural netlist */
|
||||
/*------------------------------------------------------*/
|
||||
@@ -818,7 +868,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
struct keyvalue *kvlist = NULL;
|
||||
char inst[MAX_STR_LEN], model[MAX_STR_LEN], instname[MAX_STR_LEN], portname[MAX_STR_LEN], pkey[MAX_STR_LEN];
|
||||
struct nlist *tp;
|
||||
struct objlist *parent, *sobj, *nobj, *lobj, *pobj;
|
||||
struct objlist *parent, *sobj, *nobj, *lobj, *pobj, *cref;
|
||||
|
||||
inst[MAX_STR_LEN-1] = '\0';
|
||||
model[MAX_STR_LEN-1] = '\0';
|
||||
@@ -938,6 +988,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
InputParseError(stderr);
|
||||
}
|
||||
in_module = (char)1;
|
||||
cref = NULL;
|
||||
|
||||
/* Save pointer to current cell */
|
||||
if (CurrentCell != NULL)
|
||||
@@ -949,6 +1000,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
||||
tp = LookupCellFile(nexttok, filenum);
|
||||
hasports = (char)0;
|
||||
|
||||
/* Check for name conflict with duplicate cell names */
|
||||
/* This may mean that the cell was used before it was */
|
||||
@@ -986,23 +1038,48 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
CellDef(nexttok, filenum);
|
||||
tp = LookupCellFile(nexttok, filenum);
|
||||
}
|
||||
else if (tp != NULL) { /* Make a new definition for an empty cell */
|
||||
FreePorts(nexttok);
|
||||
CellDelete(nexttok, filenum); /* This removes any PLACEHOLDER flag */
|
||||
else if (tp != NULL) { /* Cell exists, but as a placeholder */
|
||||
struct nlist *tptmp = NULL;
|
||||
char ctemp[8];
|
||||
int n = 0;
|
||||
|
||||
/* This redefines a placeholder module to an unused temporary cell name */
|
||||
while (1) {
|
||||
sprintf(ctemp, "%d", n);
|
||||
tptmp = LookupCellFile(ctemp, filenum);
|
||||
if (tptmp == NULL) break;
|
||||
n++;
|
||||
}
|
||||
CellRehash(nexttok, ctemp, filenum);
|
||||
tptmp = LookupCellFile(ctemp, filenum);
|
||||
|
||||
/* Create a new module definition */
|
||||
CellDef(model, filenum);
|
||||
tp = LookupCellFile(model, filenum);
|
||||
|
||||
/* Find an instance of this module in the netlist */
|
||||
cref = FindInstanceOf(tp);
|
||||
if ((cref != NULL) && (cref->name != NULL)) {
|
||||
hasports = (char)1;
|
||||
/* Copy ports from the original parent cell to the new parent cell */
|
||||
for (pobj = tptmp->cell; pobj && (pobj->type == PORT); pobj = pobj->next)
|
||||
Port(pobj->name);
|
||||
}
|
||||
/* Remove the original cell definition */
|
||||
FreePorts(ctemp);
|
||||
CellDelete(ctemp, filenum); /* This removes any PLACEHOLDER flag */
|
||||
}
|
||||
else if (tp == NULL) { /* Completely new cell, no name conflict */
|
||||
CellDef(model, filenum);
|
||||
tp = LookupCellFile(model, filenum);
|
||||
}
|
||||
|
||||
hasports = (char)0;
|
||||
inlined_decls = (char)0;
|
||||
|
||||
if (tp != NULL) {
|
||||
struct bus wb, *nb;
|
||||
|
||||
tp->flags |= CELL_VERILOG;
|
||||
PushStack(tp->name, CellStackPtr);
|
||||
|
||||
/* Need to support both types of I/O lists: Those */
|
||||
@@ -1071,7 +1148,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
if (GetBusTok(&wb) != 0) {
|
||||
// Didn't parse as a bus, so wing it
|
||||
wb.start = wb.end = -1;
|
||||
Port(nexttok);
|
||||
CheckPort(cref, nexttok);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1079,13 +1156,13 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
if (wb.start > wb.end) {
|
||||
for (i = wb.start; i >= wb.end; i--) {
|
||||
sprintf(portname, "%s[%d]", nexttok, i);
|
||||
Port(portname);
|
||||
CheckPort(cref, portname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = wb.start; i <= wb.end; i++) {
|
||||
sprintf(portname, "%s[%d]", nexttok, i);
|
||||
Port(portname);
|
||||
CheckPort(cref, portname);
|
||||
}
|
||||
}
|
||||
/* Also register this port as a bus */
|
||||
@@ -1097,7 +1174,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
wb.start = wb.end = -1;
|
||||
}
|
||||
else {
|
||||
Port(nexttok);
|
||||
CheckPort(cref, nexttok);
|
||||
}
|
||||
}
|
||||
hasports = 1;
|
||||
@@ -1153,7 +1230,7 @@ skip_endmodule:
|
||||
if (GetBusTok(&wb) != 0) {
|
||||
// Didn't parse as a bus, so wing it
|
||||
wb.start = wb.end = -1;
|
||||
Port(nexttok);
|
||||
CheckPort(cref, nexttok);
|
||||
}
|
||||
}
|
||||
else if (!match(nexttok, ",")) {
|
||||
@@ -1161,13 +1238,13 @@ skip_endmodule:
|
||||
if (wb.start > wb.end) {
|
||||
for (i = wb.start; i >= wb.end; i--) {
|
||||
sprintf(portname, "%s[%d]", nexttok, i);
|
||||
Port(portname);
|
||||
CheckPort(cref, portname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = wb.start; i <= wb.end; i++) {
|
||||
sprintf(portname, "%s[%d]", nexttok, i);
|
||||
Port(portname);
|
||||
CheckPort(cref, portname);
|
||||
}
|
||||
}
|
||||
/* Also register this port as a bus */
|
||||
@@ -1178,7 +1255,7 @@ skip_endmodule:
|
||||
wb.start = wb.end = -1;
|
||||
}
|
||||
else {
|
||||
Port(nexttok);
|
||||
CheckPort(cref, nexttok);
|
||||
}
|
||||
}
|
||||
hasports = 1;
|
||||
@@ -1194,6 +1271,7 @@ skip_endmodule:
|
||||
InputParseError(stderr);
|
||||
}
|
||||
in_module = (char)0;
|
||||
cref = NULL;
|
||||
|
||||
if (*CellStackPtr) PopStack(CellStackPtr);
|
||||
if (*CellStackPtr) ReopenCellDef((*CellStackPtr)->cellname, filenum);
|
||||
@@ -2115,7 +2193,7 @@ nextinst:
|
||||
sprintf(localnet, "_noconnect_%d_", localcount++);
|
||||
Node(localnet);
|
||||
join(localnet, obptr->name);
|
||||
Fprintf(stderr,
|
||||
Fprintf(stdout,
|
||||
"Note: Implicit pin %s in instance %s of %s in cell %s\n",
|
||||
obpinname, locinst, modulename, CurrentCell->name);
|
||||
}
|
||||
@@ -2207,8 +2285,8 @@ nextinst:
|
||||
char tempname[MAX_STR_LEN];
|
||||
int maxnode;
|
||||
|
||||
/* This pin was probably implicit in the first call */
|
||||
/* and so it needs to be added to the definition. */
|
||||
/* This pin was probably implicit in the first call */
|
||||
/* and so it needs to be added to the definition. */
|
||||
|
||||
ReopenCellDef(modulename, filenum);
|
||||
Port(scan->name);
|
||||
@@ -2265,7 +2343,7 @@ nextinst:
|
||||
sprintf(tempname, "_noconnect_%d_", localcount++);
|
||||
Node(tempname);
|
||||
join(tempname, nobj->name);
|
||||
Fprintf(stderr, "Note: Implicit pin %s in instance "
|
||||
Fprintf(stdout, "Note: Implicit pin %s in instance "
|
||||
"%s of %s in cell %s\n",
|
||||
scan->name, sobj->instance.name,
|
||||
modulename, CurrentCell->name);
|
||||
|
||||
+33
-7
@@ -2228,7 +2228,13 @@ _netcmp_compare(ClientData clientData,
|
||||
Fprintf(stdout, "\nCircuit 1 cell %s is a black box; will not flatten "
|
||||
"Circuit 2\n", name1);
|
||||
}
|
||||
else if (hascontents1 || hascontents2) {
|
||||
else if (!hascontents1 && !hascontents2 && (tp1->flags & CELL_PLACEHOLDER)
|
||||
&& (tp2->flags & CELL_PLACEHOLDER)) {
|
||||
/* Two empty subcircuits, don't flatten anything */
|
||||
Fprintf(stdout, "\nCircuit 1 cell %s and Circuit 2 cell %s are black"
|
||||
" boxes.\n", name1, name2);
|
||||
}
|
||||
else {
|
||||
FlattenUnmatched(tp1, name1, 1, 0);
|
||||
FlattenUnmatched(tp2, name2, 1, 0);
|
||||
DescribeContents(name1, fnum1, name2, fnum2);
|
||||
@@ -2241,10 +2247,6 @@ _netcmp_compare(ClientData clientData,
|
||||
DescribeContents(name1, fnum1, name2, fnum2);
|
||||
}
|
||||
}
|
||||
else { /* Two empty subcircuits */
|
||||
Fprintf(stdout, "\nCircuit 1 cell %s and Circuit 2 cell %s are black"
|
||||
" boxes.\n", name1, name2);
|
||||
}
|
||||
CreateTwoLists(name1, fnum1, name2, fnum2, dolist);
|
||||
|
||||
// Return the names of the two cells being compared, if doing "compare
|
||||
@@ -3375,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 */
|
||||
@@ -3413,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;
|
||||
|
||||
@@ -3840,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} ...");
|
||||
|
||||
Reference in New Issue
Block a user