mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-27 00:16:37 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48c9e6b292 | ||
|
|
527cdb3dab | ||
|
|
ced5846da3 | ||
|
|
b99d33064f | ||
|
|
ee66c00121 | ||
|
|
f40a50d3b8 | ||
|
|
399472e940 | ||
|
|
8e0371e09b | ||
|
|
395f857a82 | ||
|
|
9e59048731 | ||
|
|
7889e2ae73 | ||
|
|
8c7d2ae239 | ||
|
|
e361640947 | ||
|
|
56b4174646 | ||
|
|
ccf2dc23c9 | ||
|
|
f8ea27d8e8 | ||
|
|
ef914e8d46 |
@@ -9,4 +9,3 @@ config.status
|
||||
*~
|
||||
*.log
|
||||
UPDATE_ME
|
||||
VERSION
|
||||
|
||||
+7
-5
@@ -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,
|
||||
|
||||
+84
-123
@@ -3704,30 +3704,10 @@ int series_optimize(struct objlist *ob1, struct nlist *tp1, int idx1,
|
||||
return PropertyOptimize(obn, tp1, run1, TRUE, comb);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Combine properties of ob1 starting at property idx1 up to */
|
||||
/* property (idx1 + run1) to match the properties of ob2 at */
|
||||
/* idx2 to (idx2 + run2). run1 is always larger than run2. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
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;
|
||||
int i, j;
|
||||
int changed = 0;
|
||||
|
||||
obn = ob1;
|
||||
for (i = 0; i < idx1; i++) obn = obn->next;
|
||||
obp = ob2;
|
||||
for (i = 0; i < idx2; i++) obp = obp->next;
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
typedef struct _propsort {
|
||||
double value;
|
||||
int idx;
|
||||
unsigned char flags;
|
||||
struct objlist *ob;
|
||||
} propsort;
|
||||
|
||||
@@ -3748,7 +3728,9 @@ static int compsort(const void *p1, const void *p2)
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Sort properties of ob1 starting at property idx1 up to */
|
||||
/* property (idx1 + run). Use series critical property for */
|
||||
/* sorting. Multiply critical property by S before sort. */
|
||||
/* 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. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
@@ -3764,8 +3746,8 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
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));
|
||||
@@ -3779,7 +3761,7 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
vl = &(obp->instance.props[p]);
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
if (vl->key == NULL) continue;
|
||||
if (!strcmp(vl->key, "S")) {
|
||||
if ((*matchfunc)(vl->key, "S")) {
|
||||
sval = vl->value.ival;
|
||||
sl = vl;
|
||||
}
|
||||
@@ -3839,27 +3821,6 @@ int parallel_optimize(struct objlist *ob1, struct nlist *tp1, int idx1,
|
||||
return PropertyOptimize(obn, tp1, run1, FALSE, comb);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Combine properties of ob1 starting at property idx1 up to */
|
||||
/* property (idx1 + run1) to match the properties of ob2 at */
|
||||
/* idx2 to (idx2 + run2). run1 is always larger than run2. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
int parallel_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;
|
||||
int i, j;
|
||||
int changed = 0;
|
||||
|
||||
obn = ob1;
|
||||
for (i = 0; i < idx1; i++) obn = obn->next;
|
||||
obp = ob2;
|
||||
for (i = 0; i < idx2; i++) obp = obp->next;
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Sort properties of ob1 starting at property idx1 up to */
|
||||
/* property (idx1 + run). Use parallel critical property for */
|
||||
@@ -3903,7 +3864,7 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
vl = &(obp->instance.props[p]);
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
if (vl->key == NULL) continue;
|
||||
if (!strcmp(vl->key, "M")) {
|
||||
if ((*matchfunc)(vl->key, "M")) {
|
||||
mval = vl->value.ival;
|
||||
ml = vl;
|
||||
}
|
||||
@@ -3949,7 +3910,7 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
vl = &(obp->instance.props[p]);
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
if (vl->key == NULL) continue;
|
||||
if (!strcmp(vl->key, "M")) {
|
||||
if ((*matchfunc)(vl->key, "M")) {
|
||||
mval = vl->value.ival;
|
||||
ml = vl;
|
||||
}
|
||||
@@ -3957,7 +3918,7 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
if (kl == NULL) continue; /* Ignored property */
|
||||
if (subs_crit == NULL)
|
||||
subs_crit = vl->key;
|
||||
if ((subs_crit != NULL) && !strcmp(vl->key, subs_crit)) {
|
||||
if ((subs_crit != NULL) && (*matchfunc)(vl->key, subs_crit)) {
|
||||
if ((vl->type == PROP_STRING || vl->type == PROP_EXPRESSION) &&
|
||||
(kl->type != vl->type))
|
||||
PromoteProperty(kl, vl);
|
||||
@@ -4195,20 +4156,6 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
||||
ob2 = pre2->next;
|
||||
}
|
||||
|
||||
/* Do not run parallel_combine until all other changes have been resolved */
|
||||
if (changed == 0) {
|
||||
if (max2 > max1)
|
||||
changed += parallel_combine(ob2, tp2, idx2, max2, ob1, tp1, idx1, max1);
|
||||
else if (max1 > max2)
|
||||
changed += parallel_combine(ob1, tp1, idx1, max1, ob2, tp2, idx2, max2);
|
||||
|
||||
if (changed > 0) {
|
||||
FREE(netwk1);
|
||||
FREE(netwk2);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Case 2: Series devices with more elements in one circuit */
|
||||
|
||||
/* Find the largest group of series devices in circuit1 */
|
||||
@@ -4294,14 +4241,6 @@ void PropertySortAndCombine(struct objlist *pre1, struct nlist *tp1,
|
||||
ob2 = pre2->next;
|
||||
}
|
||||
|
||||
/* Do not run series_combine until all other changes have been resolved */
|
||||
if (changed == 0) {
|
||||
if (max2 > max1)
|
||||
changed += series_combine(ob2, tp2, idx2, max2, ob1, tp1, idx1, max1);
|
||||
else if (max1 > max2)
|
||||
changed += series_combine(ob1, tp1, idx1, max1, ob2, tp2, idx2, max2);
|
||||
}
|
||||
|
||||
FREE(netwk1);
|
||||
FREE(netwk2);
|
||||
|
||||
@@ -4335,9 +4274,10 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
{
|
||||
struct objlist *ob2, *obt;
|
||||
struct property *kl, *m_rec, **plist;
|
||||
unsigned char **clist;
|
||||
struct valuelist ***vlist, *vl, *vl2, *newvlist;
|
||||
proplinkptr plink, ptop;
|
||||
int pcount, p, i, j, k, pmatch, ival, crit, ctype;
|
||||
int pcount, p, i, j, k, pmatch, ival, ctype;
|
||||
double dval;
|
||||
static struct valuelist nullvl, dfltvl;
|
||||
char multiple[2], other[2];
|
||||
@@ -4359,8 +4299,6 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
m_rec = NULL;
|
||||
ptop = NULL;
|
||||
pcount = 1;
|
||||
crit = -1;
|
||||
ctype = -1;
|
||||
kl = (struct property *)HashFirst(&(tp->propdict));
|
||||
while (kl != NULL) {
|
||||
// Make a linked list so we don't have to iterate through the hash again
|
||||
@@ -4375,31 +4313,22 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
else
|
||||
kl->idx = pcount++;
|
||||
|
||||
// Set critical property index, if there is one.
|
||||
// To do: deal with possibility of multiple critical properties
|
||||
// per instance?
|
||||
|
||||
if ((series == FALSE) && (kl->merge & MERGE_P_CRIT)) {
|
||||
crit = kl->idx;
|
||||
ctype = kl->merge & (MERGE_P_ADD | MERGE_P_PAR);
|
||||
}
|
||||
else if ((series == TRUE) && (kl->merge & MERGE_S_CRIT)) {
|
||||
crit = kl->idx;
|
||||
ctype = kl->merge & (MERGE_S_ADD | MERGE_S_PAR);
|
||||
}
|
||||
|
||||
kl = (struct property *)HashNext(&(tp->propdict));
|
||||
}
|
||||
// Recast the linked list as an array
|
||||
plist = (struct property **)CALLOC(pcount, sizeof(struct property *));
|
||||
vlist = (struct valuelist ***)CALLOC(pcount, sizeof(struct valuelist **));
|
||||
if (m_rec == NULL)
|
||||
clist = (unsigned char **)CALLOC(pcount, sizeof(unsigned char *));
|
||||
if (m_rec == NULL) {
|
||||
vlist[0] = (struct valuelist **)CALLOC(run, sizeof(struct valuelist *));
|
||||
clist[0] = (unsigned char *)CALLOC(run, sizeof(unsigned char));
|
||||
}
|
||||
|
||||
while (ptop != NULL) {
|
||||
plist[ptop->prop->idx] = ptop->prop;
|
||||
vlist[ptop->prop->idx] = (struct valuelist **)CALLOC(run,
|
||||
sizeof(struct valuelist *));
|
||||
clist[ptop->prop->idx] = (unsigned char *)CALLOC(run, sizeof(unsigned char));
|
||||
plink = ptop;
|
||||
FREE(ptop);
|
||||
ptop = plink->next;
|
||||
@@ -4433,6 +4362,16 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
}
|
||||
else if (kl != NULL) {
|
||||
vlist[kl->idx][i] = vl;
|
||||
if (series == FALSE) {
|
||||
if (kl->merge & (MERGE_P_ADD | MERGE_P_PAR))
|
||||
clist[kl->idx][i] = kl->merge &
|
||||
(MERGE_P_ADD | MERGE_P_PAR | MERGE_P_CRIT);
|
||||
}
|
||||
else if (series == TRUE) {
|
||||
if (kl->merge & (MERGE_S_ADD | MERGE_S_PAR))
|
||||
clist[kl->idx][i] = kl->merge &
|
||||
(MERGE_S_ADD | MERGE_S_PAR | MERGE_S_CRIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (++i == run) break;
|
||||
@@ -4494,11 +4433,20 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
// Additive properties do not need to be matched, since
|
||||
// they can be combined. Critical paroperties must be
|
||||
// matched. Properties with no merge behavior must match.
|
||||
|
||||
ctype = clist[p][i];
|
||||
if (!(ctype & MERGE_S_CRIT)) {
|
||||
if ((series == TRUE) && (ctype & (MERGE_S_ADD | MERGE_S_PAR))) {
|
||||
pmatch++;
|
||||
continue;
|
||||
}
|
||||
if ((series == FALSE) && (ctype & (MERGE_P_ADD | MERGE_P_PAR))) {
|
||||
pmatch++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch(vl->type) {
|
||||
@@ -4587,42 +4535,53 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
}
|
||||
}
|
||||
|
||||
// If comb == TRUE, reduce M (or S) to 1 by merging the critical
|
||||
// property (if any)
|
||||
// If comb == TRUE, reduce M (or S) to 1 by merging additive properties
|
||||
// (if any)
|
||||
|
||||
if ((comb == TRUE) && (crit != -1)) {
|
||||
if (comb == TRUE) {
|
||||
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 ((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);
|
||||
/* For all properties that are not M, S, or crit, */
|
||||
/* combine as specified by the merge type of the property. */
|
||||
|
||||
for (p = 1; p < pcount; p++) {
|
||||
vl = vlist[p][i];
|
||||
ctype = clist[p][i];
|
||||
|
||||
/* critical properties never combine */
|
||||
if ((series == TRUE) && (ctype & MERGE_S_CRIT)) continue;
|
||||
if ((series == FALSE) && (ctype & MERGE_P_CRIT)) continue;
|
||||
|
||||
if (ctype & (MERGE_S_ADD | 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 | 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4649,9 +4608,11 @@ cleanup:
|
||||
kl = (struct property *)plist[p];
|
||||
if (kl) kl->idx = 0;
|
||||
FREE(vlist[p]);
|
||||
FREE(clist[p]);
|
||||
}
|
||||
FREE(plist);
|
||||
FREE(vlist);
|
||||
FREE(clist);
|
||||
|
||||
return changed;
|
||||
}
|
||||
@@ -4910,9 +4871,9 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1,
|
||||
kl2 = &klm;
|
||||
else if (vl2 == &svl)
|
||||
kl2 = &kls;
|
||||
else if (vl1 == &mvl)
|
||||
else if ((*matchfunc)(vl2->key, mvl.key))
|
||||
kl2 = &klm;
|
||||
else if (vl1 == &svl)
|
||||
else if ((*matchfunc)(vl2->key, svl.key))
|
||||
kl2 = &kls;
|
||||
else
|
||||
continue;
|
||||
|
||||
+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) {
|
||||
|
||||
+2
-3
@@ -2489,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 */
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
@@ -3063,7 +3062,7 @@ int remove_group_tags(struct objlist *ob)
|
||||
for (nob = ob->next; nob && nob->type != FIRSTPIN; nob = nob->next)
|
||||
if (nob->type == PROPERTY)
|
||||
break;
|
||||
if (nob->type != PROPERTY) return; // shouldn't happen
|
||||
if (nob->type != PROPERTY) return 0; // shouldn't happen
|
||||
|
||||
for (sob = NULL; nob && nob->type == PROPERTY; nob = nob->next) {
|
||||
for (i = 0; ; i++) {
|
||||
|
||||
+4
-2
@@ -87,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,
|
||||
|
||||
+7
-5
@@ -108,13 +108,15 @@ struct valuelist {
|
||||
#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 0x08 /* Properties sum with device series merge */
|
||||
#define MERGE_S_PAR 0x10 /* Properties add in parallel with series merge */
|
||||
#define MERGE_S_CRIT 0x20 /* This property enables series merging */
|
||||
#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)
|
||||
#define MERGE_S_MASK (MERGE_S_ADD | MERGE_S_PAR | MERGE_S_CRIT)
|
||||
#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. */
|
||||
|
||||
+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();
|
||||
|
||||
|
||||
+19
-30
@@ -3227,12 +3227,11 @@ _netcmp_property(ClientData clientData,
|
||||
};
|
||||
|
||||
char *combineoptions[] = {
|
||||
"none", "par", "add", "par_critical", "add_critical", NULL
|
||||
"none", "par", "add", "critical", NULL
|
||||
};
|
||||
|
||||
enum CombineOptionIdx {
|
||||
COMB_NONE_IDX, COMB_PAR_IDX, COMB_ADD_IDX, COMB_PAR_CRITICAL_IDX,
|
||||
COMB_ADD_CRITICAL_IDX
|
||||
COMB_NONE_IDX, COMB_PAR_IDX, COMB_ADD_IDX, COMB_CRITICAL_IDX
|
||||
};
|
||||
|
||||
char *yesno[] = {
|
||||
@@ -3268,24 +3267,24 @@ _netcmp_property(ClientData clientData,
|
||||
break;
|
||||
case CLASS_RES: case CLASS_RES3:
|
||||
PropertyMerge(tp->name, tp->file, "w",
|
||||
MERGE_P_PAR | MERGE_P_CRIT, MERGE_ALL_MASK);
|
||||
MERGE_P_PAR | MERGE_S_CRIT, MERGE_ALL_MASK);
|
||||
PropertyMerge(tp->name, tp->file, "l",
|
||||
MERGE_S_ADD | MERGE_S_CRIT, MERGE_ALL_MASK);
|
||||
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.
|
||||
/* 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_P_CRIT |
|
||||
MERGE_S_PAR | MERGE_S_CRIT, MERGE_ALL_MASK);
|
||||
MERGE_P_ADD | MERGE_S_PAR, MERGE_ALL_MASK);
|
||||
tp->flags |= COMB_SERIES;
|
||||
break;
|
||||
case CLASS_INDUCTOR:
|
||||
PropertyMerge(tp->name, tp->file, "value",
|
||||
MERGE_P_PAR | MERGE_P_CRIT |
|
||||
MERGE_S_PAR | MERGE_S_CRIT, MERGE_ALL_MASK);
|
||||
MERGE_S_ADD | MERGE_P_PAR, MERGE_ALL_MASK);
|
||||
tp->flags |= COMB_SERIES;
|
||||
break;
|
||||
}
|
||||
@@ -3437,8 +3436,7 @@ _netcmp_property(ClientData clientData,
|
||||
mergemask = MERGE_S_MASK;
|
||||
switch (idx2) {
|
||||
case COMB_NONE_IDX:
|
||||
mergeval &= ~(MERGE_S_ADD | MERGE_S_PAR
|
||||
| MERGE_S_CRIT);
|
||||
mergeval &= ~(MERGE_S_MASK);
|
||||
tp->flags &= ~COMB_SERIES;
|
||||
break;
|
||||
case COMB_PAR_IDX:
|
||||
@@ -3449,12 +3447,8 @@ _netcmp_property(ClientData clientData,
|
||||
mergeval |= MERGE_S_ADD;
|
||||
tp->flags |= COMB_SERIES;
|
||||
break;
|
||||
case COMB_PAR_CRITICAL_IDX:
|
||||
mergeval |= (MERGE_S_PAR | MERGE_S_CRIT);
|
||||
tp->flags |= COMB_SERIES;
|
||||
break;
|
||||
case COMB_ADD_CRITICAL_IDX:
|
||||
mergeval |= (MERGE_S_ADD | MERGE_S_CRIT);
|
||||
case COMB_CRITICAL_IDX:
|
||||
mergeval |= MERGE_S_CRIT;
|
||||
tp->flags |= COMB_SERIES;
|
||||
break;
|
||||
}
|
||||
@@ -3463,8 +3457,7 @@ _netcmp_property(ClientData clientData,
|
||||
mergemask = MERGE_P_MASK;
|
||||
switch (idx2) {
|
||||
case COMB_NONE_IDX:
|
||||
mergeval &= ~(MERGE_P_ADD | MERGE_P_PAR
|
||||
| MERGE_P_CRIT);
|
||||
mergeval &= ~(MERGE_P_MASK);
|
||||
tp->flags |= COMB_NO_PARALLEL;
|
||||
break;
|
||||
case COMB_PAR_IDX:
|
||||
@@ -3475,12 +3468,8 @@ _netcmp_property(ClientData clientData,
|
||||
mergeval |= MERGE_P_ADD;
|
||||
tp->flags &= ~COMB_NO_PARALLEL;
|
||||
break;
|
||||
case COMB_PAR_CRITICAL_IDX:
|
||||
mergeval |= (MERGE_P_PAR | MERGE_P_CRIT);
|
||||
tp->flags &= ~COMB_NO_PARALLEL;
|
||||
break;
|
||||
case COMB_ADD_CRITICAL_IDX:
|
||||
mergeval |= (MERGE_P_ADD | MERGE_P_CRIT);
|
||||
case COMB_CRITICAL_IDX:
|
||||
mergeval |= MERGE_P_CRIT;
|
||||
tp->flags &= ~COMB_NO_PARALLEL;
|
||||
break;
|
||||
}
|
||||
@@ -3695,7 +3684,7 @@ _netcmp_property(ClientData clientData,
|
||||
mergeval = MERGE_P_ADD;
|
||||
break;
|
||||
case ADD_CRIT_IDX:
|
||||
mergeval = MERGE_P_ADD | MERGE_P_CRIT;
|
||||
mergeval = MERGE_P_ADD | MERGE_P_XCRIT;
|
||||
break;
|
||||
case PAR_ONLY_IDX:
|
||||
case PAR2_ONLY_IDX:
|
||||
@@ -3703,12 +3692,12 @@ _netcmp_property(ClientData clientData,
|
||||
break;
|
||||
case PAR_CRIT_IDX:
|
||||
case PAR2_CRIT_IDX:
|
||||
mergeval = MERGE_P_PAR | MERGE_P_CRIT;
|
||||
mergeval = MERGE_P_PAR | MERGE_P_XCRIT;
|
||||
break;
|
||||
case SER_CRIT_IDX:
|
||||
case SER2_CRIT_IDX:
|
||||
case SER3_CRIT_IDX:
|
||||
mergeval = MERGE_S_ADD | MERGE_S_CRIT;
|
||||
mergeval = MERGE_S_ADD | MERGE_S_XCRIT;
|
||||
break;
|
||||
case SER_IDX:
|
||||
case SER2_IDX:
|
||||
|
||||
Reference in New Issue
Block a user