mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-22 14:07:07 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e0371e09b | ||
|
|
395f857a82 | ||
|
|
9e59048731 | ||
|
|
7889e2ae73 | ||
|
|
8c7d2ae239 | ||
|
|
e361640947 | ||
|
|
56b4174646 | ||
|
|
ccf2dc23c9 | ||
|
|
f8ea27d8e8 | ||
|
|
ef914e8d46 | ||
|
|
f9cc4d3db6 | ||
|
|
d8eefdad9a | ||
|
|
2cdf3c450f |
+8
-6
@@ -1391,7 +1391,7 @@ SurveyCell(struct nlist *tc, struct hashdict *compdict, int file1, int file2, in
|
||||
/* */
|
||||
/* If there is a mismatch between instances of low- */
|
||||
/* level devices, determine if the mismatches can be */
|
||||
/* resolved by parallel/serial combining, according to */
|
||||
/* resolved by parallel/series combining, according to */
|
||||
/* combination rules. */
|
||||
/* */
|
||||
/* Return the number of modifications made. */
|
||||
@@ -1659,7 +1659,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
ecomp = (ECompare *)HashFirst(&compdict);
|
||||
while (ecomp != NULL) {
|
||||
if ((ecomp->num1 != ecomp->num2) && (ecomp->cell1 != NULL) &&
|
||||
(ecomp->cell1->class == CLASS_RES)) {
|
||||
((ecomp->cell1->class == CLASS_RES) ||
|
||||
(ecomp->cell1->class == CLASS_VSOURCE))) {
|
||||
int node1 = -1, node2 = -1;
|
||||
lob = NULL;
|
||||
for (ob1 = tc1->cell; ob1; ) {
|
||||
@@ -1703,7 +1704,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
if (found) break;
|
||||
}
|
||||
if (found) {
|
||||
Fprintf(stdout, "Removing zero-valued device"
|
||||
Fprintf(stdout, "Removing zero-valued device "
|
||||
"%s from cell %s makes a better match\n",
|
||||
tsub1->name,
|
||||
tc1->name);
|
||||
@@ -1763,7 +1764,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
// Repeat the last section for the other circuit
|
||||
|
||||
if ((ecomp->num1 != ecomp->num2) && (ecomp->cell2 != NULL) &&
|
||||
(ecomp->cell2->class == CLASS_RES)) {
|
||||
((ecomp->cell2->class == CLASS_RES) ||
|
||||
(ecomp->cell2->class == CLASS_VSOURCE))) {
|
||||
int node1 = -1, node2 = -1;
|
||||
lob = NULL;
|
||||
for (ob2 = tc2->cell; ob2; ) {
|
||||
@@ -1807,7 +1809,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
if (found) break;
|
||||
}
|
||||
if (found) {
|
||||
Fprintf(stdout, "Removing zero-valued device"
|
||||
Fprintf(stdout, "Removing zero-valued device "
|
||||
"%s from cell %s makes a better match\n",
|
||||
tsub2->name,
|
||||
tc2->name);
|
||||
@@ -1917,7 +1919,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
char *dstr = NULL;
|
||||
tc2 = LookupCellFile(ob2->model.class, ecomp0X->cell2->file);
|
||||
if (tc2->flags & CELL_DUPLICATE) {
|
||||
dstr = strstr(ob1->model.class, "[[");
|
||||
dstr = strstr(ob2->model.class, "[[");
|
||||
if (dstr) *dstr = '\0';
|
||||
}
|
||||
ncomp = (ECompare *)HashInt2Lookup(ob2->model.class,
|
||||
|
||||
+325
-227
@@ -500,7 +500,7 @@ void SummarizeDataStructures(void)
|
||||
if (E->graph == Circuit1->file) cell1++;
|
||||
else cell2++;
|
||||
}
|
||||
Printf("Circuit 1 contains %d elements, Circuit 2 contains %d elements.",
|
||||
Printf("Circuit 1 contains %d devices, Circuit 2 contains %d devices.",
|
||||
cell1, cell2);
|
||||
if (cell1 != cell2) Printf(" *** MISMATCH ***");
|
||||
Printf("\n");
|
||||
@@ -518,12 +518,12 @@ void SummarizeDataStructures(void)
|
||||
if (N->elementlist == NULL) orphan2++;
|
||||
}
|
||||
}
|
||||
Printf("Circuit 1 contains %d nodes, Circuit 2 contains %d nodes.",
|
||||
Printf("Circuit 1 contains %d nets, Circuit 2 contains %d nets.",
|
||||
cell1, cell2);
|
||||
if (cell1 != cell2) Printf(" *** MISMATCH ***");
|
||||
Printf("\n");
|
||||
if (orphan1 || orphan2) {
|
||||
Printf("Circuit 1 contains %d orphan nodes, Circuit 2 contains %d orphans.");
|
||||
Printf("Circuit 1 contains %d orphan nets, Circuit 2 contains %d orphans.");
|
||||
if (orphan1 != orphan2) Printf(" *** MISMATCH ***");
|
||||
Printf("\n");
|
||||
}
|
||||
@@ -2076,7 +2076,7 @@ struct Node *CreateNodeList(char *name, short graph)
|
||||
* in sequence to link up 'subelement' field of ElementList,
|
||||
* then 'node' field of NodeList structures.
|
||||
*
|
||||
* Return the number of devices combined by serial/parallel merging
|
||||
* Return the number of devices combined by series/parallel merging
|
||||
*/
|
||||
|
||||
int CreateLists(char *name, short graph)
|
||||
@@ -2102,7 +2102,7 @@ int CreateLists(char *name, short graph)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parallel and serial combinations. Run until networks of */
|
||||
/* Parallel and series combinations. Run until networks of */
|
||||
/* devices are resolved into a single device with the network */
|
||||
/* represented by a number of property records. */
|
||||
|
||||
@@ -2112,19 +2112,21 @@ int CreateLists(char *name, short graph)
|
||||
total += pcnt;
|
||||
if (ppass > 0 && pcnt == 0) break;
|
||||
for (spass = 0; ; spass++) {
|
||||
scnt = CombineSerial(name, graph);
|
||||
scnt = CombineSeries(name, graph);
|
||||
total += scnt;
|
||||
if (scnt == 0) break;
|
||||
}
|
||||
if (spass == 0) break;
|
||||
}
|
||||
/* Uncomment this for series/parallel network diagnostics */
|
||||
/* DumpNetworkAll(name, graph); */
|
||||
|
||||
Elements = CreateElementList(name, graph);
|
||||
Nodes = CreateNodeList(name, graph);
|
||||
if (LookupElementList == NULL) return total;
|
||||
|
||||
ElementScan = NULL;
|
||||
NListScan = NULL; /* just to stop the compiler from bitching */
|
||||
NListScan = NULL;
|
||||
for (ob = tp->cell; ob != NULL; ob = ob->next) {
|
||||
if (ob->type == FIRSTPIN) {
|
||||
if (ElementScan == NULL) ElementScan = Elements;
|
||||
@@ -2221,7 +2223,7 @@ struct Node *CreateNodeList(char *name, short graph)
|
||||
* in sequence to link up 'subelement' field of ElementList,
|
||||
* then 'node' field of NodeList structures.
|
||||
*
|
||||
* Return the number of devices combined by serial/parallel merging
|
||||
* Return the number of devices combined by series/parallel merging
|
||||
*/
|
||||
|
||||
int CreateLists(char *name, short graph)
|
||||
@@ -2250,7 +2252,7 @@ int CreateLists(char *name, short graph)
|
||||
|
||||
ConnectAllNodes(name, graph);
|
||||
|
||||
/* Parallel and serial combinations. Run until networks of */
|
||||
/* Parallel and series combinations. Run until networks of */
|
||||
/* devices are resolved into a single device with the network */
|
||||
/* represented by a number of property records. */
|
||||
|
||||
@@ -2260,12 +2262,14 @@ int CreateLists(char *name, short graph)
|
||||
total += pcnt;
|
||||
if (ppass > 0 && pcnt == 0) break;
|
||||
for (spass = 0; ; spass++) {
|
||||
scnt = CombineSerial(name, graph);
|
||||
scnt = CombineSeries(name, graph);
|
||||
total += scnt;
|
||||
if (scnt == 0) break;
|
||||
}
|
||||
if (spass == 0) break;
|
||||
}
|
||||
/* Uncomment this for series/parallel network diagnostics */
|
||||
/* DumpNetworkAll(name, graph); */
|
||||
|
||||
E = CreateElementList(name, graph);
|
||||
N = CreateNodeList(name, graph);
|
||||
@@ -3464,7 +3468,7 @@ void CreateTwoLists(char *name1, int file1, char *name2, int file2, int dolist)
|
||||
}
|
||||
|
||||
if (modified > 0) {
|
||||
Printf("Circuit was modified by parallel/serial device merging.\n");
|
||||
Printf("Circuit was modified by parallel/series device merging.\n");
|
||||
Printf("New circuit summary:\n\n");
|
||||
/* print preliminary statistics */
|
||||
Printf("Contents of circuit 1: ");
|
||||
@@ -3685,18 +3689,19 @@ int Iterate(void)
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Combine properties of ob1 starting at property idx1 up to */
|
||||
/* property (idx1 + run1), where devices match critical serial */
|
||||
/* property (idx1 + run1), where devices match critical series */
|
||||
/* values and can be combined by summing over the "S" record. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
int serial_optimize(struct objlist *ob1, struct nlist *tp1, int idx1, int run1)
|
||||
int series_optimize(struct objlist *ob1, struct nlist *tp1, int idx1,
|
||||
int run1, int comb)
|
||||
{
|
||||
struct objlist *obn;
|
||||
int i;
|
||||
|
||||
obn = ob1;
|
||||
for (i = 0; i < idx1; i++) obn = obn->next;
|
||||
return PropertyOptimize(obn, tp1, run1, TRUE);
|
||||
return PropertyOptimize(obn, tp1, run1, TRUE, comb);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
@@ -3705,7 +3710,7 @@ int serial_optimize(struct objlist *ob1, struct nlist *tp1, int idx1, int run1)
|
||||
/* idx2 to (idx2 + run2). run1 is always larger than run2. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
int serial_combine(struct objlist *ob1, struct nlist *tp1, int idx1, int run1,
|
||||
int series_combine(struct objlist *ob1, struct nlist *tp1, int idx1, int run1,
|
||||
struct objlist *ob2, struct nlist *tp2, int idx2, int run2)
|
||||
{
|
||||
struct objlist *obn, *obp;
|
||||
@@ -3717,17 +3722,13 @@ int serial_combine(struct objlist *ob1, struct nlist *tp1, int idx1, int run1,
|
||||
obp = ob2;
|
||||
for (i = 0; i < idx2; i++) obp = obp->next;
|
||||
|
||||
// for (j = 0; j < run2; j++) {
|
||||
// for (i = 0; i < run1; i++) {
|
||||
// }
|
||||
// }
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
typedef struct _propsort {
|
||||
double value;
|
||||
int idx;
|
||||
unsigned char flags;
|
||||
struct objlist *ob;
|
||||
} propsort;
|
||||
|
||||
@@ -3747,25 +3748,27 @@ static int compsort(const void *p1, const void *p2)
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Sort properties of ob1 starting at property idx1 up to */
|
||||
/* property (idx1 + run). Use serial critical property for */
|
||||
/* sorting. Multiply critical property by S before sort. */
|
||||
/* property (idx1 + run). Use series critical property for */
|
||||
/* sorting. Combine properties by S before sort. Note that */
|
||||
/* use of "S" implies that the devices are the same in all */
|
||||
/* properties. */
|
||||
/* ob1 is the record before the first property. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
void serial_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
{
|
||||
struct objlist *obn, *obp;
|
||||
propsort *proplist;
|
||||
struct property *kl;
|
||||
struct valuelist *vl;
|
||||
int i, p, sval;
|
||||
struct valuelist *vl, *sl;
|
||||
int i, p, sval, merge_type;
|
||||
double cval;
|
||||
|
||||
obn = ob1->next;
|
||||
for (i = 0; i < idx1; i++) obn = obn->next;
|
||||
|
||||
// Create a structure of length (run) to hold critical property
|
||||
// value and index. Then sort that list, then use the sorted
|
||||
// Create a structure of length (run) to hold property value
|
||||
// and index. Then sort that list, then use the sorted
|
||||
// indexes to sort the actual property linked list.
|
||||
|
||||
proplist = (propsort *)MALLOC(run * sizeof(propsort));
|
||||
@@ -3774,22 +3777,34 @@ void serial_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
sval = 1;
|
||||
cval = 0.0;
|
||||
for (i = 0; i < run; i++) {
|
||||
merge_type = MERGE_NONE;
|
||||
for (p = 0;; p++) {
|
||||
vl = &(obp->instance.props[p]);
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
if (vl->key == NULL) continue;
|
||||
if (!strcmp(vl->key, "S"))
|
||||
if (!strcmp(vl->key, "S")) {
|
||||
sval = vl->value.ival;
|
||||
sl = vl;
|
||||
}
|
||||
else {
|
||||
kl = (struct property *)HashLookup(vl->key, &(tp1->propdict));
|
||||
if (kl && (kl->merge == MERGE_SER_CRIT))
|
||||
if (kl && (kl->merge & MERGE_S_CRIT)) {
|
||||
if (vl->type == PROP_INTEGER)
|
||||
cval = (double)vl->value.ival;
|
||||
else
|
||||
cval = vl->value.dval;
|
||||
merge_type = kl->merge & (MERGE_S_ADD | MERGE_S_PAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
proplist[i].value = (double)sval * cval;
|
||||
if (merge_type == MERGE_S_ADD) {
|
||||
proplist[i].value = cval * (double)sval;
|
||||
sl->value.ival = 1;
|
||||
}
|
||||
else if (merge_type == MERGE_S_PAR) {
|
||||
proplist[i].value = cval / (double)sval;
|
||||
sl->value.ival = 1;
|
||||
}
|
||||
proplist[i].idx = i;
|
||||
proplist[i].ob = obp;
|
||||
obp = obp->next;
|
||||
@@ -3816,14 +3831,15 @@ void serial_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
/* record. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
int parallel_optimize(struct objlist *ob1, struct nlist *tp1, int idx1, int run1)
|
||||
int parallel_optimize(struct objlist *ob1, struct nlist *tp1, int idx1,
|
||||
int run1, int comb)
|
||||
{
|
||||
struct objlist *obn;
|
||||
int i;
|
||||
|
||||
obn = ob1;
|
||||
for (i = 0; i < idx1; i++) obn = obn->next;
|
||||
return PropertyOptimize(obn, tp1, run1, FALSE);
|
||||
return PropertyOptimize(obn, tp1, run1, FALSE, comb);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
@@ -3844,11 +3860,6 @@ int parallel_combine(struct objlist *ob1, struct nlist *tp1, int idx1, int run1,
|
||||
obp = ob2;
|
||||
for (i = 0; i < idx2; i++) obp = obp->next;
|
||||
|
||||
// for (j = 0; j < run2; j++) {
|
||||
// for (i = 0; i < run1; i++) {
|
||||
// }
|
||||
// }
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -3864,8 +3875,8 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
struct objlist *obn, *obp;
|
||||
propsort *proplist;
|
||||
struct property *kl;
|
||||
struct valuelist *vl;
|
||||
int i, p, sval, has_crit = FALSE;
|
||||
struct valuelist *vl, *ml;
|
||||
int i, p, mval, merge_type, has_crit = FALSE;
|
||||
char *subs_crit = NULL;
|
||||
double cval;
|
||||
|
||||
@@ -3887,18 +3898,21 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
proplist = (propsort *)MALLOC(run * sizeof(propsort));
|
||||
|
||||
obp = obn;
|
||||
sval = 1;
|
||||
mval = 1;
|
||||
cval = 0.0;
|
||||
for (i = 0; i < run; i++) {
|
||||
merge_type = MERGE_NONE;
|
||||
for (p = 0;; p++) {
|
||||
vl = &(obp->instance.props[p]);
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
if (vl->key == NULL) continue;
|
||||
if (!strcmp(vl->key, "S"))
|
||||
sval = vl->value.ival;
|
||||
if (!strcmp(vl->key, "M")) {
|
||||
mval = vl->value.ival;
|
||||
ml = vl;
|
||||
}
|
||||
kl = (struct property *)HashLookup(vl->key, &(tp1->propdict));
|
||||
if (kl == NULL) continue; /* Ignored property */
|
||||
if (kl->merge == MERGE_ADD_CRIT) {
|
||||
if (kl->merge & MERGE_P_CRIT) {
|
||||
has_crit = TRUE;
|
||||
if ((vl->type == PROP_STRING || vl->type == PROP_EXPRESSION) &&
|
||||
(kl->type != vl->type))
|
||||
@@ -3911,9 +3925,17 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
+ (double)vl->value.string[1] / 10.0;
|
||||
else
|
||||
cval = vl->value.dval;
|
||||
merge_type = kl->merge & (MERGE_P_ADD | MERGE_P_PAR);
|
||||
}
|
||||
}
|
||||
proplist[i].value = (double)sval * cval;
|
||||
if (merge_type == MERGE_P_ADD) {
|
||||
proplist[i].value = cval * (double)mval;
|
||||
ml->value.ival = 1;
|
||||
}
|
||||
else if (merge_type == MERGE_P_PAR) {
|
||||
proplist[i].value = cval / (double)mval;
|
||||
ml->value.ival = 1;
|
||||
}
|
||||
proplist[i].idx = i;
|
||||
proplist[i].ob = obp;
|
||||
obp = obp->next;
|
||||
@@ -3922,15 +3944,18 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
if (has_crit == FALSE) {
|
||||
/* If no critical property was specified, then choose the first one found */
|
||||
/* and recalculate all the proplist values. */
|
||||
sval = 1;
|
||||
mval = 1;
|
||||
obp = obn;
|
||||
merge_type = MERGE_NONE;
|
||||
for (i = 0; i < run; i++) {
|
||||
for (p = 0;; p++) {
|
||||
vl = &(obp->instance.props[p]);
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
if (vl->key == NULL) continue;
|
||||
if (!strcmp(vl->key, "S"))
|
||||
sval = vl->value.ival;
|
||||
if (!strcmp(vl->key, "M")) {
|
||||
mval = vl->value.ival;
|
||||
ml = vl;
|
||||
}
|
||||
kl = (struct property *)HashLookup(vl->key, &(tp1->propdict));
|
||||
if (kl == NULL) continue; /* Ignored property */
|
||||
if (subs_crit == NULL)
|
||||
@@ -3947,9 +3972,17 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
+ (double)vl->value.string[1] / 10.0;
|
||||
else
|
||||
cval = vl->value.dval;
|
||||
merge_type = kl->merge & (MERGE_P_ADD | MERGE_P_PAR);
|
||||
}
|
||||
}
|
||||
proplist[i].value = (double)sval * cval;
|
||||
if (merge_type == MERGE_P_ADD) {
|
||||
proplist[i].value = cval * (double)mval;
|
||||
ml->value.ival = 1;
|
||||
}
|
||||
else if (merge_type == MERGE_P_PAR) {
|
||||
proplist[i].value = cval / (double)mval;
|
||||
ml->value.ival = 1;
|
||||
}
|
||||
obp = obp->next;
|
||||
}
|
||||
}
|
||||
@@ -3970,11 +4003,11 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Attempt to match two property lists representing serial/ */
|
||||
/* Attempt to match two property lists representing series/ */
|
||||
/* parallel combinations of devices. Where the number of */
|
||||
/* devices is not equal, try to reduce the one with more */
|
||||
/* devices to match. If there are the same number of parallel */
|
||||
/* or serial devices, check if they match better by swapping. */
|
||||
/* or series devices, check if they match better by swapping. */
|
||||
/* The goal is to get two property lists that can be checked by */
|
||||
/* 1-to-1 matching in PropertyMatch(). */
|
||||
/*--------------------------------------------------------------*/
|
||||
@@ -3987,7 +4020,7 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
||||
|
||||
int p, n;
|
||||
int run, cnt, idx1, idx2, max1, max2;
|
||||
int icount1, icount2, changed;
|
||||
int icount1, icount2, changed, result;
|
||||
char *netwk1, *netwk2;
|
||||
char *c1, *c2;
|
||||
struct valuelist *vl;
|
||||
@@ -4001,6 +4034,10 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
||||
iterations++;
|
||||
changed = 0;
|
||||
|
||||
/* Remove group tags if they no longer contain series devices */
|
||||
while (remove_group_tags(pre1));
|
||||
while (remove_group_tags(pre2));
|
||||
|
||||
// How many property records are there?
|
||||
// If there is only one property record in each instance then
|
||||
// there is nothing to be sorted.
|
||||
@@ -4061,8 +4098,8 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
||||
strcat(netwk2, "D");
|
||||
}
|
||||
|
||||
// Printf("Diagnostic: network1 is \"%s\" "
|
||||
// "network2 is \"%s\"\n", netwk1, netwk2);
|
||||
/* Printf("Diagnostic: network1 is \"%s\" "
|
||||
"network2 is \"%s\"\n", netwk1, netwk2); */
|
||||
|
||||
/* Method to resolve any network to the largest solution that */
|
||||
/* matches both sides. Use the netwk1, netwk2 strings to determine */
|
||||
@@ -4075,7 +4112,7 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
||||
/* in the other. If non-summing parameters of interest match, */
|
||||
/* then merge all devices that can be merged until both sides */
|
||||
/* have the same number of devices. */
|
||||
/* 2) Find serial devices that have more elements in one circuit */
|
||||
/* 2) Find series devices that have 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 have the same number of devices. */
|
||||
@@ -4130,8 +4167,19 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
||||
// Printf("Circuit 1 has %d devices in parallel while circuit 2 has %d\n",
|
||||
// (max1 == 1) ? 0 : max1, (max2 == 1) ? 0 : max2);
|
||||
|
||||
if (max1 > 1) changed += parallel_optimize(ob1, tp1, idx1, max1);
|
||||
if (max2 > 1) changed += parallel_optimize(ob2, tp2, idx2, max2);
|
||||
if (max1 > 1) {
|
||||
result = parallel_optimize(ob1, tp1, idx1, max1, FALSE);
|
||||
if (result > 0) changed += result;
|
||||
else if ((result < 0) && (max1 > max2))
|
||||
changed += series_optimize(ob1, tp1, idx1, max1, TRUE);
|
||||
}
|
||||
|
||||
if (max2 > 1) {
|
||||
result = parallel_optimize(ob2, tp2, idx2, max2, FALSE);
|
||||
if (result > 0) changed += result;
|
||||
else if ((result < 0) && (max2 > max1))
|
||||
changed += series_optimize(ob2, tp2, idx2, max2, TRUE);
|
||||
}
|
||||
|
||||
if (changed > 0) {
|
||||
FREE(netwk1);
|
||||
@@ -4164,9 +4212,9 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
||||
}
|
||||
}
|
||||
|
||||
/* Case 2: Serial devices with more elements in one circuit */
|
||||
/* Case 2: Series devices with more elements in one circuit */
|
||||
|
||||
/* Find the largest group of serial devices in circuit1 */
|
||||
/* Find the largest group of series devices in circuit1 */
|
||||
run = 0;
|
||||
cnt = 0;
|
||||
idx1 = 0;
|
||||
@@ -4190,7 +4238,7 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
||||
if (*c1 == '\0') break;
|
||||
}
|
||||
|
||||
/* Find the largest group of serial devices in circuit2 */
|
||||
/* Find the largest group of series devices in circuit2 */
|
||||
run = 0;
|
||||
cnt = 0;
|
||||
idx2 = 0;
|
||||
@@ -4218,10 +4266,21 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
||||
// Printf("Circuit 1 has %d devices in series while circuit 2 has %d\n",
|
||||
// (max1 == 1) ? 0 : max1, (max2 == 1) ? 0 : max2);
|
||||
|
||||
if (max1 > 1) changed += serial_optimize(ob1, tp1, idx1, max1);
|
||||
if (max2 > 1) changed += serial_optimize(ob2, tp2, idx2, max2);
|
||||
if (max1 > 1) {
|
||||
result = series_optimize(ob1, tp1, idx1, max1, FALSE);
|
||||
if (result > 0) changed += result;
|
||||
else if ((result < 0) && (max1 > max2))
|
||||
changed += parallel_optimize(ob1, tp1, idx1, max1, TRUE);
|
||||
}
|
||||
if (max2 > 1) {
|
||||
result = series_optimize(ob2, tp2, idx2, max2, FALSE);
|
||||
if (result > 0) changed += result;
|
||||
else if ((result < 0) && (max2 > max1))
|
||||
changed += parallel_optimize(ob2, tp2, idx2, max2, TRUE);
|
||||
}
|
||||
|
||||
if (changed > 0) {
|
||||
|
||||
FREE(netwk1);
|
||||
FREE(netwk2);
|
||||
continue;
|
||||
@@ -4229,21 +4288,21 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
||||
|
||||
if (max1 > 1) {
|
||||
/* Re-link first property, because it may have been moved */
|
||||
serial_sort(pre1, tp1, idx1, max1);
|
||||
series_sort(pre1, tp1, idx1, max1);
|
||||
ob1 = pre1->next;
|
||||
}
|
||||
if (max2 > 1) {
|
||||
/* Re-link first property, because it may have been moved */
|
||||
serial_sort(pre2, tp2, idx2, max2);
|
||||
series_sort(pre2, tp2, idx2, max2);
|
||||
ob2 = pre2->next;
|
||||
}
|
||||
|
||||
/* Do not run serial_combine until all other changes have been resolved */
|
||||
/* Do not run series_combine until all other changes have been resolved */
|
||||
if (changed == 0) {
|
||||
if (max2 > max1)
|
||||
changed += serial_combine(ob2, tp2, idx2, max2, ob1, tp1, idx1, max1);
|
||||
changed += series_combine(ob2, tp2, idx2, max2, ob1, tp1, idx1, max1);
|
||||
else if (max1 > max2)
|
||||
changed += serial_combine(ob1, tp1, idx1, max1, ob2, tp2, idx2, max2);
|
||||
changed += series_combine(ob1, tp1, idx1, max1, ob2, tp2, idx2, max2);
|
||||
}
|
||||
|
||||
FREE(netwk1);
|
||||
@@ -4252,7 +4311,7 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
||||
/* Continue looping until there are no further changes to be made */
|
||||
}
|
||||
if (iterations > 1)
|
||||
Printf("No more changes can be made to serial/parallel networks.\n");
|
||||
Printf("No more changes can be made to series/parallel networks.\n");
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
@@ -4262,7 +4321,7 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
||||
/* critical property (if defined), and merge devices with the */
|
||||
/* same properties (by summing property "M" for devices) */
|
||||
/* */
|
||||
/* For final optimization, if run == 1 and M > 1, then merge */
|
||||
/* For final optimization, if comb == 1 and M > 1, then merge */
|
||||
/* the critical property over M and set M to 1. */
|
||||
/* */
|
||||
/* Return the number of devices modified. */
|
||||
@@ -4274,7 +4333,8 @@ typedef struct _proplink {
|
||||
proplinkptr next;
|
||||
} proplink;
|
||||
|
||||
int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int serial)
|
||||
int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
int comb)
|
||||
{
|
||||
struct objlist *ob2, *obt;
|
||||
struct property *kl, *m_rec, **plist;
|
||||
@@ -4283,11 +4343,13 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int serial)
|
||||
int pcount, p, i, j, k, pmatch, ival, crit, ctype;
|
||||
double dval;
|
||||
static struct valuelist nullvl, dfltvl;
|
||||
char multiple[2];
|
||||
int changed = 0;
|
||||
char multiple[2], other[2];
|
||||
int changed = 0, fail = 0;
|
||||
|
||||
multiple[1] = '\0';
|
||||
multiple[0] = (serial == TRUE) ? 'S' : 'M';
|
||||
multiple[0] = (series == TRUE) ? 'S' : 'M';
|
||||
other[1] = '\0';
|
||||
other[0] = (series == TRUE) ? 'M' : 'S';
|
||||
|
||||
nullvl.type = PROP_INTEGER;
|
||||
nullvl.value.ival = 0;
|
||||
@@ -4317,18 +4379,18 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int serial)
|
||||
kl->idx = pcount++;
|
||||
|
||||
// Set critical property index, if there is one.
|
||||
// To do: deal with possibility of multiple critical properties
|
||||
// per instance?
|
||||
|
||||
if ((serial == FALSE) && (kl->merge == MERGE_ADD_CRIT ||
|
||||
kl->merge == MERGE_PAR_CRIT)) {
|
||||
crit = kl->idx;
|
||||
ctype = kl->merge;
|
||||
if (series == FALSE) {
|
||||
if (kl->merge & MERGE_P_CRIT) crit = kl->idx;
|
||||
if (kl->merge & (MERGE_P_ADD | MERGE_P_PAR))
|
||||
ctype = kl->merge & (MERGE_P_ADD | MERGE_P_PAR);
|
||||
}
|
||||
else if ((serial == TRUE) && (kl->merge == MERGE_SER_CRIT)) {
|
||||
crit = kl->idx;
|
||||
ctype = MERGE_ADD_CRIT;
|
||||
else if (series == TRUE) {
|
||||
if (kl->merge & MERGE_S_CRIT) crit = kl->idx;
|
||||
if (kl->merge & (MERGE_S_ADD | MERGE_S_PAR))
|
||||
ctype = kl->merge & (MERGE_S_ADD | MERGE_S_PAR);
|
||||
}
|
||||
|
||||
kl = (struct property *)HashNext(&(tp->propdict));
|
||||
}
|
||||
// Recast the linked list as an array
|
||||
@@ -4362,6 +4424,16 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int serial)
|
||||
vlist[0][i] = vl;
|
||||
}
|
||||
}
|
||||
if (kl == NULL) {
|
||||
/* Prevent setting both M > 1 and S > 1 in any one */
|
||||
/* device, as it is ambiguous. */
|
||||
|
||||
if ((*matchfunc)(vl->key, other)) {
|
||||
if (vl->type == PROP_INTEGER)
|
||||
if (vl->value.ival > 1)
|
||||
fail = 1;
|
||||
}
|
||||
}
|
||||
else if (kl != NULL) {
|
||||
vlist[kl->idx][i] = vl;
|
||||
}
|
||||
@@ -4381,174 +4453,181 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int serial)
|
||||
}
|
||||
|
||||
// Now combine records with same properties by summing M (S).
|
||||
for (i = 0; i < run - 1; i++) {
|
||||
for (j = 1; j < run; j++) {
|
||||
pmatch = 0;
|
||||
for (p = 1; p < pcount; p++) {
|
||||
kl = plist[p];
|
||||
vl = vlist[p][i];
|
||||
vl2 = vlist[p][j];
|
||||
if (vl == NULL && vl2 == NULL) {
|
||||
pmatch++;
|
||||
continue;
|
||||
}
|
||||
if (comb == FALSE) {
|
||||
for (i = 0; i < run - 1; i++) {
|
||||
for (j = 1; j < run; j++) {
|
||||
pmatch = 0;
|
||||
for (p = 1; p < pcount; p++) {
|
||||
kl = plist[p];
|
||||
vl = vlist[p][i];
|
||||
vl2 = vlist[p][j];
|
||||
if (vl == NULL && vl2 == NULL) {
|
||||
pmatch++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If either value is missing, it takes kl->pdefault
|
||||
// and must apply promotions if necessary.
|
||||
// If either value is missing, it takes kl->pdefault
|
||||
// and must apply promotions if necessary.
|
||||
|
||||
else if (vl == NULL || vl2 == NULL) {
|
||||
if (vl == NULL) {
|
||||
if (kl->type != vlist[p][j]->type)
|
||||
else if (vl == NULL || vl2 == NULL) {
|
||||
if (vl == NULL) {
|
||||
if (kl->type != vlist[p][j]->type)
|
||||
PromoteProperty(kl, vl2);
|
||||
}
|
||||
else {
|
||||
if (kl->type != vlist[p][i]->type)
|
||||
}
|
||||
else {
|
||||
if (kl->type != vlist[p][i]->type)
|
||||
PromoteProperty(kl, vl);
|
||||
}
|
||||
vl = &dfltvl;
|
||||
dfltvl.type = kl->type;
|
||||
switch (kl->type) {
|
||||
case PROP_STRING:
|
||||
}
|
||||
vl = &dfltvl;
|
||||
dfltvl.type = kl->type;
|
||||
switch (kl->type) {
|
||||
case PROP_STRING:
|
||||
dfltvl.value.string = kl->pdefault.string;
|
||||
break;
|
||||
case PROP_INTEGER:
|
||||
case PROP_INTEGER:
|
||||
dfltvl.value.ival = kl->pdefault.ival;
|
||||
break;
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
dfltvl.value.ival = kl->pdefault.ival;
|
||||
break;
|
||||
case PROP_EXPRESSION:
|
||||
case PROP_EXPRESSION:
|
||||
dfltvl.value.stack = kl->pdefault.stack;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Critical properties can be multiplied up by M (S) and do not
|
||||
// need to match. May want a more nuanced comparison, though.
|
||||
if (p == crit) {
|
||||
pmatch++;
|
||||
continue;
|
||||
}
|
||||
// Critical properties can be multiplied up by M (S) and do not
|
||||
// need to match. May want a more nuanced comparison, though.
|
||||
if (p == crit) {
|
||||
pmatch++;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(vl->type) {
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
dval = 2 * fabs(vl->value.dval - vl2->value.dval)
|
||||
switch(vl->type) {
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
dval = 2 * fabs(vl->value.dval - vl2->value.dval)
|
||||
/ (vl->value.dval + vl2->value.dval);
|
||||
if (dval <= kl->slop.dval) pmatch++;
|
||||
break;
|
||||
case PROP_INTEGER:
|
||||
ival = abs(vl->value.ival - vl2->value.ival);
|
||||
if (ival <= kl->slop.ival) pmatch++;
|
||||
break;
|
||||
case PROP_STRING:
|
||||
if ((*matchfunc)(vl->value.string, vl2->value.string)) pmatch++;
|
||||
break;
|
||||
if (dval <= kl->slop.dval) pmatch++;
|
||||
break;
|
||||
case PROP_INTEGER:
|
||||
ival = abs(vl->value.ival - vl2->value.ival);
|
||||
if (ival <= kl->slop.ival) pmatch++;
|
||||
break;
|
||||
case PROP_STRING:
|
||||
if ((*matchfunc)(vl->value.string, vl2->value.string)) pmatch++;
|
||||
break;
|
||||
|
||||
/* will not attempt to match expressions, but it could
|
||||
* be done with some minor effort by matching each
|
||||
* stack token and comparing those that are strings.
|
||||
*/
|
||||
}
|
||||
}
|
||||
if (pmatch == (pcount - 1)) {
|
||||
// Sum M (S) (p == 0) records and remove one record
|
||||
if (vlist[0][i] == NULL) {
|
||||
// Add this to the end of the property record
|
||||
// find ith record in ob
|
||||
p = 0;
|
||||
for (ob2 = ob; p != i; ob2 = ob2->next, p++);
|
||||
// Count entries, add one, reallocate
|
||||
for (p = 0;; p++) {
|
||||
vl = &ob2->instance.props[p];
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
/* will not attempt to match expressions, but it could
|
||||
* be done with some minor effort by matching each
|
||||
* stack token and comparing those that are strings.
|
||||
*/
|
||||
}
|
||||
p++;
|
||||
newvlist = (struct valuelist *)CALLOC(p + 1,
|
||||
}
|
||||
if (fail == 1) {
|
||||
/* If failure due to need to prevent M > 1 and S > 1 on */
|
||||
/* the same device, then do not do optimization. If */
|
||||
/* optimization could have been done, return -1. */
|
||||
|
||||
if (pmatch == (pcount - 1))
|
||||
changed = -1;
|
||||
}
|
||||
else if (pmatch == (pcount - 1)) {
|
||||
// Sum M (S) (p == 0) records and remove one record
|
||||
if (vlist[0][i] == NULL) {
|
||||
// Add this to the end of the property record
|
||||
// find ith record in ob
|
||||
p = 0;
|
||||
for (ob2 = ob; p != i; ob2 = ob2->next, p++);
|
||||
// Count entries, add one, reallocate
|
||||
for (p = 0;; p++) {
|
||||
vl = &ob2->instance.props[p];
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
}
|
||||
p++;
|
||||
newvlist = (struct valuelist *)CALLOC(p + 1,
|
||||
sizeof(struct valuelist));
|
||||
// Move end record forward
|
||||
vl = &newvlist[p];
|
||||
vl->key = NULL;
|
||||
vl->type = PROP_ENDLIST;
|
||||
vl->value.ival = 0;
|
||||
// Move end record forward
|
||||
vl = &newvlist[p];
|
||||
vl->key = NULL;
|
||||
vl->type = PROP_ENDLIST;
|
||||
vl->value.ival = 0;
|
||||
|
||||
// Add "M" ("S") record behind it
|
||||
vl = &newvlist[--p];
|
||||
vl->key = strsave(multiple);
|
||||
vl->type = PROP_INTEGER;
|
||||
vl->value.ival = 1;
|
||||
vlist[0][i] = vl;
|
||||
// Copy the rest of the records and regenerate vlist
|
||||
for (--p; p >= 0; p--) {
|
||||
vl = &newvlist[p];
|
||||
vl->key = ob2->instance.props[p].key;
|
||||
vl->type = ob2->instance.props[p].type;
|
||||
vl->value = ob2->instance.props[p].value;
|
||||
// Add "M" ("S") record behind it
|
||||
vl = &newvlist[--p];
|
||||
vl->key = strsave(multiple);
|
||||
vl->type = PROP_INTEGER;
|
||||
vl->value.ival = 1;
|
||||
vlist[0][i] = vl;
|
||||
// Copy the rest of the records and regenerate vlist
|
||||
for (--p; p >= 0; p--) {
|
||||
vl = &newvlist[p];
|
||||
vl->key = ob2->instance.props[p].key;
|
||||
vl->type = ob2->instance.props[p].type;
|
||||
vl->value = ob2->instance.props[p].value;
|
||||
|
||||
kl = (struct property *)HashLookup(vl->key, &(tp->propdict));
|
||||
if (kl != NULL) vlist[kl->idx][i] = vl;
|
||||
kl = (struct property *)HashLookup(vl->key, &(tp->propdict));
|
||||
if (kl != NULL) vlist[kl->idx][i] = vl;
|
||||
}
|
||||
|
||||
// Replace instance properties with the new list
|
||||
FREE(ob2->instance.props);
|
||||
ob2->instance.props = newvlist;
|
||||
}
|
||||
|
||||
// Replace instance properties with the new list
|
||||
FREE(ob2->instance.props);
|
||||
ob2->instance.props = newvlist;
|
||||
}
|
||||
|
||||
if (vlist[0][j] == NULL) {
|
||||
vlist[0][j] = &nullvl; // Mark this position
|
||||
vlist[0][i]->value.ival++;
|
||||
}
|
||||
else if (vlist[0][i]->value.ival > 0) {
|
||||
vlist[0][i]->value.ival += vlist[0][j]->value.ival;
|
||||
vlist[0][j]->value.ival = 0;
|
||||
if (vlist[0][j] == NULL) {
|
||||
vlist[0][j] = &nullvl; // Mark this position
|
||||
vlist[0][i]->value.ival++;
|
||||
}
|
||||
else if (vlist[0][j]->value.ival > 0) {
|
||||
vlist[0][i]->value.ival += vlist[0][j]->value.ival;
|
||||
vlist[0][j]->value.ival = 0;
|
||||
}
|
||||
}
|
||||
else j++;
|
||||
}
|
||||
else j++;
|
||||
}
|
||||
}
|
||||
|
||||
// For the special case of run == 1, reduce M (or S) to 1 by
|
||||
// merging the critical property (if any)
|
||||
// If comb == TRUE, reduce M (or S) to 1 by merging the critical
|
||||
// property (if any)
|
||||
|
||||
if ((run == 1) && (crit != -1) && (vlist[0][0] != NULL)) {
|
||||
int mult = vlist[0][0]->value.ival;
|
||||
if (mult > 1) {
|
||||
vl = vlist[crit][0];
|
||||
if ((comb == TRUE) && (crit != -1)) {
|
||||
int mult;
|
||||
for (i = 0; i < run; i++) {
|
||||
if (vlist[0][i] == NULL) continue;
|
||||
mult = vlist[0][i]->value.ival;
|
||||
if (mult > 1) {
|
||||
changed = 0;
|
||||
vl = vlist[crit][i];
|
||||
|
||||
if ((serial == TRUE) && (ctype = MERGE_SER_CRIT)) {
|
||||
if (vl->type == PROP_INTEGER)
|
||||
vl->value.ival *= mult;
|
||||
else if (vl->type == PROP_DOUBLE)
|
||||
vl->value.dval *= (double)mult;
|
||||
vlist[0][0]->value.ival = 1;
|
||||
changed += mult;
|
||||
if ((ctype == MERGE_S_ADD) || (ctype == MERGE_P_ADD)) {
|
||||
if (vl->type == PROP_INTEGER)
|
||||
vl->value.ival *= mult;
|
||||
else if (vl->type == PROP_DOUBLE)
|
||||
vl->value.dval *= (double)mult;
|
||||
vlist[0][i]->value.ival = 1;
|
||||
changed += mult;
|
||||
}
|
||||
else if ((ctype == MERGE_S_PAR) || (ctype == MERGE_P_PAR)) {
|
||||
/* Technically one should check if divide-by-mult */
|
||||
/* reduces the value to < 1 and promote to double */
|
||||
/* if so, but that's a very unlikely case. */
|
||||
if (vl->type == PROP_INTEGER)
|
||||
vl->value.ival /= mult;
|
||||
else if (vl->type == PROP_DOUBLE)
|
||||
vl->value.dval /= (double)mult;
|
||||
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);
|
||||
}
|
||||
}
|
||||
else if (serial == FALSE && (ctype = MERGE_ADD_CRIT)) {
|
||||
if (vl->type == PROP_INTEGER)
|
||||
vl->value.ival *= mult;
|
||||
else if (vl->type == PROP_DOUBLE)
|
||||
vl->value.dval *= (double)mult;
|
||||
vlist[0][0]->value.ival = 1;
|
||||
changed += mult;
|
||||
}
|
||||
else if (serial == FALSE && (ctype = MERGE_PAR_CRIT)) {
|
||||
/* Technically one should check if divide-by-mult */
|
||||
/* reduces the value to < 1 and promote to double */
|
||||
/* if so, but that's a very unlikely case. */
|
||||
if (vl->type == PROP_INTEGER)
|
||||
vl->value.ival /= mult;
|
||||
else if (vl->type == PROP_DOUBLE)
|
||||
vl->value.dval /= (double)mult;
|
||||
vlist[0][0]->value.ival = 1;
|
||||
changed += mult;
|
||||
}
|
||||
if (changed > 0) {
|
||||
if (serial)
|
||||
Printf("Combined %d serial devices.\n", changed);
|
||||
else
|
||||
Printf("Combined %d parallel devices.\n", changed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4566,6 +4645,8 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int serial)
|
||||
ob2 = ob2->next;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
||||
// Cleanup memory allocation
|
||||
for (p = 0; p < pcount; p++) {
|
||||
kl = (struct property *)plist[p];
|
||||
@@ -5057,7 +5138,7 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Dump a description of a device's serial/parallel network */
|
||||
/* Dump a description of a device's series/parallel network */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
void DumpNetwork(struct objlist *ob, int cidx)
|
||||
@@ -5102,6 +5183,23 @@ void DumpNetwork(struct objlist *ob, int cidx)
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Call DumpNetwork() on each device in the object list */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
void DumpNetworkAll(char *model, int file)
|
||||
{
|
||||
struct nlist *tp;
|
||||
struct objlist *ob;
|
||||
|
||||
if ((tp = LookupCellFile(model, file)) == NULL) {
|
||||
Printf("Cell: %s does not exist.\n", model);
|
||||
}
|
||||
for (ob = tp->cell; ob; ob = ob->next)
|
||||
if (ob->type == FIRSTPIN)
|
||||
DumpNetwork(ob, file);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Compare the properties of two objects. The passed values */
|
||||
/* ob1 and ob2 are pointers to the first entry (firstpin) of */
|
||||
@@ -5206,7 +5304,7 @@ PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
|
||||
#endif
|
||||
}
|
||||
|
||||
// Attempt to organize devices by serial and parallel combination
|
||||
// Attempt to organize devices by series and parallel combination
|
||||
if (t1type == PROPERTY && t2type == PROPERTY)
|
||||
PropertySortAndCombine(obn1, tc1, obn2, tc2);
|
||||
|
||||
@@ -5227,7 +5325,7 @@ PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
|
||||
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/serial network does not match"
|
||||
Fprintf(stdout, "Circuit 1 parallel/series network does not match"
|
||||
" Circuit 2\n");
|
||||
DumpNetwork(ob1, 1);
|
||||
DumpNetwork(ob2, 2);
|
||||
@@ -5278,7 +5376,7 @@ PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
|
||||
else if ((t2type != PROPERTY) && (checked_one == TRUE)) {
|
||||
// t1 has more property records than t2, and they did not get
|
||||
// merged equally by PropertySortAndCombine().
|
||||
Fprintf(stdout, "Circuit 2 parallel/serial network does not match"
|
||||
Fprintf(stdout, "Circuit 2 parallel/series network does not match"
|
||||
" Circuit 1\n");
|
||||
DumpNetwork(ob1, 1);
|
||||
DumpNetwork(ob2, 2);
|
||||
@@ -5332,13 +5430,13 @@ PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print,
|
||||
inst2, FALSE, FALSE, &multmatch, NULL);
|
||||
if (multmatch == 1) {
|
||||
/* Final attempt: Reduce M to 1 on both devices */
|
||||
PropertyOptimize(tp1, tc1, 1, FALSE);
|
||||
PropertyOptimize(tp2, tc2, 1, FALSE);
|
||||
PropertyOptimize(tp1, tc1, 1, FALSE, TRUE);
|
||||
PropertyOptimize(tp2, tc2, 1, FALSE, TRUE);
|
||||
}
|
||||
else if (multmatch == 2) {
|
||||
/* Final attempt: Reduce S to 1 on both devices */
|
||||
PropertyOptimize(tp1, tc1, 1, TRUE);
|
||||
PropertyOptimize(tp2, tc2, 1, TRUE);
|
||||
PropertyOptimize(tp1, tc1, 1, TRUE, TRUE);
|
||||
PropertyOptimize(tp2, tc2, 1, TRUE, TRUE);
|
||||
}
|
||||
#ifdef TCL_NETGEN
|
||||
mlist =
|
||||
|
||||
+5
-1
@@ -36,7 +36,8 @@ extern int EquivalenceNodes(char *name1, int file1, char *name2, int file2);
|
||||
extern int EquivalenceClasses(char *name1, int file1, char *name2, int file2);
|
||||
extern int IgnoreClass(char *name, int file, unsigned char type);
|
||||
extern int MatchPins(struct nlist *tp1, struct nlist *tp2, int dolist);
|
||||
extern int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int serial);
|
||||
extern int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run,
|
||||
int series, int comb);
|
||||
|
||||
extern int CreateCompareQueue(char *, int, char *, int);
|
||||
extern int GetCompareQueueTop(char **, int *, char **, int *);
|
||||
@@ -47,6 +48,9 @@ extern void PrintIllegalClasses();
|
||||
extern void PrintIllegalNodeClasses();
|
||||
extern void PrintIllegalElementClasses();
|
||||
|
||||
extern void DumpNetwork(struct objlist *ob, int cidx);
|
||||
extern void DumpNetworkAll(char *name, int file);
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
extern int EquivalentNode();
|
||||
extern int EquivalentElement();
|
||||
|
||||
+25
-5
@@ -437,7 +437,10 @@ void SpiceSkipNewLine(void)
|
||||
/* delimiters (this presumably could be further extended as needed). */
|
||||
/* so ",;()" would be a valid delimiter set, but to include C-style */
|
||||
/* comments and verilog-style parameter lists, one would need */
|
||||
/* ",;()X/**///#(". */
|
||||
/* "X/**///#(X,;()". Two-character delimiters should go first so that */
|
||||
/* they have precedence over one-character delimiters. 'X' should be */
|
||||
/* the first character of the delimiter string in addition to marking */
|
||||
/* the boundary between two-character and one-character delimiters. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
char *strdtok(char *pstring, char *delim1, char *delim2)
|
||||
@@ -468,6 +471,23 @@ char *strdtok(char *pstring, char *delim1, char *delim2)
|
||||
|
||||
/* "stoken" is now set. Now find the end of the current token */
|
||||
|
||||
s = stoken;
|
||||
|
||||
/* Special verilog rule: If a name begins with '\', then all characters */
|
||||
/* are a valid part of the name until a space character is reached. The */
|
||||
/* space character becomes part of the verilog name. The remainder of the */
|
||||
/* name is parsed according to the rules of "delim2". */
|
||||
|
||||
if (*s == '\\') {
|
||||
while (*s != '\0') {
|
||||
if (*s == ' ') {
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check string from position stoken. If a character in "delim2" is found, */
|
||||
/* save the character in "lastdelim", null the byte at that position, and */
|
||||
/* return the token. If a character in "delim1" is found, do the same but */
|
||||
@@ -476,11 +496,11 @@ char *strdtok(char *pstring, char *delim1, char *delim2)
|
||||
/* as for "delim2" above. If not, then set "lastdelim" to a null byte and */
|
||||
/* return the token. */
|
||||
|
||||
for (s = stoken; *s; s++) {
|
||||
twofer = FALSE;
|
||||
for (s2 = delim2; s2 && *s2; s2++) {
|
||||
for (; *s; s++) {
|
||||
twofer = (delim2 && (*delim2 == 'X')) ? TRUE : FALSE;
|
||||
for (s2 = ((twofer == TRUE) ? delim2 + 1 : delim2); s2 && *s2; s2++) {
|
||||
if (*s2 == 'X') {
|
||||
twofer = TRUE;
|
||||
twofer = FALSE;
|
||||
continue;
|
||||
}
|
||||
if (twofer) {
|
||||
|
||||
+145
-39
@@ -897,6 +897,32 @@ void SetParallelCombine(int value)
|
||||
RecurseCellHashTable2(SetParallelCombineFlag, (void *)(&value));
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Same as above, for series (here for symmetry, although "property */
|
||||
/* series all" would be an odd command to issue, and "property series */
|
||||
/* none" is the default, so not needed). */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
struct nlist *SetSeriesCombineFlag(struct hashlist *p, void *clientdata)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
int *value = (int *)clientdata;
|
||||
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
if (*value == TRUE)
|
||||
ptr->flags &= (~COMB_SERIES);
|
||||
else
|
||||
ptr->flags |= COMB_SERIES;
|
||||
|
||||
return NULL; /* NULL keeps search alive */
|
||||
}
|
||||
|
||||
void SetSeriesCombine(int value)
|
||||
{
|
||||
ClearDumpedList();
|
||||
RecurseCellHashTable2(SetSeriesCombineFlag, (void *)(&value));
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Delete a property from the master cell record. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
@@ -992,15 +1018,15 @@ PropertyTolerance(char *name, int fnum, char *key, int ival, double dval)
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
PropertyMerge(char *name, int fnum, char *key, int merge_type)
|
||||
PropertyMerge(char *name, int fnum, char *key, int merge_type, int merge_mask)
|
||||
{
|
||||
struct property *kl = NULL;
|
||||
struct nlist *tc;
|
||||
int result;
|
||||
|
||||
if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
|
||||
result = PropertyMerge(name, Circuit1->file, key, merge_type);
|
||||
result = PropertyMerge(name, Circuit2->file, key, merge_type);
|
||||
result = PropertyMerge(name, Circuit1->file, key, merge_type, merge_mask);
|
||||
result = PropertyMerge(name, Circuit2->file, key, merge_type, merge_mask);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1016,7 +1042,8 @@ PropertyMerge(char *name, int fnum, char *key, int merge_type)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
kl->merge = merge_type;
|
||||
kl->merge &= ~merge_mask;
|
||||
kl->merge |= merge_type;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -2462,8 +2489,7 @@ int ConvertStringToInteger(char *string, int *ival)
|
||||
*ival = (int)lval;
|
||||
return 1;
|
||||
}
|
||||
else if (eptr == string)
|
||||
return 0; /* No conversion */
|
||||
else return 0; /* No conversion */
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
@@ -2868,50 +2894,50 @@ void ConnectAllNodes(char *model, int file)
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Serial and Parallel combination: */
|
||||
/* All devices of the same type that exist in serial and parallel */
|
||||
/* Series and Parallel combination: */
|
||||
/* All devices of the same type that exist in series and parallel */
|
||||
/* combinations will be treated as a single device in a network. */
|
||||
/* Serial connections are only allowed for resistors and inductors. */
|
||||
/* Any device may be connected in parallel. For combinations of serial */
|
||||
/* Series connections are only allowed for resistors and inductors. */
|
||||
/* Any device may be connected in parallel. For combinations of series */
|
||||
/* and parallel, as in a resistor network, there is a set of rules: */
|
||||
/* */
|
||||
/* Running parallel and serial checks: */
|
||||
/* Running parallel and series checks: */
|
||||
/* 1. Run parallel once. If a repeat run and no devices are merged, */
|
||||
/* then go to 4. */
|
||||
/* 2. Run serial until no devices are merged. */
|
||||
/* 3. If serial ran more than once, then go to 1. */
|
||||
/* 2. Run series until no devices are merged. */
|
||||
/* 3. If series ran more than once, then go to 1. */
|
||||
/* 4. End merge */
|
||||
/* */
|
||||
/* Each merge procedure, when it finds two devices that can be merged, */
|
||||
/* removes the second device from the netlist and adds its properties */
|
||||
/* to the first device. If a serial merge, then the nodes are adjusted */
|
||||
/* to the first device. If a series merge, then the nodes are adjusted */
|
||||
/* appropriately. Where A is the property list of the first device and */
|
||||
/* B is the property list of the second device, the first and last */
|
||||
/* properties of A and the first property of B may require a marker to */
|
||||
/* indicate the topology of the network, as follows (in order): */
|
||||
/* */
|
||||
/* For a parallel merge: */
|
||||
/* 1) If A has serial components then tag first property of A with */
|
||||
/* 1) If A has series components then tag first property of A with */
|
||||
/* "open" and tag first property of B with "close". */
|
||||
/* 2) If B has serial components then tag first property of B with */
|
||||
/* 2) If B has series components then tag first property of B with */
|
||||
/* "open". */
|
||||
/* */
|
||||
/* For a serial merge: */
|
||||
/* For a series merge: */
|
||||
/* 1) If A has unbalanced "opens", then add "close" to first */
|
||||
/* property of B to balance the "opens". */
|
||||
/* 2) Always tag B with "serial". */
|
||||
/* 2) Always tag B with "series". */
|
||||
/* */
|
||||
/* Tags are indicated by a property named "_tag" which has a string */
|
||||
/* value of ordered characters, "+" for serial, "(" for open, and ")" */
|
||||
/* value of ordered characters, "+" for series, "(" for open, and ")" */
|
||||
/* for close. A device with only one property record has no "_tag" */
|
||||
/* record. A device which is in parallel with the device(s) in front */
|
||||
/* of it is implicitly parallel by not having an "+" tag, and may not */
|
||||
/* have a tag at all. */
|
||||
/* */
|
||||
/* The property check routine is responsible for comparing device */
|
||||
/* serial/parallel networks against each other. Otherwise, each */
|
||||
/* serial/parallel network is considered topologically as a single */
|
||||
/* device, and any differences in the serial/parallel networks between */
|
||||
/* series/parallel networks against each other. Otherwise, each */
|
||||
/* series/parallel network is considered topologically as a single */
|
||||
/* device, and any differences in the series/parallel networks between */
|
||||
/* two circuits being matched will be treated as a property error. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
@@ -2927,7 +2953,8 @@ int add_prop_tag(struct objlist *obr, char tagc)
|
||||
char *tmpstr;
|
||||
|
||||
hastag = FALSE;
|
||||
for (nob = obr; nob->next && nob->next->type == PROPERTY; nob = nob->next) {
|
||||
for (nob = obr; nob; nob = nob->next) {
|
||||
if (nob->type != PROPERTY) break;
|
||||
for (i = 0; ; i++) {
|
||||
kv = &(nob->instance.props[i]);
|
||||
if (kv->type == PROP_ENDLIST) break;
|
||||
@@ -3018,6 +3045,75 @@ void add_balancing_close(struct objlist *ob1, struct objlist *ob2)
|
||||
while (opentags-- > 0) add_prop_tag(nob, ')');
|
||||
}
|
||||
|
||||
/* Remove unneeded group tags, when device merging has removed all but */
|
||||
/* one, or all but parallel devices inside a group. For simplicity, */
|
||||
/* handle only one group at a time. Return 1 if a group was removed */
|
||||
/* and 0 if not. The caller should run repeatedly until the routine */
|
||||
/* returns 0. */
|
||||
|
||||
int remove_group_tags(struct objlist *ob)
|
||||
{
|
||||
struct objlist *nob, *sob;
|
||||
int i, si, stags;
|
||||
struct valuelist *kv;
|
||||
char *tag;
|
||||
|
||||
/* Find the first property record in ob. */
|
||||
for (nob = ob->next; nob && nob->type != FIRSTPIN; nob = nob->next)
|
||||
if (nob->type == PROPERTY)
|
||||
break;
|
||||
if (nob->type != PROPERTY) return 0; // shouldn't happen
|
||||
|
||||
for (sob = NULL; nob && nob->type == PROPERTY; nob = nob->next) {
|
||||
for (i = 0; ; i++) {
|
||||
kv = &(nob->instance.props[i]);
|
||||
if (kv->type == PROP_ENDLIST) break;
|
||||
if (kv->type == PROP_STRING) {
|
||||
if (!strcmp(kv->key, "_tag")) {
|
||||
for (tag = kv->value.string; *tag != '\0'; tag++) {
|
||||
if (*tag == '(') {
|
||||
sob = nob; /* Save position of open group */
|
||||
si = i; /* Save index of open group */
|
||||
stags = 0; /* Check for series tags */
|
||||
}
|
||||
else if (*tag == '+')
|
||||
stags++;
|
||||
else if (*tag == ')') {
|
||||
if (stags == 0) {
|
||||
/* Remove close tag */
|
||||
for (++i; ; i++) {
|
||||
nob->instance.props[i - 1] = nob->instance.props[i];
|
||||
if (nob->instance.props[i].type == PROP_ENDLIST) break;
|
||||
}
|
||||
/* Remove open tag */
|
||||
for (i = si + 1; ; i++) {
|
||||
sob->instance.props[i - 1] = sob->instance.props[i];
|
||||
if (sob->instance.props[i].type == PROP_ENDLIST) break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
sob = NULL;
|
||||
stags = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sob != NULL) {
|
||||
/* Implicit close tag at end */
|
||||
if (stags == 0) {
|
||||
/* Remove open tag */
|
||||
for (i = si + 1; ; i++) {
|
||||
sob->instance.props[i - 1] = sob->instance.props[i];
|
||||
if (sob->instance.props[i].type == PROP_ENDLIST) break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Find all devices that are of the same class and check for parallel */
|
||||
/* combinations, and combine them where found, adjusting property "M" */
|
||||
@@ -3229,7 +3325,7 @@ int CombineParallel(char *model, int file)
|
||||
|
||||
if (propfirst != NULL) {
|
||||
|
||||
// Serial/Parallel logic:
|
||||
// Series/Parallel logic:
|
||||
// If propfirst has _tag in properties,
|
||||
// then add an "open" tag at propfirst
|
||||
add_prop_tag(propfirst, '(');
|
||||
@@ -3272,9 +3368,9 @@ int CombineParallel(char *model, int file)
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* For the purposes of serial connection checking, find if all pins */
|
||||
/* For the purposes of series connection checking, find if all pins */
|
||||
/* of two instances after the first two pins are connected to the name */
|
||||
/* nodes. This depends on the definition of a serial device as having */
|
||||
/* nodes. This depends on the definition of a series device as having */
|
||||
/* two ports, but any additional ports (such as a substrate connection) */
|
||||
/* must be the same for all devices in series. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
@@ -3284,7 +3380,7 @@ int check_pin_nodes(struct objlist *ob1, struct objlist *ob2)
|
||||
struct objlist *nob, *pob;
|
||||
|
||||
/* A dummy device may have both terminals connected to the same */
|
||||
/* point, triggering a false check for a serial device. */
|
||||
/* point, triggering a false check for a series device. */
|
||||
if (ob1 == ob2) return FALSE;
|
||||
|
||||
for (nob = ob1->next; nob && nob->type != FIRSTPIN; nob = nob->next)
|
||||
@@ -3313,12 +3409,12 @@ int check_pin_nodes(struct objlist *ob1, struct objlist *ob2)
|
||||
/* one. */
|
||||
/* */
|
||||
/* This routine depends on CombineParallel() being run first so that no */
|
||||
/* parallel devices are reported as serial. */
|
||||
/* parallel devices are reported as series. */
|
||||
/* */
|
||||
/* Return the number of devices merged. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
int CombineSerial(char *model, int file)
|
||||
int CombineSeries(char *model, int file)
|
||||
{
|
||||
struct nlist *tp, *tp2;
|
||||
struct objlist ***instlist;
|
||||
@@ -3331,7 +3427,7 @@ int CombineSerial(char *model, int file)
|
||||
return -1;
|
||||
}
|
||||
/* Diagnostic */
|
||||
/* Printf("CombineSerial start model = %s file = %d\n", model, file); */
|
||||
/* Printf("CombineSeries start model = %s file = %d\n", model, file); */
|
||||
|
||||
instlist = (struct objlist ***)CALLOC((tp->nodename_cache_maxnodenum + 1),
|
||||
sizeof(struct objlist **));
|
||||
@@ -3346,26 +3442,36 @@ int CombineSerial(char *model, int file)
|
||||
instlist[ob->node] = (struct objlist **)CALLOC(2,
|
||||
sizeof(struct objlist *));
|
||||
|
||||
/* Device must be marked as able to be combined in serial. */
|
||||
/* Device must be marked as able to be combined in series. */
|
||||
/* Note that devices with more than two pins are expected */
|
||||
/* to serial connect along the first two pins, and the */
|
||||
/* to series connect along the first two pins, and the */
|
||||
/* remaining pins must all connect to the same nodes. By */
|
||||
/* default, CLASS_RES, CLASS_RES3, and CLASS_INDUCTOR are */
|
||||
/* all allowed to combine in serial. All other devices */
|
||||
/* must have serial combination explicitly enabled. */
|
||||
/* all allowed to combine in series. All other devices */
|
||||
/* must have series combination explicitly enabled. */
|
||||
/* NOTE: Arbitrarily, the first two pins of a device are */
|
||||
/* assumed to be the ones that make serial connections. */
|
||||
/* assumed to be the ones that make series connections. */
|
||||
/* Additional pins, if any, do not. */
|
||||
|
||||
tp2 = LookupCellFile(ob->model.class, file);
|
||||
if ((tp2->flags & COMB_SERIAL) && (ob->type <= 2))
|
||||
if ((tp2->flags & COMB_SERIES) && (ob->type <= 2)) {
|
||||
instlist[ob->node][0] = obp;
|
||||
|
||||
/* Node may not be a port of the subcircuit */
|
||||
for (obn = tp->cell; obn && obn->type == PORT; obn = obn->next) {
|
||||
if (obn->node == ob->node) {
|
||||
/* invalidate node */
|
||||
instlist[ob->node][0] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
/* invalidate node */
|
||||
instlist[ob->node][0] = NULL;
|
||||
}
|
||||
else if (instlist[ob->node][0] == NULL) {
|
||||
/* Node is not valid for serial connection */
|
||||
/* Node is not valid for series connection */
|
||||
}
|
||||
else if (instlist[ob->node][1] == NULL) {
|
||||
/* Check if first instance is the same type */
|
||||
@@ -3393,7 +3499,7 @@ int CombineSerial(char *model, int file)
|
||||
struct valuelist *kv2;
|
||||
|
||||
/* Diagnostic */
|
||||
/* Fprintf(stdout, "Found serial instances %s and %s\n",
|
||||
/* Fprintf(stdout, "Found series instances %s and %s\n",
|
||||
instlist[i][0]->instance.name,
|
||||
instlist[i][1]->instance.name); */
|
||||
scnt++;
|
||||
@@ -3504,7 +3610,7 @@ int CombineSerial(char *model, int file)
|
||||
obs = obn;
|
||||
}
|
||||
|
||||
/* If 2nd device appears anywhere else in the serial device */
|
||||
/* If 2nd device appears anywhere else in the series device */
|
||||
/* list, replace it with the 1st device. */
|
||||
for (j = i + 1; j <= tp->nodename_cache_maxnodenum; j++) {
|
||||
if (instlist[j] == NULL) continue;
|
||||
|
||||
+8
-4
@@ -36,9 +36,11 @@ extern struct property *PropertyString(char *name, int fnum, char *key,
|
||||
double slop, char *pdefault);
|
||||
extern int PropertyDelete(char *name, int fnum, char *key);
|
||||
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 PropertyMerge(char *name, int fnum, char *key, int merge_type);
|
||||
extern int PropertyMerge(char *name, int fnum, char *key, int merge_type,
|
||||
int merge_mask);
|
||||
extern void ResolveProperties(char *name1, int file1, char *name2, int file2);
|
||||
extern void CopyProperties(struct objlist *obj_to, struct objlist *obj_from);
|
||||
extern int PromoteProperty(struct property *, struct valuelist *);
|
||||
@@ -85,8 +87,10 @@ extern int PrematchLists(char *, int, char *, int);
|
||||
#define CLASS_DIODE 16 /* standard SPICE diode */
|
||||
#define CLASS_INDUCTOR 17 /* standard SPICE inductor */
|
||||
#define CLASS_XLINE 18 /* transmission line model */
|
||||
#define CLASS_MODULE 19 /* sim "x"; black-box subcircuit */
|
||||
#define CLASS_UNDEF 20 /* not defined; error */
|
||||
#define CLASS_VSOURCE 19 /* independent voltage source */
|
||||
#define CLASS_ISOURCE 20 /* independent current source */
|
||||
#define CLASS_MODULE 21 /* sim "x"; black-box subcircuit */
|
||||
#define CLASS_UNDEF 22 /* not defined; error */
|
||||
|
||||
extern char *P(char *fname, char *inststr, char *drain, char *gate, char *source);
|
||||
extern char *P4(char *fname, char *inststr, char *drain, char *gate, char *source,
|
||||
@@ -120,7 +124,7 @@ extern void ConvertGlobals(char *name, int fnum);
|
||||
extern int CleanupPins(char *name, int fnum);
|
||||
extern void ConnectAllNodes(char *model, int fnum);
|
||||
extern int CombineParallel(char *model, int fnum);
|
||||
extern int CombineSerial(char *model, int fnum);
|
||||
extern int CombineSeries(char *model, int fnum);
|
||||
extern int NoDisconnectedNodes;
|
||||
extern int PropertyKeyMatch(char *, char *);
|
||||
extern int PropertyValueMatch(char *, char *);
|
||||
|
||||
+20
-8
@@ -103,18 +103,30 @@ struct valuelist {
|
||||
|
||||
/* Part 3: Keys & Defaults (kept in the cell record as a hash table) */
|
||||
|
||||
#define MERGE_NONE 0 /* Property does not change when devices merge */
|
||||
#define MERGE_ADD 1 /* Properties sum with device parallel merge */
|
||||
#define MERGE_ADD_CRIT 2 /* Properties sum with device parallel merge */
|
||||
#define MERGE_PAR 3 /* Properties add in parallel with device merge */
|
||||
#define MERGE_PAR_CRIT 4 /* Properties add in parallel with device merge */
|
||||
#define MERGE_SER 5 /* Properties sum with device parallel merge */
|
||||
#define MERGE_SER_CRIT 6 /* Properties sum with device parallel merge */
|
||||
#define MERGE_NONE 0x00 /* Property does not change when devices merge */
|
||||
|
||||
#define MERGE_P_ADD 0x01 /* Properties sum with device parallel merge */
|
||||
#define MERGE_P_PAR 0x02 /* Properties add in parallel with parallel merge */
|
||||
#define MERGE_P_CRIT 0x04 /* This property enables parallel merging */
|
||||
#define MERGE_P_XCRIT 0x08 /* Old "critical" behavior (deprecated) */
|
||||
|
||||
#define MERGE_S_ADD 0x10 /* Properties sum with device series merge */
|
||||
#define MERGE_S_PAR 0x20 /* Properties add in parallel with series merge */
|
||||
#define MERGE_S_CRIT 0x40 /* This property enables series merging */
|
||||
#define MERGE_S_XCRIT 0x80 /* Old "critical" behavior (deprecated) */
|
||||
|
||||
#define MERGE_P_MASK (MERGE_P_ADD | MERGE_P_PAR | MERGE_P_CRIT | MERGE_P_XCRIT)
|
||||
#define MERGE_S_MASK (MERGE_S_ADD | MERGE_S_PAR | MERGE_S_CRIT | MERGE_S_XCRIT)
|
||||
#define MERGE_ALL_MASK (MERGE_P_MASK | MERGE_S_MASK)
|
||||
|
||||
/* Although the above are flags, "ADD" and "PAR" are mutually exclusive. */
|
||||
|
||||
/* Note: A "critical" merge means that the property causes the number of */
|
||||
/* devices to change. e.g., transistor width is critical; transistor drain */
|
||||
/* area sums when devices are merged, but does not change the number of devices.*/
|
||||
/* More than one property can be critical. e.g., width and number of fingers. */
|
||||
/* Also it is possible for a property (e.g., "value") to be critical for both */
|
||||
/* series and parallel merging. */
|
||||
|
||||
struct property {
|
||||
char *key; /* name of the property */
|
||||
@@ -217,7 +229,7 @@ struct nlist {
|
||||
|
||||
/* Flags for combination allowances and prohibitions */
|
||||
|
||||
#define COMB_SERIAL 0x40
|
||||
#define COMB_SERIES 0x40
|
||||
#define COMB_NO_PARALLEL 0x80
|
||||
|
||||
extern struct nlist *CurrentCell;
|
||||
|
||||
+32
-3
@@ -117,6 +117,12 @@ void SpiceSubCell(struct nlist *tp, int IsSubCell)
|
||||
case CLASS_NPN: case CLASS_PNP: case CLASS_BJT:
|
||||
spice_class = 'Q';
|
||||
break;
|
||||
case CLASS_VSOURCE:
|
||||
spice_class = 'V';
|
||||
break;
|
||||
case CLASS_ISOURCE:
|
||||
spice_class = 'I';
|
||||
break;
|
||||
case CLASS_RES: case CLASS_RES3:
|
||||
spice_class = 'R';
|
||||
break;
|
||||
@@ -172,7 +178,7 @@ void SpiceSubCell(struct nlist *tp, int IsSubCell)
|
||||
break;
|
||||
}
|
||||
|
||||
/* caps and resistors, print out device value */
|
||||
/* caps, resistors, voltage and current sources, print out device value */
|
||||
|
||||
/* print out device type (model/subcircuit name) */
|
||||
|
||||
@@ -217,6 +223,23 @@ void SpiceSubCell(struct nlist *tp, int IsSubCell)
|
||||
FlushString(" %s", model); /* semiconductor resistor */
|
||||
break;
|
||||
|
||||
case CLASS_VSOURCE:
|
||||
case CLASS_ISOURCE:
|
||||
ob = ob->next;
|
||||
if (ob->type == PROPERTY) {
|
||||
struct valuelist *vl;
|
||||
int i;
|
||||
for (i == 0;; i++) {
|
||||
vl = &(ob->instance.props[i]);
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
else if (vl->type == PROP_VALUE) {
|
||||
FlushString(" %g", vl->value.dval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
FlushString(" %s", model); /* everything else */
|
||||
}
|
||||
@@ -711,6 +734,12 @@ skip_ends:
|
||||
else if (!strcasecmp(nexttok, "R")) {
|
||||
class = CLASS_RES;
|
||||
}
|
||||
else if (!strcasecmp(nexttok, "V")) {
|
||||
class = CLASS_VSOURCE;
|
||||
}
|
||||
else if (!strcasecmp(nexttok, "I")) {
|
||||
class = CLASS_ISOURCE;
|
||||
}
|
||||
else if (!strcasecmp(nexttok, "C")) {
|
||||
class = CLASS_CAP;
|
||||
}
|
||||
@@ -1436,7 +1465,7 @@ skip_ends:
|
||||
Port("pos");
|
||||
Port("neg");
|
||||
PropertyInteger(model, filenum, "M", 0, 1);
|
||||
SetClass(CLASS_MODULE);
|
||||
SetClass(CLASS_VSOURCE);
|
||||
EndCell();
|
||||
ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */
|
||||
}
|
||||
@@ -1490,7 +1519,7 @@ skip_ends:
|
||||
Port("pos");
|
||||
Port("neg");
|
||||
PropertyInteger(model, filenum, "M", 0, 1);
|
||||
SetClass(CLASS_MODULE);
|
||||
SetClass(CLASS_ISOURCE);
|
||||
EndCell();
|
||||
ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */
|
||||
}
|
||||
|
||||
+77
-22
@@ -59,8 +59,9 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
// See netfile.c for explanation of delimiters. 'X'
|
||||
// separates single-character delimiters from two-character delimiters.
|
||||
#define VLOG_DELIMITERS ",;:(){}[]=X///**/#("
|
||||
#define VLOG_PIN_NAME_DELIMITERS "()X///**/"
|
||||
#define VLOG_DELIMITERS "X///**/(**)#(X,;:(){}[]="
|
||||
#define VLOG_PIN_NAME_DELIMITERS "X///**/(**)X()"
|
||||
#define VLOG_PIN_CHECK_DELIMITERS "X///**/(**)X(),{}"
|
||||
|
||||
// Global storage for verilog parameters
|
||||
struct hashdict verilogparams;
|
||||
@@ -291,6 +292,8 @@ int GetBusTok(struct bus *wb)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* Move token forward to bus name */
|
||||
SkipTokComments(VLOG_DELIMITERS);
|
||||
}
|
||||
else {
|
||||
struct bus *hbus;
|
||||
@@ -312,7 +315,7 @@ int GetBusTok(struct bus *wb)
|
||||
|
||||
int GetBus(char *astr, struct bus *wb)
|
||||
{
|
||||
char *colonptr, *brackstart, *brackend;
|
||||
char *colonptr, *brackstart, *brackend, *sstr;
|
||||
int result, start, end;
|
||||
|
||||
if (wb == NULL) return 0;
|
||||
@@ -320,15 +323,21 @@ int GetBus(char *astr, struct bus *wb)
|
||||
wb->start = -1;
|
||||
wb->end = -1;
|
||||
}
|
||||
brackstart = strchr(astr, '[');
|
||||
sstr = astr;
|
||||
|
||||
// Skip to the end of verilog names bounded by '\' and ' '
|
||||
if (*sstr == '\\')
|
||||
while (*sstr && *sstr != ' ') sstr++;
|
||||
|
||||
brackstart = strchr(sstr, '[');
|
||||
if (brackstart != NULL) {
|
||||
brackend = strchr(astr, ']');
|
||||
brackend = strchr(sstr, ']');
|
||||
if (brackend == NULL) {
|
||||
Printf("Badly formed array notation \"%s\"\n", astr);
|
||||
return 1;
|
||||
}
|
||||
*brackend = '\0';
|
||||
colonptr = strchr(astr, ':');
|
||||
colonptr = strchr(sstr, ':');
|
||||
if (colonptr) *colonptr = '\0';
|
||||
result = sscanf(brackstart + 1, "%d", &start);
|
||||
if (colonptr) *colonptr = ':';
|
||||
@@ -1062,14 +1071,25 @@ skip_endmodule:
|
||||
}
|
||||
}
|
||||
|
||||
else if (match(nexttok, "wire")) { /* wire = node */
|
||||
else if (match(nexttok, "wire") || match(nexttok, "assign")) { /* wire = node */
|
||||
struct bus wb, *nb;
|
||||
char nodename[128];
|
||||
int is_assignment = FALSE;
|
||||
struct objlist *lhs, *rhs;
|
||||
|
||||
// Several allowed uses of "assign":
|
||||
// "assign a = b" joins two nets.
|
||||
// "assign a = {b, c, ...}" creates a bus from components.
|
||||
// "assign" using any boolean arithmetic is not structural verilog.
|
||||
|
||||
SkipTokNoNewline(VLOG_DELIMITERS);
|
||||
if (match(nexttok, "real")) SkipTokNoNewline(VLOG_DELIMITERS);
|
||||
while (nexttok != NULL) {
|
||||
/* Handle bus notation */
|
||||
if (GetBusTok(&wb) == 0) {
|
||||
if (match(nexttok, "=")) {
|
||||
is_assignment = TRUE;
|
||||
}
|
||||
else if (GetBusTok(&wb) == 0) {
|
||||
/* Handle bus notation */
|
||||
SkipTokNoNewline(VLOG_DELIMITERS);
|
||||
if (wb.start > wb.end) {
|
||||
for (i = wb.end; i <= wb.start; i++) {
|
||||
@@ -1091,10 +1111,28 @@ skip_endmodule:
|
||||
HashPtrInstall(nexttok, nb, &buses);
|
||||
}
|
||||
else {
|
||||
if (LookupObject(nexttok, CurrentCell) == NULL)
|
||||
if (is_assignment) {
|
||||
/* Handle assignment statements */
|
||||
/* To be done: Handle where both are bus names, and */
|
||||
/* where lhs is a bus name and rhs is a list of nets */
|
||||
if ((rhs = LookupObject(nexttok, CurrentCell)) != NULL) {
|
||||
join(lhs->name, rhs->name);
|
||||
}
|
||||
else {
|
||||
Printf("Module '%s' is not structural verilog, "
|
||||
"making black-box.\n", model);
|
||||
SetClass(CLASS_MODULE);
|
||||
goto skip_endmodule;
|
||||
}
|
||||
is_assignment = FALSE;
|
||||
}
|
||||
else if (LookupObject(nexttok, CurrentCell) == NULL)
|
||||
Node(nexttok);
|
||||
lhs = LookupObject(nexttok, CurrentCell);
|
||||
}
|
||||
SkipTokNoNewline(VLOG_DELIMITERS);
|
||||
do {
|
||||
SkipTokNoNewline(VLOG_DELIMITERS);
|
||||
} while (nexttok && match(nexttok, ";"));
|
||||
}
|
||||
}
|
||||
else if (match(nexttok, "endmodule")) {
|
||||
@@ -1106,8 +1144,7 @@ skip_endmodule:
|
||||
// Ignore any other directive starting with a backtick
|
||||
SkipNewLine(VLOG_DELIMITERS);
|
||||
}
|
||||
else if (match(nexttok, "reg") || match(nexttok, "assign")
|
||||
|| match(nexttok, "always")) {
|
||||
else if (match(nexttok, "reg") || match(nexttok, "always")) {
|
||||
Printf("Module '%s' is not structural verilog, making black-box.\n", model);
|
||||
// To be done: Remove any contents (but may not be necessary)
|
||||
// Recast as module
|
||||
@@ -1201,12 +1238,12 @@ skip_endmodule:
|
||||
arraystart = wb.start;
|
||||
arrayend = wb.end;
|
||||
}
|
||||
SkipTokComments(VLOG_DELIMITERS);
|
||||
}
|
||||
|
||||
if (match(nexttok, "(")) {
|
||||
char savetok = (char)0;
|
||||
struct portelement *new_port;
|
||||
char *in_line_net = NULL;
|
||||
|
||||
// Read the pin list
|
||||
while (nexttok != NULL) {
|
||||
@@ -1233,7 +1270,7 @@ skip_endmodule:
|
||||
Printf("Badly formed subcircuit pin line at \"%s\"\n", nexttok);
|
||||
SkipNewLine(VLOG_DELIMITERS);
|
||||
}
|
||||
SkipTokComments(VLOG_PIN_NAME_DELIMITERS);
|
||||
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
|
||||
if (match(nexttok, ")")) {
|
||||
char localnet[100];
|
||||
// Empty parens, so create a new local node
|
||||
@@ -1242,7 +1279,29 @@ skip_endmodule:
|
||||
new_port->net = strsave(localnet);
|
||||
}
|
||||
else {
|
||||
new_port->net = strsave(nexttok);
|
||||
if (!strcmp(nexttok, "{")) {
|
||||
char *in_line_net = (char *)MALLOC(1);
|
||||
*in_line_net = '\0';
|
||||
/* In-line array---Read to "}" */
|
||||
while (nexttok) {
|
||||
char *new_in_line_net = (char *)MALLOC(
|
||||
strlen(in_line_net) +
|
||||
strlen(nexttok) + 1);
|
||||
strcpy(new_in_line_net, in_line_net);
|
||||
strcat(new_in_line_net, nexttok);
|
||||
FREE(in_line_net);
|
||||
in_line_net = new_in_line_net;
|
||||
if (!strcmp(nexttok, "}")) break;
|
||||
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
|
||||
}
|
||||
if (!nexttok) {
|
||||
Printf("Unterminated net in pin %s\n", in_line_net);
|
||||
}
|
||||
new_port->net = in_line_net;
|
||||
}
|
||||
else
|
||||
new_port->net = strsave(nexttok);
|
||||
|
||||
/* Read array information along with name; will be parsed later */
|
||||
SkipTokComments(VLOG_DELIMITERS);
|
||||
if (match(nexttok, "[")) {
|
||||
@@ -1251,8 +1310,8 @@ skip_endmodule:
|
||||
if (!match(nexttok, ")")) {
|
||||
char *expnet;
|
||||
expnet = (char *)MALLOC(strlen(new_port->net)
|
||||
+ strlen(nexttok) + 2);
|
||||
sprintf(expnet, "%s[%s", new_port->net, nexttok);
|
||||
+ strlen(nexttok) + 3);
|
||||
sprintf(expnet, "%s [%s", new_port->net, nexttok);
|
||||
FREE(new_port->net);
|
||||
new_port->net = expnet;
|
||||
}
|
||||
@@ -1680,10 +1739,6 @@ char *ReadVerilogTop(char *fname, int *fnum, int blackbox)
|
||||
kl->pdefault.ival = 1;
|
||||
HashPtrInstall(kl->key, kl, &verilogdefs);
|
||||
|
||||
/* All verilog files should start with a comment line, */
|
||||
/* but we won't depend upon it. Any comment line */
|
||||
/* will be handled by the main Verilog file processing. */
|
||||
|
||||
ReadVerilogFile(fname, filenum, &CellStack, blackbox);
|
||||
CloseParseFile();
|
||||
|
||||
|
||||
+168
-48
@@ -3157,19 +3157,25 @@ _netcmp_equate(ClientData clientData,
|
||||
/* add --- add new property */
|
||||
/* remove --- delete existing property */
|
||||
/* tolerance --- set property tolerance */
|
||||
/* merge --- set property merge behavior */
|
||||
/* merge --- (deprecated) */
|
||||
/* or */
|
||||
/* netgen::property default */
|
||||
/* or */
|
||||
/* netgen::property <device>|<model> <option> */
|
||||
/* yes|no */
|
||||
/* Where <option> is one of: */
|
||||
/* serial --- allow/prohibit serial combination */
|
||||
/* series --- allow/prohibit series combination */
|
||||
/* parallel --- allow/prohibit parallel combination */
|
||||
/* or */
|
||||
/* netgen::property parallel none */
|
||||
/* --- prohibit parallel combinations by */
|
||||
/* default. */
|
||||
/* default (for all devices). */
|
||||
/* */
|
||||
/* series|parallel options are: */
|
||||
/* enable|disable|none|{<key> <combine_option>} */
|
||||
/* */
|
||||
/* combine options are: */
|
||||
/* par|add|par_critical|add_critical */
|
||||
/* */
|
||||
/* Formerly: (none) */
|
||||
/* Results: */
|
||||
@@ -3189,11 +3195,11 @@ _netcmp_property(ClientData clientData,
|
||||
|
||||
char *options[] = {
|
||||
"add", "create", "remove", "delete", "tolerance", "merge", "serial",
|
||||
"parallel", NULL
|
||||
"series", "parallel", NULL
|
||||
};
|
||||
enum OptionIdx {
|
||||
ADD_IDX, CREATE_IDX, REMOVE_IDX, DELETE_IDX, TOLERANCE_IDX, MERGE_IDX,
|
||||
SERIAL_IDX, PARALLEL_IDX
|
||||
SERIAL_IDX, SERIES_IDX, PARALLEL_IDX
|
||||
};
|
||||
int result, index, idx2;
|
||||
|
||||
@@ -3204,16 +3210,30 @@ _netcmp_property(ClientData clientData,
|
||||
INTEGER_IDX, DOUBLE_IDX, VALUE_IDX, STRING_IDX
|
||||
};
|
||||
|
||||
/* Note: "merge" has been deprecated, but kept for backwards compatibility. */
|
||||
/* It has been replaced by "combineoptions" below, used with "series" and */
|
||||
/* "parallel". */
|
||||
|
||||
char *mergeoptions[] = {
|
||||
"none", "add", "add_critical", "par", "par_critical",
|
||||
"parallel", "parallel_critical", "ser_critical", "ser",
|
||||
"serial_critical", "serial", NULL
|
||||
"serial_critical", "series_critical", "serial", "series", NULL
|
||||
};
|
||||
|
||||
enum MergeOptionIdx {
|
||||
NONE_IDX, ADD_ONLY_IDX, ADD_CRIT_IDX,
|
||||
PAR_ONLY_IDX, PAR_CRIT_IDX, PAR2_ONLY_IDX, PAR2_CRIT_IDX,
|
||||
SER_CRIT_IDX, SER_IDX, SER2_CRIT_IDX, SER2_IDX
|
||||
SER_CRIT_IDX, SER_IDX, SER2_CRIT_IDX, SER3_CRIT_IDX, SER2_IDX, SER3_IDX
|
||||
};
|
||||
|
||||
char *combineoptions[] = {
|
||||
"none", "par", "add", "critical", NULL
|
||||
};
|
||||
|
||||
enum CombineOptionIdx {
|
||||
COMB_NONE_IDX, COMB_PAR_IDX, COMB_ADD_IDX, COMB_CRITICAL_IDX
|
||||
};
|
||||
|
||||
char *yesno[] = {
|
||||
"on", "yes", "true", "enable", "allow",
|
||||
"off", "no", "false", "disable", "prohibit", NULL
|
||||
@@ -3238,25 +3258,34 @@ _netcmp_property(ClientData clientData,
|
||||
case CLASS_NMOS: case CLASS_PMOS: case CLASS_FET3:
|
||||
case CLASS_NMOS4: case CLASS_PMOS4: case CLASS_FET4:
|
||||
case CLASS_FET:
|
||||
PropertyMerge(tp->name, tp->file, "w", MERGE_ADD_CRIT);
|
||||
PropertyMerge(tp->name, tp->file, "w", MERGE_P_ADD | MERGE_P_CRIT,
|
||||
MERGE_ALL_MASK);
|
||||
PropertyDelete(tp->name, tp->file, "as");
|
||||
PropertyDelete(tp->name, tp->file, "ad");
|
||||
PropertyDelete(tp->name, tp->file, "ps");
|
||||
PropertyDelete(tp->name, tp->file, "pd");
|
||||
break;
|
||||
case CLASS_RES: case CLASS_RES3:
|
||||
PropertyMerge(tp->name, tp->file, "w", MERGE_ADD_CRIT);
|
||||
PropertyMerge(tp->name, tp->file, "l", MERGE_SER_CRIT);
|
||||
tp->flags |= COMB_SERIAL;
|
||||
PropertyMerge(tp->name, tp->file, "w",
|
||||
MERGE_P_PAR | MERGE_S_CRIT, MERGE_ALL_MASK);
|
||||
PropertyMerge(tp->name, tp->file, "l",
|
||||
MERGE_S_ADD | MERGE_P_CRIT, MERGE_ALL_MASK);
|
||||
PropertyMerge(tp->name, tp->file, "value",
|
||||
MERGE_S_ADD | MERGE_P_PAR, MERGE_ALL_MASK);
|
||||
tp->flags |= COMB_SERIES;
|
||||
break;
|
||||
case CLASS_CAP: case CLASS_ECAP: case CLASS_CAP3:
|
||||
// NOTE: No attempt to combine area, width, or length;
|
||||
// only value.
|
||||
PropertyMerge(tp->name, tp->file, "value", MERGE_ADD_CRIT);
|
||||
/* NOTE: No attempt to modify perimeter, length, or width */
|
||||
PropertyMerge(tp->name, tp->file, "area",
|
||||
MERGE_P_ADD | MERGE_S_PAR, MERGE_ALL_MASK);
|
||||
PropertyMerge(tp->name, tp->file, "value",
|
||||
MERGE_P_ADD | MERGE_S_PAR, MERGE_ALL_MASK);
|
||||
tp->flags |= COMB_SERIES;
|
||||
break;
|
||||
case CLASS_INDUCTOR:
|
||||
PropertyMerge(tp->name, tp->file, "value", MERGE_PAR_CRIT);
|
||||
tp->flags |= COMB_SERIAL;
|
||||
PropertyMerge(tp->name, tp->file, "value",
|
||||
MERGE_S_ADD | MERGE_P_PAR, MERGE_ALL_MASK);
|
||||
tp->flags |= COMB_SERIES;
|
||||
break;
|
||||
}
|
||||
tp = NextCell();
|
||||
@@ -3274,7 +3303,22 @@ _netcmp_property(ClientData clientData,
|
||||
}
|
||||
else {
|
||||
Tcl_SetResult(interp, "Bad option, should be property parallel none|all",
|
||||
NONE);
|
||||
NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
else if ((objc == 3) && ((!strcmp(Tcl_GetString(objv[1]), "series")) ||
|
||||
(!strcmp(Tcl_GetString(objv[1]), "serial")))) {
|
||||
if (!strcmp(Tcl_GetString(objv[2]), "none")) {
|
||||
SetSeriesCombine(FALSE);
|
||||
}
|
||||
else if (!strcmp(Tcl_GetString(objv[2]), "all")) {
|
||||
SetSeriesCombine(TRUE);
|
||||
}
|
||||
else {
|
||||
Tcl_SetResult(interp, "Bad option, should be property series none|all",
|
||||
NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
@@ -3329,10 +3373,11 @@ _netcmp_property(ClientData clientData,
|
||||
|
||||
switch (index) {
|
||||
case SERIAL_IDX:
|
||||
case SERIES_IDX:
|
||||
case PARALLEL_IDX:
|
||||
if (objc == 3) {
|
||||
if (index == SERIAL_IDX) {
|
||||
tobj1 = Tcl_NewBooleanObj((tp->flags & COMB_SERIAL) ? 1 : 0);
|
||||
if (index == SERIAL_IDX || index == SERIES_IDX) {
|
||||
tobj1 = Tcl_NewBooleanObj((tp->flags & COMB_SERIES) ? 1 : 0);
|
||||
Tcl_SetObjResult(interp, tobj1);
|
||||
return TCL_OK;
|
||||
}
|
||||
@@ -3342,30 +3387,97 @@ _netcmp_property(ClientData clientData,
|
||||
return TCL_OK;
|
||||
}
|
||||
}
|
||||
else if (objc == 4) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[3],
|
||||
(CONST84 char **)yesno,
|
||||
"combine", 0, &idx2) != TCL_OK) {
|
||||
Tcl_WrongNumArgs(interp, 3, objv, "enable|disable");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (idx2 <= 4) { /* true, enable, etc. */
|
||||
if (index == SERIAL_IDX)
|
||||
tp->flags |= COMB_SERIAL;
|
||||
else
|
||||
tp->flags &= ~COMB_NO_PARALLEL;
|
||||
}
|
||||
else { /* false, disable, etc. */
|
||||
if (index == SERIAL_IDX)
|
||||
tp->flags &= ~COMB_SERIAL;
|
||||
else
|
||||
tp->flags |= COMB_NO_PARALLEL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "serial|parallel enable|disable");
|
||||
else if (objc < 4) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "series|parallel enable|disable");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
for (i = 3; i < objc; i++) {
|
||||
// Each value must be a list of two, or a yes/no answer.
|
||||
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i],
|
||||
(CONST84 char **)yesno,
|
||||
"combine", 0, &idx2) == TCL_OK) {
|
||||
if (idx2 <= 4) { /* true, enable, etc. */
|
||||
if (index == SERIAL_IDX || index == SERIES_IDX)
|
||||
tp->flags |= COMB_SERIES;
|
||||
else
|
||||
tp->flags &= ~COMB_NO_PARALLEL;
|
||||
}
|
||||
else { /* false, disable, etc. */
|
||||
if (index == SERIAL_IDX || index == SERIES_IDX)
|
||||
tp->flags &= ~COMB_SERIES;
|
||||
else
|
||||
tp->flags |= COMB_NO_PARALLEL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
result = Tcl_ListObjLength(interp, objv[i], &llen);
|
||||
if ((result != TCL_OK) || (llen != 2)) {
|
||||
Tcl_SetResult(interp, "Not a {key merge_type} pair list.",
|
||||
NULL);
|
||||
}
|
||||
else {
|
||||
int mergeval = MERGE_NONE;
|
||||
int mergemask = MERGE_NONE;
|
||||
|
||||
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;
|
||||
|
||||
result = Tcl_GetIndexFromObj(interp, tobj2,
|
||||
(CONST84 char **)combineoptions,
|
||||
"combine_type", 0, &idx2);
|
||||
if (result != TCL_OK) return result;
|
||||
|
||||
if (index == SERIAL_IDX || index == SERIES_IDX) {
|
||||
mergemask = MERGE_S_MASK;
|
||||
switch (idx2) {
|
||||
case COMB_NONE_IDX:
|
||||
mergeval &= ~(MERGE_S_MASK);
|
||||
tp->flags &= ~COMB_SERIES;
|
||||
break;
|
||||
case COMB_PAR_IDX:
|
||||
mergeval = MERGE_S_PAR;
|
||||
tp->flags |= COMB_SERIES;
|
||||
break;
|
||||
case COMB_ADD_IDX:
|
||||
mergeval |= MERGE_S_ADD;
|
||||
tp->flags |= COMB_SERIES;
|
||||
break;
|
||||
case COMB_CRITICAL_IDX:
|
||||
mergeval |= MERGE_S_CRIT;
|
||||
tp->flags |= COMB_SERIES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else { /* index == PARALLEL_IDX */
|
||||
mergemask = MERGE_P_MASK;
|
||||
switch (idx2) {
|
||||
case COMB_NONE_IDX:
|
||||
mergeval &= ~(MERGE_P_MASK);
|
||||
tp->flags |= COMB_NO_PARALLEL;
|
||||
break;
|
||||
case COMB_PAR_IDX:
|
||||
mergeval |= MERGE_P_PAR;
|
||||
tp->flags &= ~COMB_NO_PARALLEL;
|
||||
break;
|
||||
case COMB_ADD_IDX:
|
||||
mergeval |= MERGE_P_ADD;
|
||||
tp->flags &= ~COMB_NO_PARALLEL;
|
||||
break;
|
||||
case COMB_CRITICAL_IDX:
|
||||
mergeval |= MERGE_P_CRIT;
|
||||
tp->flags &= ~COMB_NO_PARALLEL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
PropertyMerge(tp->name, fnum, Tcl_GetString(tobj1), mergeval,
|
||||
mergemask);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ADD_IDX:
|
||||
@@ -3535,6 +3647,11 @@ _netcmp_property(ClientData clientData,
|
||||
break;
|
||||
|
||||
case MERGE_IDX:
|
||||
// NOTE: This command option is deprecated, kept for backwards
|
||||
// compatibility, with updated flag values. This command format
|
||||
// is unable to specify a property as being a critical property
|
||||
// for merging both in series and in parallel.
|
||||
|
||||
if (objc == 3) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "{property_key merge_type} ...");
|
||||
return TCL_ERROR;
|
||||
@@ -3564,29 +3681,32 @@ _netcmp_property(ClientData clientData,
|
||||
mergeval = MERGE_NONE;
|
||||
break;
|
||||
case ADD_ONLY_IDX:
|
||||
mergeval = MERGE_ADD;
|
||||
mergeval = MERGE_P_ADD;
|
||||
break;
|
||||
case ADD_CRIT_IDX:
|
||||
mergeval = MERGE_ADD_CRIT;
|
||||
mergeval = MERGE_P_ADD | MERGE_P_XCRIT;
|
||||
break;
|
||||
case PAR_ONLY_IDX:
|
||||
case PAR2_ONLY_IDX:
|
||||
mergeval = MERGE_PAR;
|
||||
mergeval = MERGE_P_PAR;
|
||||
break;
|
||||
case PAR_CRIT_IDX:
|
||||
case PAR2_CRIT_IDX:
|
||||
mergeval = MERGE_PAR_CRIT;
|
||||
mergeval = MERGE_P_PAR | MERGE_P_XCRIT;
|
||||
break;
|
||||
case SER_CRIT_IDX:
|
||||
case SER2_CRIT_IDX:
|
||||
mergeval = MERGE_SER_CRIT;
|
||||
case SER3_CRIT_IDX:
|
||||
mergeval = MERGE_S_ADD | MERGE_S_XCRIT;
|
||||
break;
|
||||
case SER_IDX:
|
||||
case SER2_IDX:
|
||||
mergeval = MERGE_SER;
|
||||
case SER3_IDX:
|
||||
mergeval = MERGE_S_ADD;
|
||||
break;
|
||||
}
|
||||
PropertyMerge(tp->name, fnum, Tcl_GetString(tobj1), mergeval);
|
||||
PropertyMerge(tp->name, fnum, Tcl_GetString(tobj1), mergeval,
|
||||
MERGE_ALL_MASK);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user