Compare commits

...
11 Commits
Author SHA1 Message Date
Tim Edwards 535b8285e9 Merge branch 'master' into netgen-1.5 2022-12-20 02:00:03 -05:00
Tim Edwards 28a2950439 Modified netgen output to not print information about combining
individual components in parallel and series as it reduces the
networks.  This information is available in total in the cell
summary.
2022-12-19 14:37:11 -05:00
Tim Edwards 1e1d506697 Merge branch 'master' into netgen-1.5 2022-12-16 02:00:03 -05:00
Tim Edwards 013fff9f37 (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).
2022-12-15 21:34:56 -05:00
Tim Edwards 4edaf0813d Merge branch 'master' into netgen-1.5 2022-11-17 02:00:01 -05:00
Tim Edwards 2292ab813b Corrected a badly implemented routine that can cause very long
run-times on large projects where a lot of cells need to be
deleted.
2022-11-16 12:37:05 -05:00
Tim Edwards a4ae5ed989 Merge branch 'master' into netgen-1.5 2022-11-05 02:00:01 -04:00
Tim Edwards 7e8508db53 Additional correction to the property match subroutine to better
check instances with permutable pins when checking parallelized
instances with disconnected pins vs. mutually connected pins.
2022-11-04 20:40:37 -04:00
Tim Edwards c9f7b24e0f Found an error in property matching causing weird errors in the
LVS result.  The property matching was failing to match (M=1) to
(M!=1) if M was not registered as a property name (which it often
isn't).  This would allow devices with different numbers of
instances in parallel to be put in the same matching group,
which then could later identify as a mismatch if the instances
were checked in a different order.
2022-11-04 12:07:21 -04:00
Tim Edwards d850586a14 Merge branch 'master' into netgen-1.5 2022-11-03 02:00:03 -04:00
Tim Edwards 95605ebbd4 Prevented checks from automatically treating two empty cells as
black boxes.  The check was supposed to check that both empty
cells really are black box entries.
2022-11-02 09:48:39 -04:00
9 changed files with 445 additions and 141 deletions
+1 -1
View File
@@ -1 +1 @@
1.5.239
1.5.244
+217 -74
View File
@@ -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");
+45
View File
@@ -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. */
/*----------------------------------------------------------------------*/
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+12
View File
@@ -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
View File
@@ -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
View File
@@ -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} ...");