Compare commits

...
13 Commits
Author SHA1 Message Date
Tim Edwards 8e0371e09b Corrected handling of verilog backslash-escaped names in the
verilog netlist parser.
2019-05-05 10:52:07 -04:00
Tim Edwards 395f857a82 Merge branch 'master' into work 2019-01-21 20:30:42 -05:00
Tim Edwards 9e59048731 Update at Mon Jan 21 20:30:40 EST 2019 by tim 2019-01-21 20:30:40 -05:00
Tim Edwards 7889e2ae73 Small typo, large effect; wrong reference to ob1 (instead of ob2) in
flatten.c can cause a segfault when analyzing whether flattening
cells generates a better circuit match.
2019-01-21 20:29:42 -05:00
Tim Edwards 8c7d2ae239 Merge branch 'master' into work 2019-01-09 20:31:57 -05:00
Tim Edwards e361640947 Update at Wed Jan 9 20:31:54 EST 2019 by tim 2019-01-09 20:31:54 -05:00
Tim Edwards 56b4174646 Fairly substantial overhaul of the tokenizing routine to better
handle verilog syntax.  Also:  Added SPICE voltage and current
sources as separate classes (as opposed to being converted to
subcircuits, which was how they were previously handled).  That
allowed voltage sources to be checked for zero value and removed
by shorting the ends together, as was being done for zero value
resistors (note that like zero-value resistors, removal is only
done if removing the component makes a better match than leaving
it in).  In particular, yosys has SPICE netlist output that
converts equality assignments ("assign a = b") into zero-value
voltage sources, so these components need to be treated as
non-physical elements.
2019-01-09 20:26:38 -05:00
Tim Edwards ccf2dc23c9 Merge branch 'master' into work 2018-11-19 08:12:59 -05:00
Tim Edwards f8ea27d8e8 Update at Mon Nov 19 08:12:57 EST 2018 by tim 2018-11-19 08:12:57 -05:00
Tim Edwards ef914e8d46 Corrected two instances of missing values on return from a function. 2018-11-19 08:12:12 -05:00
Tim Edwards f9cc4d3db6 Merge branch 'master' into work 2018-11-18 13:09:58 -05:00
Tim Edwards d8eefdad9a Update at Sun Nov 18 13:09:56 EST 2018 by tim 2018-11-18 13:09:56 -05:00
Tim Edwards 2cdf3c450f Extended the series/parallel merging setup commands to include
the possibility that a device (e.g., resistor or capacitor) may
not be a semiconductor device (in other words, a parasitic or
ideal device), and therefore uses "value" but not width and
length, and therefore "value" is a critical property to merge
both in series and parallel.  Corrected the series/parallel
network optimization to prevent it from setting both M and S
records > 1 on the same device (which is ambiguous).  To try
to get number of devices to match, where there are both series
and parallel devices, they will be merged across the critical
property early (before property matching).
2018-11-18 13:04:57 -05:00
11 changed files with 814 additions and 364 deletions
+1 -1
View File
@@ -1 +1 @@
1.5.113
1.5.117
+8 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;