Compare commits

...
25 Commits
Author SHA1 Message Date
Tim Edwards fb7876c7a6 Merge branch 'master' into netgen-1.5 2021-07-03 03:00:13 -04:00
Tim Edwards a984ac1a4d Corrected an error in a recent update that handles the case where
a final parallel or series combination needs to be done but there
are still multiple property records.  The multiplier was being
incorrectly applied twice, causing an automatic mismatch in
parameter values.
2021-07-02 10:51:44 -04:00
Tim Edwards e31caa3500 Merge branch 'master' into netgen-1.5 2021-06-26 03:00:10 -04:00
Tim Edwards 738c1f7b37 Corrected an error probably introduced into the code with the handling
of multiple devices during flattening, that will skip over a node
record at the end of a subcircuit call being flattened and therefore
remove it from the netlist.
2021-06-25 13:16:42 -04:00
Tim Edwards c3cf6c3765 Made another correction that prevents netgen from truncating the pin
list that it prints in the side-by-side element mismatch comparison
for an element, when there is no node record associated with the pin
connection.  This makes the output clearer.
2021-06-25 12:35:11 -04:00
Tim Edwards 99dcc20c0a Corrected MatchPins so that it returns an error code of 0 when pins are
swapped, so that if pin names are swapped on the top level, netgen will
report this as a final error message.  Otherwise, the mismatch is only
reported back in the pin list where it is not obvious.
2021-06-25 10:27:24 -04:00
Tim Edwards c1355bee45 Merge branch 'master' into netgen-1.5 2021-06-25 03:00:10 -04:00
Tim Edwards 4bbc496749 Corrected an error in the "run converge" and "run resolve" methods.
The algorithm is to run without exhaustive subdivision until the
last step because this is much faster.  The final iteration must
be run with exhaustive subdivision on, or else it is possible to
have cells with swapped pins matching.  The routines that resolve
automorphisms were setting exhaustive subdivision for the final
iteration.  But simple "run converge" and "run resolve" were not.
2021-06-24 14:53:24 -04:00
Tim Edwards 4fb8b59a2f Merge branch 'master' into netgen-1.5 2021-06-19 03:00:10 -04:00
Tim Edwards c4f03eabaf Corrected an error not checking for running off the end of a list,
in code from a recent commit.
2021-06-18 21:23:21 -04:00
Tim Edwards 6a555ad6ed Added a missing method from parallel/series matching which is to
add properties across multiple property records in the last matching
step, if there are still multiple properties and the values can be
combined.  Previously, netgen had been assuming that there would only
be one property record left at this point, which is not true.  This
shows up particularly for BSIM fingered devices, since "nf" is
ignored.
2021-06-18 10:44:44 -04:00
Tim Edwards 626faf22f9 Merge branch 'master' into netgen-1.5 2021-06-17 03:00:10 -04:00
Tim Edwards 1c5457e180 Corrected a minor issue that cropped up today in which the search
for file extensions is greedy and picks the first matching extension
starting at the front of the string, such that, e.g., "file.ext.spice"
is interpreted as a ".ext" file and not a ".spice" file.
2021-06-16 15:20:39 -04:00
Tim Edwards 7d246c36a6 Corrected an issue with flattening when the instances to be flattened
run to the end of the list of circuit elements.  Also corrected
another issue caused by the flag to denote multiple no-connect pins,
which can be on an instance pin and so cannot share the data from the
instance record.
2021-06-16 14:32:14 -04:00
Tim Edwards 550234dce5 Merge branch 'master' into netgen-1.5 2021-06-15 03:00:36 -04:00
Tim Edwards 92dfa74403 Corrected an issue that was caused by introducing a type of parallel
device with one or more no-connect pins.  The flag that indicates a
no-connect pin was checked incorrectly, potentially causing obscure
and misleading property mismatch messages to be generated.
2021-06-14 14:30:10 -04:00
Tim Edwards a4c0028706 Merge branch 'master' into netgen-1.5 2021-06-13 03:00:32 -04:00
Tim Edwards d53541d1d3 Correction to previous commit (failed to link to last pointer
after processing properties during flattening).
2021-06-12 20:15:55 -04:00
Tim Edwards 57b2d21221 Modified the way flattening is done to account for multiple property
records, which were being ignored.  This really only applies to
parallel subcircuits being flattened.  To flatten correctly requires
that any circuit with N property records must be flattened into the
parent at least N times.  To do:  Must look for M > 1 records in the
properties and flatten (M - 1) additional times.
2021-06-12 17:37:50 -04:00
Tim Edwards e7ae84bbc8 Merge branch 'master' into netgen-1.5 2021-06-10 03:00:09 -04:00
Tim Edwards dfabdaa367 Modified the JSON output so that missing pins which do not match
unconnected pins in the other netlist are marked as "(no pin)"
rather than "(no matching pin)".  This allows a script parsint the
JSON file (e.g., count_lvs.py from qflow) to distinguish between a
real pin error and one that can be ignored.
2021-06-09 09:34:02 -04:00
Tim Edwards c5c1306f6a Corrected a minor error where the property mismatch check outputs
an error message while doing a non-final iteration, where all
output is supposed to be suppressed.
2021-06-09 09:20:45 -04:00
Tim Edwards 43c018f3bc Merge branch 'master' into netgen-1.5 2021-06-09 03:00:10 -04:00
Tim Edwards 0614461c84 Modified MatchPins so that pin mismatches on nets that are not
connected to anything are once again ignored (the prior commit
to prevent netgen from not reporting swapped pins as an error
overcorrected).
2021-06-08 17:25:17 -04:00
Tim Edwards 6e94886b65 Messed up basic pin comparison between black-box vs. non-black-box
subcircuit situations in the last commit.  This commit fixes it.
2021-06-08 16:52:57 -04:00
8 changed files with 430 additions and 265 deletions
+1 -1
View File
@@ -1 +1 @@
1.5.183
1.5.192
+241 -191
View File
@@ -254,9 +254,10 @@ void flattenCell(char *name, int file)
int flattenInstancesOf(char *name, int fnum, char *instance)
{
struct objlist *ParentParams;
struct objlist *ParentProps;
struct objlist *ParentProps, *CurrentProp;
struct objlist *NextObj, *LastObj, *prepp;
struct objlist *ChildObjList;
struct objlist *ChildObjList, *ChildListEnd;
struct objlist *ChildStart, *ChildEnd, *ParentEnd, *ParentNext;
struct nlist *ThisCell;
struct nlist *ChildCell;
struct objlist *tmp, *ob2, *ob3;
@@ -334,215 +335,264 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
ParentProps = ParentProps->next) {
if (ParentProps->type == PROPERTY) break;
}
if (ParentProps && (ParentProps->type != PROPERTY)) ParentProps = NULL;
/* not primitive, so need to flatten this instance */
notdone = 1;
/* if this is a new instance, flatten it */
/* if (ChildCell->dumped == 0) flattenCell(ParentParams->model.class, file); */
ChildObjList = CopyObjList(ChildCell->cell, 1);
numflat++;
/* update node numbers in child to unique numbers */
oldmax = 0;
for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next)
if (tmp->node > oldmax) oldmax = tmp->node;
if (nextnode <= oldmax) nextnode = oldmax + 1;
for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next)
if (tmp->node <= oldmax && tmp->node > 0) {
if (Debug) Printf("Update node %d --> %d\n", tmp->node, nextnode);
UpdateNodeNumbers(ChildObjList, tmp->node, nextnode);
nextnode++;
}
/* copy nodenumbers of ports from parent */
ob2 = ParentParams;
for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next)
if (IsPort(tmp)) {
if (tmp->node > 0) {
if (ob2->node == -1) {
// Before commiting to attaching to a unconnected node, see
// if there is another node in ParentParams with the same
// name and a valid node number. If so, connect them. In
// the broader case, it may be necessary to consider all
// nodes, not just those with node == -1, and call join()
// here to update all node numbers in the parent cell.
// In that case, a more efficient method is needed for
// tracking same-name ports.
for (ob3 = ParentParams; ob3 && ob3->type >= FIRSTPIN; ob3 = ob3->next) {
if (ob3 == ob2) continue;
if ((*matchfunc)(ob3->name, ob2->name) && ob3->node != -1) {
ob2->node = ob3->node;
break;
}
}
}
if (Debug) {
// Printf(" Sealing port: %d to node %d\n", tmp->node, ob2->node);
Printf("Update node %d --> %d\n", tmp->node, ob2->node);
}
UpdateNodeNumbers(ChildObjList, tmp->node, ob2->node);
}
/* in pathological cases, the lengths of the port lists may
* change. This is an error, but that is no reason to allow
* the code to core dump. We avoid this by placing a
* superfluous check on ob2->type
*/
if (ob2 != NULL)
ob2 = ob2->next;
if (ob2 == NULL) break;
}
/* Using name == NULL to indicate that a .ext file is being */
/* flattened on the fly. This is quick & dirty. */
if (name != NULL) {
/* delete all port elements from child */
while ((ChildObjList != NULL) && IsPort(ChildObjList)) {
/* delete all ports at beginning of list */
if (Debug) Printf("deleting leading port from child\n");
tmp = ChildObjList->next;
// FreeObjectAndHash(ChildObjList, ChildCell);
FreeObject(ChildObjList);
ChildObjList = tmp;
}
tmp = ChildObjList;
while (tmp && (tmp->next != NULL)) {
if (IsPort(tmp->next)) {
ob2 = (tmp->next)->next;
if (Debug) Printf("deleting a port from child\n");
// FreeObjectAndHash(tmp->next, ChildCell);
FreeObject(tmp->next);
tmp->next = ob2;
}
else tmp = tmp->next;
}
if (ParentProps && (ParentProps->type != PROPERTY)) {
ParentProps = NULL;
CurrentProp = NULL;
}
else
CurrentProp = ParentProps;
/* for each element in child, prepend 'prefix' */
/* Find the end record of the parent cell and save it */
for (ParentEnd = (ParentProps) ? ParentProps : ParentParams;
ParentEnd && ParentEnd->next &&
/* Stop on a node or the next instance */
((ParentEnd->next->type > FIRSTPIN) ||
(ParentEnd->next->type == PROPERTY));
ParentEnd = ParentEnd->next);
/* Not primitive, so need to flatten this instance */
notdone = 1;
/* Loop over property records. Need to flatten once per */
/* property record (or more, if property has M > 1) */
ob2 = NULL;
ChildObjList = NULL;
ChildListEnd = NULL;
while (1) {
ChildStart = CopyObjList(ChildCell->cell, 1);
numflat++;
/* Find the end record of the child cell and save it */
for (ChildEnd = ChildStart; ChildEnd && ChildEnd->next;
ChildEnd = ChildEnd->next);
if (ChildListEnd == NULL) ChildListEnd = ChildEnd;
/* update node numbers in child to unique numbers */
oldmax = 0;
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next)
if (tmp->node > oldmax) oldmax = tmp->node;
if (nextnode <= oldmax) nextnode = oldmax + 1;
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next)
if (tmp->node <= oldmax && tmp->node > 0) {
if (Debug) Printf("Update node %d --> %d\n", tmp->node, nextnode);
UpdateNodeNumbers(ChildStart, tmp->node, nextnode);
nextnode++;
}
/* copy nodenumbers of ports from parent */
ob2 = ParentParams;
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) {
if (IsPort(tmp)) {
if (tmp->node > 0) {
if (ob2->node == -1) {
// Before commiting to attaching to a unconnected node, see
// if there is another node in ParentParams with the same
// name and a valid node number. If so, connect them. In
// the broader case, it may be necessary to consider all
// nodes, not just those with node == -1, and call join()
// here to update all node numbers in the parent cell.
// In that case, a more efficient method is needed for
// tracking same-name ports.
for (ob3 = ParentParams; ob3 && ob3->type >= FIRSTPIN;
ob3 = ob3->next) {
if (ob3 == ob2) continue;
if ((*matchfunc)(ob3->name, ob2->name) && ob3->node != -1) {
ob2->node = ob3->node;
break;
}
}
}
if (Debug) {
// Printf(" Sealing port: %d to node %d\n", tmp->node, ob2->node);
Printf("Update node %d --> %d\n", tmp->node, ob2->node);
}
UpdateNodeNumbers(ChildStart, tmp->node, ob2->node);
}
/* in pathological cases, the lengths of the port lists may
* change. This is an error, but that is no reason to allow
* the code to core dump. We avoid this by placing a
* superfluous check on ob2->type
*/
if (ob2 != NULL) ob2 = ob2->next;
if (ob2 == NULL) break;
}
}
/* Using name == NULL to indicate that a .ext file is being */
/* flattened on the fly. This is quick & dirty. */
if (name != NULL) {
/* delete all port elements from child */
while ((ChildStart != NULL) && IsPort(ChildStart)) {
/* delete all ports at beginning of list */
if (Debug) Printf("deleting leading port from child\n");
tmp = ChildStart->next;
FreeObject(ChildStart);
ChildStart = tmp;
}
tmp = ChildStart;
while (tmp && (tmp->next != NULL)) {
if (IsPort(tmp->next)) {
ob2 = (tmp->next)->next;
if (Debug) Printf("deleting a port from child\n");
FreeObject(tmp->next);
tmp->next = ob2;
}
else tmp = tmp->next;
}
if (ChildStart == NULL) {
if (ChildListEnd == ChildEnd) ChildListEnd = NULL;
ChildEnd = NULL;
}
}
/* for each element in child, prepend 'prefix' */
#if !OLDPREFIX
/* replaces all the sprintf's below */
strcpy(tmpstr,ParentParams->instance.name);
strcat(tmpstr,SEPARATOR);
prefixlength = strlen(tmpstr);
/* replaces all the sprintf's below */
strcpy(tmpstr,ParentParams->instance.name);
strcat(tmpstr,SEPARATOR);
prefixlength = strlen(tmpstr);
#endif
for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next) {
if (tmp->type == PROPERTY)
continue;
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) {
if (tmp->type == PROPERTY)
continue;
else if (IsGlobal(tmp)) {
/* Keep the name but search for node of same name in parent */
/* and replace the node number, if found. */
else if (IsGlobal(tmp)) {
/* Keep the name but search for node of same name in parent */
/* and replace the node number, if found. */
for (ob2 = ThisCell->cell; ob2 != NULL; ob2 = ob2->next) {
/* Type in parent may be a port, not a global */
if (ob2->type == tmp->type || ob2->type == PORT) {
if ((*matchfunc)(tmp->name, ob2->name)) {
if (ob2->node >= 0) {
// Replace all child objects with this node number
rnodenum = tmp->node;
for (ob3 = ChildObjList; ob3 != NULL; ob3 = ob3->next) {
if (ob3->node == rnodenum)
ob3->node = ob2->node;
}
break;
}
}
}
}
// Don't hash this if the parent had a port of this name
if (!ob2 || ob2->type != PORT)
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
continue;
}
for (ob2 = ThisCell->cell; ob2 != NULL; ob2 = ob2->next) {
/* Type in parent may be a port, not a global */
if (ob2->type == tmp->type || ob2->type == PORT) {
if ((*matchfunc)(tmp->name, ob2->name)) {
if (ob2->node >= 0) {
// Replace all child objects with this node number
rnodenum = tmp->node;
for (ob3 = ChildStart; ob3 != NULL; ob3 = ob3->next) {
if (ob3->node == rnodenum)
ob3->node = ob2->node;
}
break;
}
}
}
}
// Don't hash this if the parent had a port of this name
if (!ob2 || ob2->type != PORT)
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
continue;
}
#if OLDPREFIX
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
tmp->name);
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
tmp->name);
#else
strcpy(tmpstr+prefixlength,tmp->name);
strcpy(tmpstr+prefixlength,tmp->name);
#endif
if (Debug) Printf("Renaming %s to %s\n", tmp->name, tmpstr);
FreeString(tmp->name);
tmp->name = strsave(tmpstr);
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
if ((tmp->type != NODE) && (tmp->instance.name != NULL)) {
if (Debug) Printf("Renaming %s to %s\n", tmp->name, tmpstr);
FreeString(tmp->name);
tmp->name = strsave(tmpstr);
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
if ((tmp->type != NODE) && (tmp->instance.name != NULL)) {
#if OLDPREFIX
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
tmp->instance.name);
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
tmp->instance.name);
#else
strcpy(tmpstr+prefixlength,tmp->instance.name);
strcpy(tmpstr+prefixlength,tmp->instance.name);
#endif
FreeString(tmp->instance.name);
tmp->instance.name = strsave(tmpstr);
if (tmp->type == FIRSTPIN)
HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict));
}
}
/* Do property inheritance */
if (ParentProps) {
for (ob2 = ChildObjList; ob2 != NULL; ob2=ob2->next) {
/* If the parent cell has properties to declare, then */
/* pass them on to children. Use globals only if the */
/* spiceparams dictionary is active (during file reading */
/* only). */
if (ob2->type == PROPERTY)
ReduceExpressions(ob2, ParentProps, ChildCell,
(spiceparams.hashtab == NULL) ? 0 : 1);
FreeString(tmp->instance.name);
tmp->instance.name = strsave(tmpstr);
if (tmp->type == FIRSTPIN)
HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict));
}
}
/* Do property inheritance */
/* NOTE: Need to do: Check properties for M > 1 and decrement
* and repeat without moving CurrentProp
*/
if (CurrentProp) {
for (ob2 = ChildStart; ob2 != NULL; ob2=ob2->next) {
/* If the parent cell has properties to declare, then */
/* pass them on to children. Use globals only if the */
/* spiceparams dictionary is active (during file */
/* reading only). */
if (ob2->type == PROPERTY)
ReduceExpressions(ob2, CurrentProp, ChildCell,
(spiceparams.hashtab == NULL) ? 0 : 1);
}
/* Repeat for each property record, as each property represents a
* unique instance that must be flattened individually.
*/
CurrentProp = CurrentProp->next;
if ((CurrentProp == NULL) || (CurrentProp->type != PROPERTY)) break;
}
else break;
/* Put the child cell at the start of ChildObjList */
ChildEnd->next = ChildObjList;
ChildObjList = ChildStart;
}
/* splice instance out of parent */
if ((ParentParams == ThisCell->cell) && (ChildObjList == NULL)) {
ThisCell->cell = ob2; /* Child cell was empty */
tmp = ob2;
/* Put the child cell at the start of ChildObjList */
if (ChildEnd) {
ChildEnd->next = ChildObjList;
ChildObjList = ChildStart;
}
else {
/* Pull the instance out of the parent */
if ((ParentParams != ThisCell->cell) || (ChildObjList != NULL)) {
if (ParentParams == ThisCell->cell) {
/* ParentParams are the very first thing in the list */
ThisCell->cell = ChildObjList;
for (ob2 = ChildObjList; ob2 && ob2->next != NULL; ob2 = ob2->next) ;
/* ParentParams are the very first thing in the list */
ThisCell->cell = ChildObjList;
}
else {
/* find ParentParams in ThisCell list. In most cases, LastObj */
/* should be pointing to it. */
if (LastObj && (LastObj->next == ParentParams)) {
ob2 = LastObj;
}
else {
for (ob2 = LastObj; ob2 && ob2->next != ParentParams; ob2=ob2->next);
if (ob2 == NULL) {
/* It should not happen that LastObj is ahead of ParentParams */
/* but just in case, this long loop will find it. */
for (ob2 = ThisCell->cell; ob2 && ob2->next != ParentParams; ob2=ob2->next);
}
}
if (ob2)
for (ob2->next = ChildObjList; ob2->next != NULL; ob2 = ob2->next) ;
else if (ChildObjList) {
/* find ParentParams in ThisCell list. In most cases, LastObj */
/* should be pointing to it. */
if (LastObj && (LastObj->next == ParentParams)) {
LastObj->next = ChildObjList;
}
else {
for (ob2 = LastObj; ob2 && ob2->next != ParentParams;
ob2 = ob2->next);
if (ob2 == NULL) {
/* It should not happen that LastObj is ahead of ParentParams */
/* but just in case, this long loop will find it. */
for (ob2 = ThisCell->cell; ob2 && ob2->next != ParentParams;
ob2 = ob2->next);
}
ob2->next = ChildObjList;
}
}
/* now, ob2 is last element in child list, so skip and reclaim parent */
else {
/* The child was completely optimized out, so close list around it */
LastObj->next = ParentEnd->next;
}
tmp = ParentParams;
do {
tmp = tmp->next;
} while ((tmp != NULL) && ((tmp->type > FIRSTPIN) || (tmp->type == PROPERTY)));
if (ob2) ob2->next = tmp;
/* Link end of child list into the parent */
if (ChildListEnd && ParentEnd)
ChildListEnd->next = ParentEnd->next;
}
while (ParentParams != tmp) {
ob2 = ParentParams->next;
FreeObjectAndHash(ParentParams, ThisCell);
ParentParams = ob2;
ParentNext = (ParentEnd) ? ParentEnd->next : NULL;
while (ParentParams != ParentNext) {
ob2 = ParentParams->next;
FreeObjectAndHash(ParentParams, ThisCell);
ParentParams = ob2;
}
NextObj = ParentParams;
} /* repeat until no more instances found */
@@ -1538,13 +1588,13 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
}
}
if (match) {
if (ecomp->cell1) {
if (ecomp->cell1 && (ecomp->num1 > 0)) {
Fprintf(stdout, "Flattening instances of %s in cell %s"
" makes a better match\n", ecomp->cell1->name,
name1);
flattenInstancesOf(name1, file1, ecomp->cell1->name);
}
if (ecomp->cell2) {
if (ecomp->cell2 && (ecomp->num2 > 0)) {
Fprintf(stdout, "Flattening instances of %s in cell %s"
" makes a better match\n", ecomp->cell2->name,
name2);
+173 -63
View File
@@ -620,15 +620,15 @@ struct FormattedList *FormatBadElementFragment(struct Element *E)
for (elems = nodes[i]->node->elementlist; elems != NULL;
elems = elems->next)
count++;
elemlist->flist[k].count = count;
if (*ob->name != *ob->instance.name) // e.g., "port_match_error"
elemlist->flist[k].name = ob->name;
else
elemlist->flist[k].name = ob->name + strlen(ob->instance.name) + 1;
elemlist->flist[k].permute = (char)1;
k++;
}
elemlist->flist[k].count = count;
if (*ob->name != *ob->instance.name) // e.g., "port_match_error"
elemlist->flist[k].name = ob->name;
else
elemlist->flist[k].name = ob->name + strlen(ob->instance.name) + 1;
elemlist->flist[k].permute = (char)1;
k++;
}
else { /* handle multiple permutable pins */
struct objlist *ob2;
@@ -665,13 +665,16 @@ struct FormattedList *FormatBadElementFragment(struct Element *E)
struct ElementList *elems;
count = 0;
if (nodes[j]->node == NULL) continue; // ?
for (elems = nodes[j]->node->elementlist; elems != NULL;
elems = elems->next)
count++;
if (nodes[j]->node == NULL) /* Under what condition is the node NULL? */
count++;
else {
for (elems = nodes[j]->node->elementlist; elems != NULL;
elems = elems->next)
count++;
}
if (count >= maxcount) {
maxcount = count;
maxindex = j;
maxcount = count;
maxindex = j;
}
}
}
@@ -4697,7 +4700,7 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
struct objlist *ob2, *obt;
struct property *kl, *m_rec, **plist;
unsigned char **clist;
struct valuelist ***vlist, *vl, *vl2, *newvlist;
struct valuelist ***vlist, *vl, *vl2, *newvlist, critval;
proplinkptr plink, ptop;
int pcount, p, i, j, k, pmatch, ival, ctype;
double dval;
@@ -4785,12 +4788,12 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
else if (kl != NULL) {
vlist[kl->idx][i] = vl;
if (series == FALSE) {
if (kl->merge & (MERGE_P_ADD | MERGE_P_PAR))
if (kl->merge & (MERGE_P_ADD | MERGE_P_PAR | MERGE_P_CRIT))
clist[kl->idx][i] = kl->merge &
(MERGE_P_ADD | MERGE_P_PAR | MERGE_P_CRIT);
}
else if (series == TRUE) {
if (kl->merge & (MERGE_S_ADD | MERGE_S_PAR))
if (kl->merge & (MERGE_S_ADD | MERGE_S_PAR | MERGE_S_CRIT))
clist[kl->idx][i] = kl->merge &
(MERGE_S_ADD | MERGE_S_PAR | MERGE_S_CRIT);
}
@@ -4945,24 +4948,44 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
// (if any)
if (comb == TRUE) {
int mult;
int mult, cidx = -1;
struct valuelist *avl, *cvl = NULL;
critval.type = PROP_ENDLIST;
critval.value.dval = 0.0;
for (i = 0; i < run; i++) {
avl = NULL;
if (vlist[0][i] == NULL) continue;
mult = vlist[0][i]->value.ival;
if (mult > 1) {
changed = 0;
changed = 0;
/* For all properties that are not M, S, or crit, */
/* combine as specified by the merge type of the property. */
/* For all properties that are not M, S, or crit, */
/* combine as specified by the merge type of the property. */
for (p = 1; p < pcount; p++) {
vl = vlist[p][i];
ctype = clist[p][i];
for (p = 1; p < pcount; p++) {
vl = vlist[p][i];
ctype = clist[p][i];
/* critical properties never combine */
if ((series == TRUE) && (ctype & MERGE_S_CRIT)) continue;
if ((series == FALSE) && (ctype & MERGE_P_CRIT)) continue;
/* critical properties never combine, but track them */
if ((series == TRUE) && (ctype & MERGE_S_CRIT)) {
if ((vl->type != critval.type) || (vl->value.dval != critval.value.dval))
{
critval.type = vl->type;
critval.value = vl->value;
cidx = i;
}
continue;
}
if ((series == FALSE) && (ctype & MERGE_P_CRIT)) {
if ((vl->type != critval.type) || (vl->value.dval != critval.value.dval))
{
critval.type = vl->type;
critval.value = vl->value;
cidx = i;
}
continue;
}
if (mult > 1) {
if (ctype & (MERGE_S_ADD | MERGE_P_ADD)) {
if (vl->type == PROP_INTEGER)
vl->value.ival *= mult;
@@ -4982,14 +5005,68 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
vlist[0][i]->value.ival = 1;
changed += mult;
}
if (changed > 0) {
if (series)
Printf("Combined %d series devices.\n", changed);
else
Printf("Combined %d parallel devices.\n", changed);
}
if (ctype & (MERGE_S_ADD | MERGE_P_ADD | MERGE_S_PAR | MERGE_P_PAR))
avl = vl;
}
if (cidx == i) cvl = avl;
/* Sorting should have put all records with the same critical */
/* value together sequentially. So if there are still */
/* multiple property records, then merge them into the first */
/* record with the same critical property value. */
if ((i > 0) && (cidx >= 0) && (cidx < i)) {
for (p = 1; p < pcount; p++) {
vl = vlist[p][i];
ctype = clist[p][i];
if (ctype & (MERGE_S_ADD | MERGE_P_ADD)) {
vlist[0][i]->value.ival = 0; /* set M to 0 */
if (cvl && (cvl->type == PROP_INTEGER))
{
if (vl->type == PROP_INTEGER)
cvl->value.ival += vl->value.ival;
else {
cvl->type = PROP_DOUBLE;
cvl->value.dval = (double)cvl->value.ival + vl->value.dval;
}
}
else if ((cvl && vl->type == PROP_DOUBLE))
{
if (vl->type == PROP_INTEGER)
cvl->value.dval += (double)vl->value.ival;
else
cvl->value.dval += vl->value.dval;
}
}
else if (ctype & (MERGE_S_PAR | MERGE_P_PAR)) {
vlist[0][i]->value.ival = 0; /* set M to 0 */
/* To do parallel combination, both types need to
* be double, so recast them if they are integer.
*/
if (vl->type == PROP_INTEGER) {
vl->type = PROP_DOUBLE;
vl->value.dval = (double)(vl->value.ival);
}
if (cvl && (cvl->type == PROP_INTEGER)) {
cvl->type = PROP_DOUBLE;
cvl->value.dval = (double)cvl->value.ival;
}
if ((cvl && (vl->type == PROP_DOUBLE))) {
cvl->value.dval =
sqrt(cvl->value.dval * cvl->value.dval
+ vl->value.dval * vl->value.dval);
}
}
}
}
}
if (changed > 0) {
if (series)
Printf("Combined %d series devices.\n", changed);
else
Printf("Combined %d parallel devices.\n", changed);
}
}
}
@@ -5595,10 +5672,10 @@ PropertyMatch(struct objlist *ob1, int file1,
int do_print, int do_list, int *retval)
{
struct nlist *tc1, *tc2;
struct objlist *tp1, *tp2, *obn1, *obn2;
struct objlist *tp1, *tp2, *obn1, *obn2, *tpc;
struct property *kl1, *kl2;
struct valuelist *vl1, *vl2;
int t1type, t2type;
int t1type, t2type, run1, run2;
int i, mismatches = 0, checked_one;
int rval = 1;
char *inst1, *inst2;
@@ -5691,13 +5768,12 @@ PropertyMatch(struct objlist *ob1, int file1,
#endif
}
/* WIP---Check for no-connect pins in merged devices on both sides. */
/* 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. . . */
for (tp1 = ob1, tp2 = ob2; (tp1 != NULL) && tp1->type >= FIRSTPIN &&
(tp2 != NULL) && tp2->type >= FIRSTPIN; tp1 = tp1->next, tp2 = tp2->next)
{
(tp2 != NULL) && tp2->type >= FIRSTPIN; tp1 = tp1->next, tp2 = tp2->next) {
struct objlist *node1, *node2;
if (file1 == Circuit1->file)
@@ -5710,17 +5786,20 @@ PropertyMatch(struct objlist *ob1, int file1,
else
node2 = Circuit2->nodename_cache[tp2->node];
if (node1->instance.flags != node2->instance.flags)
{
/* 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",
tp1->instance.name, node1->name,
(node1->instance.flags == 0) ? "tied together" : "no connects",
node1->instance.flags);
(node1->flags == 0) ? "tied together" : "no connects",
node1->flags);
Fprintf(stdout, " Circuit2 instance %s pin %s connections are %s (%d)\n",
tp2->instance.name, node2->name,
(node2->instance.flags == 0) ? "tied together" : "no connects",
node2->instance.flags);
(node2->flags == 0) ? "tied together" : "no connects",
node2->flags);
mismatches++;
}
}
@@ -5746,10 +5825,12 @@ PropertyMatch(struct objlist *ob1, int file1,
if ((t1type != PROPERTY) && (checked_one == TRUE)) {
// t2 has more property records than t1, and they did not get
// merged equally by PropertySortAndCombine().
Fprintf(stdout, "Circuit 1 parallel/series network does not match"
if (do_print) {
Fprintf(stdout, "Circuit 1 parallel/series network does not match"
" Circuit 2\n");
DumpNetwork(ob1, 1);
DumpNetwork(ob2, 2);
DumpNetwork(ob1, 1);
DumpNetwork(ob2, 2);
}
mismatches++;
}
else if (t1type != PROPERTY) {
@@ -5851,13 +5932,19 @@ PropertyMatch(struct objlist *ob1, int file1,
inst2, FALSE, FALSE, &multmatch, NULL);
if (multmatch == 1) {
/* Final attempt: Reduce M to 1 on both devices */
PropertyOptimize(tp1, tc1, 1, FALSE, TRUE);
PropertyOptimize(tp2, tc2, 1, FALSE, TRUE);
run1 = run2 = 0;
for (tpc = tp1; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run1++;
for (tpc = tp2; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run2++;
PropertyOptimize(tp1, tc1, run1, FALSE, TRUE);
PropertyOptimize(tp2, tc2, run2, FALSE, TRUE);
}
else if (multmatch == 2) {
/* Final attempt: Reduce S to 1 on both devices */
PropertyOptimize(tp1, tc1, 1, TRUE, TRUE);
PropertyOptimize(tp2, tc2, 1, TRUE, TRUE);
run1 = run2 = 0;
for (tpc = tp1; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run1++;
for (tpc = tp2; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run2++;
PropertyOptimize(tp1, tc1, run1, TRUE, TRUE);
PropertyOptimize(tp2, tc2, run2, TRUE, TRUE);
}
#ifdef TCL_NETGEN
mlist =
@@ -6804,6 +6891,11 @@ int reorderpins(struct hashlist *p, int file)
"Ordering will be arbitrary.\n", tc2->name);
for (ob = ptr->cell; ob != NULL; ) {
/* Catch badness */
if (ob->next && (ob->next->node > 100000)) {
Fprintf(stdout, "Bad.\n");
}
if (ob->type == FIRSTPIN) {
if ((*matchfunc)(ob->model.class, tc2->name)) {
char *sptr = ob->instance.name;
@@ -6822,6 +6914,7 @@ int reorderpins(struct hashlist *p, int file)
nodes[ob2->model.port] = ob->node;
names[ob2->model.port] = ob->name;
}
ob = ob->next;
ob2 = ob2->next;
if (i < numports - 1) {
@@ -7131,8 +7224,13 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
snprintf(ostr, left_col_end, "%s", obn->name);
if ((*matchfunc)(obn->name, obp->name))
snprintf(ostr + left_col_end + 1, left_col_end, "%s", obp->name);
else
else {
snprintf(ostr + left_col_end + 1, left_col_end, "%s **Mismatch**", obp->name);
/* Pins with different names are on different nets,
* so this should trigger an error return code.
*/
result = 0;
}
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
@@ -7245,7 +7343,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
/* so apply only to black-box (CELL_PLACEHOLDER) entries. */
/* (Semi-hack: Allow "!" global flag) */
if ((tc1->flags & CELL_PLACEHOLDER) && (tc2->flags & CELL_PLACEHOLDER)) {
if (((tc1->flags & CELL_PLACEHOLDER) && (tc2->flags & CELL_PLACEHOLDER)) ||
(NodeClasses == NULL)) {
ob1 = tc1->cell;
bangptr1 = strrchr(ob1->name, '!');
if (bangptr1 && (*(bangptr1 + 1) == '\0'))
@@ -7341,15 +7440,6 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
Fprintf(stderr, "No netlist match for cell %s pin %s\n",
tc2->name, ob2->name);
}
#ifdef TCL_NETGEN
if (dolist) {
Tcl_ListObjAppendElement(netgeninterp, plist1,
Tcl_NewStringObj("(no matching pin)", -1));
Tcl_ListObjAppendElement(netgeninterp, plist2,
Tcl_NewStringObj(ob2->name, -1));
}
#endif
result = 0;
/* Before making a proxy pin, check to see if */
/* flattening instances has left a port with a */
@@ -7366,8 +7456,28 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if ((obt == NULL) && (notempty == 1)) {
ob2->node = -2; // Will run this through cleanuppins
needclean2 = 1;
#ifdef TCL_NETGEN
if (dolist) {
Tcl_ListObjAppendElement(netgeninterp, plist1,
Tcl_NewStringObj("(no pin)", -1));
Tcl_ListObjAppendElement(netgeninterp, plist2,
Tcl_NewStringObj(ob2->name, -1));
}
#endif
continue;
}
else if (notempty == 1) {
/* Flag this as an error */
result = 0;
#ifdef TCL_NETGEN
if (dolist) {
Tcl_ListObjAppendElement(netgeninterp, plist1,
Tcl_NewStringObj("(no matching pin)", -1));
Tcl_ListObjAppendElement(netgeninterp, plist2,
Tcl_NewStringObj(ob2->name, -1));
}
#endif
}
ob2->model.port = numnodes++; // Assign a port order
/* Add a proxy pin to tc1 */
+3 -1
View File
@@ -896,7 +896,9 @@ char *ReadNetlist(char *fname, int *fnum)
/* make first pass looking for extension */
for (index = 0; formats[index].extension != NULL; index++) {
if (strstr(fname, formats[index].extension) != NULL) {
int extlen = strlen(formats[index].extension);
int flen = strlen(fname);
if (!strcmp(fname + flen - extlen, formats[index].extension)) {
return (*(formats[index].proc))(fname, fnum);
}
}
+3 -2
View File
@@ -1352,7 +1352,8 @@ void Node(char *name)
tp->name = strsave(name);
tp->type = NODE; /* internal node type */
tp->model.class = NULL;
tp->instance.flags = 0;
tp->instance.name = NULL;
tp->flags = 0;
tp->node = -1; /* null node */
tp->next = NULL;
AddToCurrentCell (tp);
@@ -3259,7 +3260,7 @@ int CombineParallel(char *model, int file)
if ((ob2->node >= 0) && (nodecount[ob2->node] == 1))
{
nob = (tp->nodename_cache)[ob2->node];
nob->instance.flags = NO_CONNECT;
nob->flags = NO_CONNECT;
strcat(pptr, "_nc");
}
else
+4 -6
View File
@@ -975,10 +975,8 @@ struct objlist *CopyObjList(struct objlist *oldlist, unsigned char doforall)
newob->model.class = NULL;
else
newob->model.class = strsave(tmp->model.class);
if (newob->type == NODE)
newob->instance.flags = tmp->instance.flags;
else
newob->instance.name = (tmp->instance.name) ?
newob->flags = tmp->flags;
newob->instance.name = (tmp->instance.name) ?
strsave(tmp->instance.name) : NULL;
}
newob->node = tmp->node;
@@ -1098,8 +1096,8 @@ void FreeObject(struct objlist *ob)
FREE(ob->instance.props);
}
}
else if (ob->type != NODE) {
/* All other records except NODE, which uses this for flags */
else {
/* All other records */
if (ob->instance.name != NULL) FreeString(ob->instance.name);
}
if (ob->model.class != NULL) FreeString(ob->model.class);
+1 -1
View File
@@ -162,9 +162,9 @@ struct objlist {
union {
char *name; /* unique name for the instance, or */
/* (string) value of property for properties */
int flags; /* Used by NODE type to flag isolated net */
struct valuelist *props; /* Property record */
} instance;
unsigned char flags; /* Used by NODE type to flag isolated net */
int node; /* the electrical node number of the port/node/pin */
struct objlist *next;
};
+4
View File
@@ -2428,6 +2428,8 @@ _netcmp_run(ClientData clientData,
else {
enable_interrupt();
while (!Iterate() && !InterruptPending);
ExhaustiveSubdivision = 1;
while (!Iterate() && !InterruptPending);
if (dolist) {
result = _netcmp_verify(clientData, interp, 2, objv - 1);
}
@@ -2446,6 +2448,8 @@ _netcmp_run(ClientData clientData,
else {
enable_interrupt();
while (!Iterate() && !InterruptPending);
ExhaustiveSubdivision = 1;
while (!Iterate() && !InterruptPending);
automorphisms = VerifyMatching();
if (automorphisms == -1)
Fprintf(stdout, "Netlists do not match.\n");