Compare commits

...
17 Commits
Author SHA1 Message Date
Tim Edwards 48c9e6b292 Merge branch 'master' into netgen-1.5 2019-06-13 03:00:05 -04:00
Tim Edwards 527cdb3dab Corrected error in detecting S and M. 2019-06-12 11:11:28 -04:00
Tim Edwards ced5846da3 "ocd_git_pure automatic update to repo" 2019-05-18 03:00:05 -04:00
Tim Edwards b99d33064f Merge branch 'master' into netgen-1.5 2019-05-18 03:00:04 -04:00
Tim Edwards ee66c00121 Further refined the last commit based on the change in definition of
a "critical property".  This lets a device define multiple critical
properties, all of which must match before additive properties can
be combined in the same device.
2019-05-17 14:33:26 -04:00
Tim Edwards f40a50d3b8 Corrected property value merging (again). By the rules of the
re-worked property command, "critical" properties must match
across devices so that all other properties can be combined as
specified (addition, parallel combination, or none).  The code was
still based on the older notion of the "critical" property being
the one to add (and thus preventing multiple properties from being
added in different ways).  This has now been fixed.
2019-05-17 11:25:34 -04:00
Tim Edwards 399472e940 "ocd_git_pure automatic update to repo" 2019-05-07 09:13:00 -04:00
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
11 changed files with 258 additions and 200 deletions
-1
View File
@@ -9,4 +9,3 @@ config.status
*~
*.log
UPDATE_ME
VERSION
+1 -1
View File
@@ -1 +1 @@
1.5.114
1.5.120
+7 -5
View File
@@ -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
View File
@@ -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
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) {
+2 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
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();
+19 -30
View File
@@ -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: