summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2019-10-19 11:16:40 +0200
committerRuben Undheim <ruben.undheim@gmail.com>2019-10-19 11:16:40 +0200
commit9533572cd883ec7e30ff6c5e4283c6e3bb9b75f0 (patch)
treec46a4f67f8e3e1e81637ee949627b172a15dda64
parent2e6501ce6a1d655c636bc7ed01ee50ba7d0d26ac (diff)
parent519925f7484ec32feec6ded0504edc457ccc29ed (diff)
Update upstream source from tag 'upstream/1.5.133'
Update to upstream version '1.5.133' with Debian dir 92b0bbf919a079e9162ea08fd6af7c7d2357c964
-rw-r--r--.gitignore4
-rw-r--r--README2
-rw-r--r--VERSION2
-rw-r--r--base/netcmp.c198
-rw-r--r--base/netfile.c265
-rw-r--r--base/netfile.h2
-rw-r--r--base/objlist.c4
-rw-r--r--base/verilog.c764
-rwxr-xr-xconfigure2
-rwxr-xr-xscripts/configure2
-rw-r--r--scripts/configure.in2
-rwxr-xr-xscripts/makedbh187
-rw-r--r--tcltk/tclnetgen.c4
-rwxr-xr-xtcltk/tkcon.tcl20
14 files changed, 850 insertions, 608 deletions
diff --git a/.gitignore b/.gitignore
index bcdb7e4..378fac5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,14 @@
netgen
netgenexec
defs.mak
+scripts/defs.mak
config.cache
config.log
+scripts/config.log
config.status
+scripts/config.status
*.o
*.so
*~
*.log
UPDATE_ME
-VERSION
diff --git a/README b/README
index 0a0a899..e0b3173 100644
--- a/README
+++ b/README
@@ -85,6 +85,8 @@ and IRSIM version 9.7:
make
make install
+Note: For FreeBSD, use 'gmake' instead.
+
IN CASE OF FAILURE
-------------------
Please contact me (tim@opencircuitdesign.com) to report compile-time and
diff --git a/VERSION b/VERSION
index 3c2b324..c56bf84 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.5.118
+1.5.133
diff --git a/base/netcmp.c b/base/netcmp.c
index 38272fb..21d048c 100644
--- a/base/netcmp.c
+++ b/base/netcmp.c
@@ -3704,27 +3704,6 @@ 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;
@@ -3782,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;
}
@@ -3843,27 +3822,6 @@ int parallel_optimize(struct objlist *ob1, struct nlist *tp1, int idx1,
}
/*--------------------------------------------------------------*/
-/* 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 */
/* sorting. Multiply critical property by M before sort. */
@@ -3906,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;
}
@@ -3952,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;
}
@@ -3960,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);
@@ -4198,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 */
@@ -4297,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);
@@ -4338,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];
@@ -4362,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
@@ -4378,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.
-
- 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 (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
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;
@@ -4436,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;
@@ -4497,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) {
@@ -4590,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);
+ }
}
}
}
@@ -4652,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;
}
@@ -4913,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;
diff --git a/base/netfile.c b/base/netfile.c
index dd29d3c..5dd140e 100644
--- a/base/netfile.c
+++ b/base/netfile.c
@@ -47,6 +47,18 @@ static FILE *outfile;
static int Graph = 0;
int File;
+/*------------------------------------------------------*/
+/* Structure for stacking nested `if[n]def in verilog */
+/*------------------------------------------------------*/
+
+struct ifstack {
+ int invert;
+ struct property *kl;
+ struct ifstack *next;
+};
+
+struct ifstack *condstack = NULL;
+
extern char *SetExtension(char *buffer, char *path, char *extension)
/* add 'extension' to 'path' (overwriting previous extension, if any),
write it into buffer (if buffer is null, malloc a buffer).
@@ -191,6 +203,8 @@ struct filestack {
static struct filestack *OpenFiles = NULL;
+struct hashdict *definitions = (struct hashdict *)NULL;
+
#define WHITESPACE_DELIMITER " \t\n\r"
/*----------------------------------------------------------------------*/
@@ -251,7 +265,6 @@ void TrimQuoted(char *line)
}
}
}
-
}
/*----------------------------------------------------------------------*/
@@ -265,39 +278,202 @@ void TrimQuoted(char *line)
int GetNextLineNoNewline(char *delimiter)
{
- char *newbuf;
- int testc;
+ char *newbuf;
+ int testc;
+ int nested = 0;
- if (feof(infile)) return -1;
+ if (feof(infile)) return -1;
- // This is more reliable than feof() ...
- testc = getc(infile);
- if (testc == -1) return -1;
- ungetc(testc, infile);
+ while (1) { /* May loop indefinitely in an `if[n]def conditional */
- if (linesize == 0) {
- /* Allocate memory for line */
- linesize = 500;
- line = (char *)MALLOC(linesize);
- linetok = (char *)MALLOC(linesize);
- }
- fgets(line, linesize, infile);
- while (strlen(line) == linesize - 1) {
- newbuf = (char *)MALLOC(linesize + 500);
- strcpy(newbuf, line);
- FREE(line);
- line = newbuf;
- fgets(line + linesize - 1, 501, infile);
- linesize += 500;
- FREE(linetok);
- linetok = (char *)MALLOC(linesize);
- }
- linenum++;
- strcpy(linetok, line);
- TrimQuoted(linetok);
+ // This is more reliable than feof() ...
+ testc = getc(infile);
+ if (testc == -1) return -1;
+ ungetc(testc, infile);
+
+ if (linesize == 0) {
+ /* Allocate memory for line */
+ linesize = 500;
+ line = (char *)MALLOC(linesize);
+ linetok = (char *)MALLOC(linesize);
+ }
+ fgets(line, linesize, infile);
+ while (strlen(line) == linesize - 1) {
+ newbuf = (char *)MALLOC(linesize + 500);
+ strcpy(newbuf, line);
+ FREE(line);
+ line = newbuf;
+ fgets(line + linesize - 1, 501, infile);
+ linesize += 500;
+ FREE(linetok);
+ linetok = (char *)MALLOC(linesize);
+ }
+
+ /* Check for substitutions (verilog only). Make sure linetok is */
+ /* large enough to hold the entire line after substitutions. */
+
+ if (definitions != NULL) {
+ char *s, *w, e;
+ struct property *kl;
+ int len, dlen, vlen, addin = 0;
+ unsigned char found = FALSE;
+
+ for (s = line; *s != '\0'; s++) {
+ if (*s == '`') {
+ w = s + 1;
+ while (isalnum(*w)) w++;
+ e = *w;
+ *w = '\0';
+ kl = (struct property *)HashLookup(s + 1, definitions);
+ if (kl != NULL) {
+ dlen = strlen(s);
+ if (kl->type == PROP_STRING) {
+ vlen = strlen(kl->pdefault.string);
+ }
+ else vlen = 12; /* Leave room for numeric conversion */
+ addin += vlen - dlen + 1;
+ found = TRUE;
+ }
+ *w = e;
+ }
+ }
+ if (found) {
+ len = strlen(line);
+ if (len + addin > linesize) {
+ while (len + addin > linesize) linesize += 500;
+ FREE(linetok);
+ linetok = (char *)MALLOC(linesize);
+ }
+ }
+ }
+
+ /* Make definition substitutions (verilog only) */
+
+ if (definitions != NULL) {
+ char *s, *t, *w, e;
+ struct property *kl;
+
+ t = linetok;
+ for (s = line; *s != '\0'; s++) {
+ if (*s == '`') {
+ w = s + 1;
+ while (isalnum(*w)) w++;
+ e = *w;
+ *w = '\0';
+ kl = (struct property *)HashLookup(s + 1, definitions);
+ if (kl != NULL) {
+ if (kl->type == PROP_STRING)
+ strcpy(t, kl->pdefault.string);
+ else if (kl->type == PROP_INTEGER)
+ sprintf(t, "%d", kl->pdefault.ival);
+ else if (kl->type == PROP_DOUBLE)
+ sprintf(t, "%g", kl->pdefault.dval);
+ t += strlen(t);
+ s = w - 1;
+ }
+ else *t++ = *s;
+ *w = e;
+ }
+ else *t++ = *s;
+ }
+ *t = '\0';
+ }
+ else
+ strcpy(linetok, line);
+
+ TrimQuoted(linetok);
+ linenum++;
+
+ nexttok = strdtok(linetok, WHITESPACE_DELIMITER, delimiter);
+ if (nexttok == NULL) return 0;
+
+ /* Handle `ifdef, `ifndef, `elsif, `else, and `endif (verilog */
+ /* only, where indicated by a non-NULL "definitions") */
+
+ if (definitions == NULL) return 0;
+
+ /* If currently skipping through a section, handle conditionals differently */
+
+ if (condstack) {
+ if (((condstack->invert == 0) && (condstack->kl == NULL))
+ || ((condstack->invert == 1) && (condstack->kl != NULL))) {
+ if (match(nexttok, "`ifdef") || match(nexttok, "`ifndef")) {
+ nested++;
+ continue;
+ }
+ else if (nested > 0) {
+ if (match(nexttok, "`endif")) nested--;
+ continue;
+ }
+ else if (nexttok[0] != '`') continue;
+ }
+ }
+
+ /* Handle conditionals (that is not being skipped over) */
+
+ if (match(nexttok, "`endif")) {
+ if (condstack == NULL) {
+ fprintf(stderr, "Error: `endif without corresponding `if[n]def\n");
+ }
+ else {
+ struct ifstack *iftop = condstack;
+ condstack = condstack->next;
+ FREE(iftop);
+ }
+ }
- nexttok = strdtok(linetok, WHITESPACE_DELIMITER, delimiter);
- return 0;
+ /* Note that `if[n]def may be nested. */
+
+ else if (match(nexttok, "`ifdef") || match(nexttok, "`ifndef") ||
+ match(nexttok, "`elsif") || match(nexttok, "`else")) {
+
+ /* Every `ifdef or `ifndef increases condstack by 1 */
+ if (nexttok[1] == 'i') {
+ struct ifstack *newif = (struct ifstack *)MALLOC(sizeof(struct ifstack));
+ newif->next = condstack;
+ condstack = newif;
+ }
+ if (condstack == NULL) {
+ fprintf(stderr, "Error: %s without `if[n]def\n", nexttok);
+ break;
+ }
+ else {
+ if (match(nexttok, "`else")) {
+ /* Invert the sense of the if[n]def scope */
+ condstack->invert = (condstack->invert == 1) ? 0 : 1;
+ }
+ else if (match(nexttok, "`elsif")) {
+ nexttok = strdtok(NULL, WHITESPACE_DELIMITER, delimiter);
+ if (nexttok == NULL) {
+ fprintf(stderr, "Error: `elsif with no conditional.\n");
+ return 0;
+ }
+ /* Keep the same scope but redefine the parameter */
+ condstack->invert = 0;
+ condstack->kl = (struct property *)HashLookup(nexttok, definitions);
+ }
+ else {
+ condstack->invert = (nexttok[3] == 'n') ? 1 : 0;
+ nexttok = strdtok(NULL, WHITESPACE_DELIMITER, delimiter);
+ if (nexttok == NULL) {
+ fprintf(stderr, "Error: %s with no conditional.\n", nexttok);
+ return 0;
+ }
+ condstack->kl = (struct property *)HashLookup(nexttok, definitions);
+ }
+ }
+ }
+ else if (condstack) {
+ if (((condstack->invert == 0) && (condstack->kl == NULL))
+ || ((condstack->invert == 1) && (condstack->kl != NULL)))
+ continue;
+ else
+ break;
+ }
+ else
+ break;
+ }
+ return 0;
}
/*----------------------------------------------------------------------*/
@@ -471,6 +647,33 @@ 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". */
+
+ /* Special verilog rule exception: To handle the problems caused by */
+ /* translating verilog backslash-escaped names into other netlist formats */
+ /* like SPICE where the convention is strictly prohibited, I have used the */
+ /* convention in qflow scripts to replace the trailing space with another */
+ /* backslash, so the name is effectively delimited by a pair of back- */
+ /* slashes. Therefore check for a space or another backslash, whichever */
+ /* comes first. That will satisfy both methods. Technically this routine */
+ /* should know whether it is parsing SPICE or verilog and handle the syntax */
+ /* accordingly (needs to be done). */
+
+ if (*s == '\\') {
+ while (*s != '\0') {
+ if ((*s == ' ') || (*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 */
@@ -479,7 +682,7 @@ 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++) {
+ for (; *s; s++) {
twofer = (delim2 && (*delim2 == 'X')) ? TRUE : FALSE;
for (s2 = ((twofer == TRUE) ? delim2 + 1 : delim2); s2 && *s2; s2++) {
if (*s2 == 'X') {
diff --git a/base/netfile.h b/base/netfile.h
index fbcf413..3fe7ffe 100644
--- a/base/netfile.h
+++ b/base/netfile.h
@@ -24,6 +24,7 @@ extern void FlushString (char *format, ...);
extern char *SetExtension(char *buffer, char *path, char *extension);
extern int File;
+extern struct hashdict *definitions;
/* input routines */
@@ -32,6 +33,7 @@ extern char *nexttok;
extern char *strdtok(char *pstring, char *delim1, char *delim2);
extern void SkipTok(char *delimiter);
extern void SkipTokNoNewline(char *delimiter);
+extern void SkipTokComments(char *delimiter);
extern void SkipNewLine(char *delimiter);
extern void SpiceTokNoNewline(void); /* handles SPICE "+" continuation line */
extern void SpiceSkipNewLine(void); /* handles SPICE "+" continuation line */
diff --git a/base/objlist.c b/base/objlist.c
index 14df071..e864a17 100644
--- a/base/objlist.c
+++ b/base/objlist.c
@@ -598,7 +598,11 @@ static int PrintCellHashTableElement(struct hashlist *p)
if (Debug == 1) Printf("Cell: %s (instanced %d times); Primitive\n",
ptr->name, ptr->number);
else if (Debug == 3) { /* list */
+#ifdef TCL_NETGEN
Tcl_AppendElement(netgeninterp, ptr->name);
+#else
+ Printf("%s ", ptr->name);
+#endif
}
}
else if ((Debug == 2) || (Debug == 3)) { /* list only */
diff --git a/base/verilog.c b/base/verilog.c
index 78d70b1..c9aa988 100644
--- a/base/verilog.c
+++ b/base/verilog.c
@@ -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///**/#((**)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;
@@ -120,19 +121,33 @@ int GetBusTok(struct bus *wb)
if (match(nexttok, "[")) {
SkipTokComments(VLOG_DELIMITERS);
- // Check for parameter names and substitute values if found.
- if (nexttok[0] == '`') {
- kl = (struct property *)HashLookup(nexttok + 1, &verilogdefs);
+ result = sscanf(nexttok, "%d", &start);
+ if (result != 1) {
+ char *aptr = NULL;
+ char addin;
+
+ // Check for "+/-(n)" at end of a parameter name
+ aptr = strrchr(nexttok, '+');
+ if (aptr == NULL) aptr = strrchr(nexttok, '-');
+ if (aptr != NULL) {
+ addin = *aptr;
+ *aptr = '\0';
+ }
+
+ // Is name in the parameter list?
+ kl = (struct property *)HashLookup(nexttok, &verilogparams);
if (kl == NULL) {
- Printf("Unknown definition %s found in array notation.\n", nexttok);
+ Printf("Array value %s is not a number or a parameter.\n",
+ nexttok);
+ return 1;
}
else {
if (kl->type == PROP_STRING) {
result = sscanf(kl->pdefault.string, "%d", &start);
if (result != 1) {
- Printf("Cannot parse first digit from parameter %s value %s\n",
- nexttok, kl->pdefault.string);
- return 1;
+ Printf("Parameter %s has value %s that cannot be parsed"
+ " as an integer.\n", nexttok, kl->pdefault.string);
+ return 1;
}
}
else if (kl->type == PROP_INTEGER) {
@@ -141,54 +156,25 @@ int GetBusTok(struct bus *wb)
else if (kl->type == PROP_DOUBLE) {
start = (int)kl->pdefault.dval;
if ((double)start != kl->pdefault.dval) {
- Printf("Cannot parse first digit from parameter %s value %g\n",
- nexttok, kl->pdefault.dval);
- return 1;
+ Printf("Parameter %s has value %g that cannot be parsed"
+ " as an integer.\n", nexttok, kl->pdefault.dval);
+ return 1;
}
}
else {
- Printf("Parameter %s has unknown type; don't know how to parse.\n",
- nexttok);
+ Printf("Parameter %s has unknown type; don't know how"
+ " to parse.\n", nexttok);
return 1;
}
}
- }
- else {
- result = sscanf(nexttok, "%d", &start);
- if (result != 1) {
- // Is name in the parameter list?
- kl = (struct property *)HashLookup(nexttok, &verilogparams);
- if (kl == NULL) {
- Printf("Array value %s is not a number or a parameter.\n",
- nexttok);
+ if (aptr != NULL) {
+ int addval;
+ *aptr = addin;
+ if (sscanf(aptr + 1, "%d", &addval) != 1) {
+ Printf("Unable to parse parameter increment '%s'\n", aptr);
return 1;
}
- else {
- if (kl->type == PROP_STRING) {
- result = sscanf(kl->pdefault.string, "%d", &start);
- if (result != 1) {
- Printf("Parameter %s has value %s that cannot be parsed"
- " as an integer.\n", nexttok, kl->pdefault.string);
- return 1;
- }
- }
- else if (kl->type == PROP_INTEGER) {
- start = kl->pdefault.ival;
- }
- else if (kl->type == PROP_DOUBLE) {
- start = (int)kl->pdefault.dval;
- if ((double)start != kl->pdefault.dval) {
- Printf("Parameter %s has value %g that cannot be parsed"
- " as an integer.\n", nexttok, kl->pdefault.dval);
- return 1;
- }
- }
- else {
- Printf("Parameter %s has unknown type; don't know how"
- " to parse.\n", nexttok);
- return 1;
- }
- }
+ start += (addin == '+') ? addval : -addval;
}
}
SkipTokComments(VLOG_DELIMITERS);
@@ -203,18 +189,33 @@ int GetBusTok(struct bus *wb)
else {
SkipTokComments(VLOG_DELIMITERS);
- // Check for parameter names and substitute values if found.
- if (nexttok[0] == '`') {
- kl = (struct property *)HashLookup(nexttok + 1, &verilogdefs);
+ result = sscanf(nexttok, "%d", &end);
+ if (result != 1) {
+ char *aptr = NULL;
+ char addin;
+
+ // Check for "+/-(n)" at end of a parameter name
+ aptr = strrchr(nexttok, '+');
+ if (aptr == NULL) aptr = strrchr(nexttok, '-');
+ if (aptr != NULL) {
+ addin = *aptr;
+ *aptr = '\0';
+ }
+
+ // Is name in the parameter list?
+ kl = (struct property *)HashLookup(nexttok, &verilogparams);
if (kl == NULL) {
- Printf("Unknown definition %s found in array notation.\n", nexttok);
+ Printf("Array value %s is not a number or a parameter.\n",
+ nexttok);
+ return 1;
}
else {
if (kl->type == PROP_STRING) {
result = sscanf(kl->pdefault.string, "%d", &end);
- if (result != 1) {
- Printf("Cannot parse second digit from parameter "
- "%s value %s\n", nexttok, kl->pdefault.string);
+ if (result != 1) {
+ Printf("Parameter %s has value %s that cannot be parsed"
+ " as an integer.\n", nexttok,
+ kl->pdefault.string);
return 1;
}
}
@@ -231,48 +232,18 @@ int GetBusTok(struct bus *wb)
}
else {
Printf("Parameter %s has unknown type; don't know how"
- " to parse.\n", nexttok);
+ " to parse.\n", nexttok);
return 1;
}
}
- }
- else {
- result = sscanf(nexttok, "%d", &end);
- if (result != 1) {
- // Is name in the parameter list?
- kl = (struct property *)HashLookup(nexttok, &verilogparams);
- if (kl == NULL) {
- Printf("Array value %s is not a number or a parameter.\n",
- nexttok);
+ if (aptr != NULL) {
+ int addval;
+ *aptr = addin;
+ if (sscanf(aptr + 1, "%d", &addval) != 1) {
+ Printf("Unable to parse parameter increment '%s'\n", aptr);
return 1;
}
- else {
- if (kl->type == PROP_STRING) {
- result = sscanf(kl->pdefault.string, "%d", &end);
- if (result != 1) {
- Printf("Parameter %s has value %s that cannot be parsed"
- " as an integer.\n", nexttok,
- kl->pdefault.string);
- return 1;
- }
- }
- else if (kl->type == PROP_INTEGER) {
- end = kl->pdefault.ival;
- }
- else if (kl->type == PROP_DOUBLE) {
- end = (int)kl->pdefault.dval;
- if ((double)end != kl->pdefault.dval) {
- Printf("Cannot parse second digit from parameter "
- "%s value %g\n", nexttok, kl->pdefault.dval);
- return 1;
- }
- }
- else {
- Printf("Parameter %s has unknown type; don't know how"
- " to parse.\n", nexttok);
- return 1;
- }
- }
+ end += (addin == '+') ? addval : -addval;
}
}
}
@@ -312,7 +283,7 @@ int GetBusTok(struct bus *wb)
int GetBus(char *astr, struct bus *wb)
{
- char *colonptr, *brackstart, *brackend;
+ char *colonptr, *brackstart, *brackend, *sigend, sdelim;
int result, start, end;
if (wb == NULL) return 0;
@@ -320,6 +291,40 @@ int GetBus(char *astr, struct bus *wb)
wb->start = -1;
wb->end = -1;
}
+
+ /* Check for wire bundles. If there are bundles, process each */
+ /* section separately and concatenate the sizes. */
+ /* To be done: Handle nested bundles, including N-times concatenation */
+
+ if (*astr == '{') {
+ struct bus wbb;
+
+ astr++;
+ wb->end = 0;
+ while((*astr != '\0') && (*astr != '}')) {
+ sigend = strchr(astr, ',');
+ if (sigend == NULL) sigend = strchr(astr, '}');
+ if (sigend == NULL) {
+ Printf("Badly formed wire bundle \"%s\"\n", astr - 1);
+ return 1;
+ }
+ sdelim = *sigend;
+ *sigend = '\0';
+ if (GetBus(astr, &wbb) == 0) {
+ if (wbb.start > wbb.end)
+ wb->start += (wbb.start - wbb.end + 1);
+ else
+ wb->start += (wbb.end - wbb.start + 1);
+ }
+ else {
+ wb->start++;
+ }
+ *sigend = sdelim;
+ astr = sigend + 1;
+ }
+ return 0;
+ }
+
brackstart = strchr(astr, '[');
if (brackstart != NULL) {
brackend = strchr(astr, ']');
@@ -595,7 +600,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
instname[255] = '\0';
in_module = (char)0;
in_param = (char)0;
-
+
while (!EndParseFile()) {
SkipTokComments(VLOG_DELIMITERS); /* get the next token */
@@ -620,6 +625,81 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
}
}
+ /* Handle parameters by treating as a localparam or definition. */
+ /* Currently anything other than a constant value is not handled */
+ /* and so will flag a warning. */
+
+ else if (match(nexttok, "parameter") || match(nexttok, "localparam")) {
+ char *paramkey = NULL;
+ char *paramval = NULL;
+
+ // Pick up key = value pairs and store in current cell. Look only
+ // at the keyword before "=". Then set the defition as everything
+ // remaining in the line, excluding comments, until the end-of-statement
+
+ while (nexttok != NULL)
+ {
+ struct property *kl = NULL;
+
+ /* Parse for parameters used in expressions. Save */
+ /* parameters in the "verilogparams" hash table. */
+
+ SkipTok(VLOG_DELIMITERS);
+ if ((nexttok == NULL) || (nexttok[0] == '\0')) break;
+ if (match(nexttok, "=")) {
+ /* Pick up remainder of statement */
+ while (nexttok != NULL) {
+ SkipTokNoNewline("X///**/X;,");
+ if (nexttok == NULL) break;
+ if (match(nexttok, ";") || match(nexttok, ",")) break;
+ if (paramval == NULL) paramval = strsave(nexttok);
+ else {
+ char *paramlast;
+ /* Append nexttok to paramval */
+ paramlast = paramval;
+ paramval = (char *)MALLOC(strlen(paramlast) + strlen(nexttok)
+ + 2);
+ sprintf(paramval, "%s %s", paramlast, nexttok);
+ FREE(paramlast);
+ }
+ }
+
+ kl = NewProperty();
+ kl->key = strsave(paramkey);
+ kl->idx = 0;
+ kl->merge = MERGE_NONE;
+
+ if (ConvertStringToInteger(paramval, &ival) == 1) {
+ kl->type = PROP_INTEGER;
+ kl->slop.ival = 0;
+ kl->pdefault.ival = ival;
+ }
+ else if (ConvertStringToFloat(paramval, &dval) == 1) {
+ kl->type = PROP_DOUBLE;
+ kl->slop.dval = 0.01;
+ kl->pdefault.dval = dval;
+ }
+ else {
+ kl->type = PROP_STRING;
+ kl->slop.dval = 0.0;
+ kl->pdefault.string = strsave(paramval);
+ }
+
+ HashPtrInstall(paramkey, kl, &verilogparams);
+ FREE(paramval);
+ paramval = NULL;
+
+ if ((nexttok == NULL) || match(nexttok, ";")) break;
+ }
+ else {
+ if (paramkey != NULL) FREE(paramkey);
+ paramkey = strsave(nexttok);
+ }
+ }
+ if (paramval != NULL) FREE(paramval);
+ if (paramkey != NULL) FREE(paramkey);
+ }
+
else if (match(nexttok, "module")) {
InitializeHashTable(&buses, OBJHASHSIZE);
SkipTokNoNewline(VLOG_DELIMITERS);
@@ -696,7 +776,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
inlined_decls = (char)0;
if (tp != NULL) {
- struct bus wb;
+ struct bus wb, *nb;
PushStack(tp->name, CellStackPtr);
@@ -760,7 +840,8 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
else {
if (!match(nexttok, "input") && !match(nexttok, "output") &&
!match(nexttok, "inout") && !match(nexttok, "real") &&
- !match(nexttok, "logic") && !match(nexttok, "integer")) {
+ !match(nexttok, "wire") && !match(nexttok, "logic") &&
+ !match(nexttok, "integer")) {
if (match(nexttok, "[")) {
if (GetBusTok(&wb) != 0) {
// Didn't parse as a bus, so wing it
@@ -782,6 +863,12 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
Port(portname);
}
}
+ /* Also register this port as a bus */
+ nb = NewBus();
+ nb->start = wb.start;
+ nb->end = wb.end;
+ HashPtrInstall(nexttok, nb, &buses);
+
wb.start = wb.end = -1;
}
else {
@@ -991,151 +1078,219 @@ skip_endmodule:
}
HashPtrInstall(kl->key, kl, &verilogdefs);
}
- else if (match(nexttok, "localparam")) {
- // Pick up key = value pairs and store in current cell
- while (nexttok != NULL)
- {
- struct property *kl = NULL;
-
- /* Parse for parameters used in expressions. Save */
- /* parameters in the "verilogparams" hash table. */
-
- SkipTokNoNewline(VLOG_DELIMITERS);
- if ((nexttok == NULL) || (nexttok[0] == '\0')) break;
- if ((eqptr = strchr(nexttok, '=')) != NULL) {
- *eqptr = '\0';
- kl = NewProperty();
- kl->key = strsave(nexttok);
- kl->idx = 0;
- kl->merge = MERGE_NONE;
-
- if (ConvertStringToInteger(eqptr + 1, &ival) == 1) {
- kl->type = PROP_INTEGER;
- kl->slop.ival = 0;
- kl->pdefault.ival = ival;
+ else if (match(nexttok, "`undef")) {
+ struct property *kl = NULL;
+
+ SkipTokNoNewline(VLOG_DELIMITERS);
+ if ((nexttok == NULL) || (nexttok[0] == '\0')) break;
+
+ kl = HashLookup(nexttok, &verilogdefs);
+ if (kl != NULL) {
+ HashDelete(nexttok, &verilogdefs);
+ if (kl->type == PROP_STRING)
+ if (kl->pdefault.string != NULL)
+ FREE(kl->pdefault.string);
+ FREE(kl->key);
+ }
+ /* Presumably it is not an error to undefine an undefined keyword */
+ }
+ else if (match(nexttok, "real") || match(nexttok, "integer")) {
+ Printf("Ignoring '%s' in module '%s'\n", nexttok, model);
+ /* Do not skip to end of module, as these can be in the middle of */
+ /* I/O assignments, which need to be parsed. */
+ while (!match(nexttok, ";")) SkipTok("X///**/X,;");
+ continue;
+ }
+ else if (match(nexttok, "wire") || match(nexttok, "assign")) { /* wire = node */
+ struct bus wb, wb2, *nb;
+ char nodename[128], noderoot[100];
+ int is_wire = match(nexttok, "wire");
+ int j;
+ struct objlist *lhs, *rhs;
+
+ /* Get left-hand side expression. If this is a wire statement, */
+ /* then define the wire. If is_wire is false, then the wire */
+ /* should already be defined. */
+
+ if (is_wire) {
+ SkipTokNoNewline(VLOG_DELIMITERS);
+ if (match(nexttok, "real"))
+ SkipTokNoNewline(VLOG_DELIMITERS);
+ else if (match(nexttok, "logic"))
+ SkipTokNoNewline(VLOG_DELIMITERS);
+
+ if (GetBusTok(&wb) == 0) {
+ /* Handle bus notation */
+ SkipTokNoNewline(VLOG_DELIMITERS);
+ strcpy(noderoot, nexttok);
+ if (wb.start > wb.end) {
+ for (i = wb.end; i <= wb.start; i++) {
+ sprintf(nodename, "%s[%d]", nexttok, i);
+ if (LookupObject(nodename, CurrentCell) == NULL)
+ Node(nodename);
+ if (i == wb.start) lhs = LookupObject(nodename, CurrentCell);
+ }
+ }
+ else {
+ for (i = wb.start; i <= wb.end; i++) {
+ sprintf(nodename, "%s[%d]", nexttok, i);
+ if (LookupObject(nodename, CurrentCell) == NULL)
+ Node(nodename);
+ if (i == wb.start) lhs = LookupObject(nodename, CurrentCell);
+ }
+ }
+ nb = NewBus();
+ nb->start = wb.start;
+ nb->end = wb.end;
+ HashPtrInstall(nexttok, nb, &buses);
}
- else if (ConvertStringToFloat(eqptr + 1, &dval) == 1) {
- kl->type = PROP_DOUBLE;
- kl->slop.dval = 0.01;
- kl->pdefault.dval = dval;
+ else {
+ if (LookupObject(nexttok, CurrentCell) == NULL) {
+ Node(nexttok);
+ lhs = LookupObject(nexttok, CurrentCell);
+ }
+ }
+ while (1) {
+ SkipTokNoNewline(VLOG_DELIMITERS);
+ if (match(nexttok, ",")) {
+ SkipTokComments(VLOG_DELIMITERS);
+ if (LookupObject(nexttok, CurrentCell) == NULL) {
+ Node(nexttok);
+ lhs = LookupObject(nexttok, CurrentCell);
+ }
+ }
+ else break;
+ }
+ }
+ else { /* "assign" */
+ SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
+ if (GetBus(nexttok, &wb) == 0) {
+ char *aptr = strchr(nexttok, '[');
+ if (aptr != NULL) {
+ *aptr = '\0';
+ /* Find object of first net in bus */
+ strcpy(noderoot, nexttok);
+ sprintf(nodename, "%s[%d]", nexttok, wb.start);
+ lhs = LookupObject(nodename, CurrentCell);
+ *aptr = '[';
+ }
}
else {
- kl->type = PROP_STRING;
- kl->slop.dval = 0.0;
- kl->pdefault.string = strsave(eqptr + 1);
+ lhs = LookupObject(nexttok, CurrentCell);
+ }
+ SkipTokComments(VLOG_DELIMITERS);
+ if (lhs && ((!nexttok) || (!match(nexttok, "=")))) {
+ fprintf(stderr, "Empty assignment for net %s\n", lhs->name);
}
- HashPtrInstall(nexttok, kl, &verilogparams);
- }
- }
- }
-
- /* Note: This is just the most basic processing of conditionals, */
- /* although it does handle nested conditionals. */
-
- else if (match(nexttok, "`ifdef") || match(nexttok, "`ifndef")) {
- struct property *kl;
- int nested = 0;
- int invert = (nexttok[3] == 'n') ? 1 : 0;
-
- SkipTokNoNewline(VLOG_DELIMITERS);
-
- /* To be done: Handle boolean arithmetic on conditionals */
-
- kl = (struct property *)HashLookup(nexttok, &verilogdefs);
- if (((invert == 0) && (kl == NULL))
- || ((invert == 1) && (kl != NULL))) {
- /* Skip to matching `endif */
- while (1) {
- SkipNewLine(VLOG_DELIMITERS);
- SkipTokComments(VLOG_DELIMITERS);
- if (EndParseFile()) break;
- if (match(nexttok, "`ifdef") || match(nexttok, "`ifndef")) {
- nested++;
- }
- else if (match(nexttok, "`endif")) {
- if (nested == 0)
- break;
- else
- nested--;
- }
- }
}
- }
- 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;
+ /* Check for assignment statement, and handle any allowed uses. */
+ /* Any uses other than those mentioned below will cause the entire */
+ /* module to be treated as a black box. */
- // 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.
+ // Allowed uses of "assign" for netlists:
+ // "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) {
- 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++) {
- sprintf(nodename, "%s[%d]", nexttok, i);
- if (LookupObject(nodename, CurrentCell) == NULL)
- Node(nodename);
+ if (nexttok && match(nexttok, "=")) {
+ char assignname[128], assignroot[100];
+
+ i = wb.start;
+ while (1) {
+ SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
+ if (!nexttok) break;
+
+ if (match(nexttok, "{")) {
+ /* RHS is a bundle */
+ continue;
}
- }
- else {
- for (i = wb.start; i <= wb.end; i++) {
- sprintf(nodename, "%s[%d]", nexttok, i);
- if (LookupObject(nodename, CurrentCell) == NULL)
- Node(nodename);
+ else if (match(nexttok, "}")) {
+ /* End of bundle */
+ continue;
}
- }
- nb = NewBus();
- nb->start = wb.start;
- nb->end = wb.end;
- HashPtrInstall(nexttok, nb, &buses);
- }
- else {
- 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);
- }
- do {
- SkipTokNoNewline(VLOG_DELIMITERS);
- } while (nexttok && match(nexttok, ";"));
- }
+ else if (match(nexttok, ",")) {
+ /* Additional signals in bundle */
+ continue;
+ }
+ else if (match(nexttok, ";")) {
+ /* End of assignment */
+ break;
+ }
+ else {
+ if (GetBus(nexttok, &wb2) == 0) {
+ char *aptr = strchr(nexttok, '[');
+ j = wb2.start;
+ if (aptr != NULL) {
+ *aptr = '\0';
+ strcpy(assignroot, nexttok);
+ sprintf(assignname, "%s[%d]", nexttok, j);
+ rhs = LookupObject(assignname, CurrentCell);
+ *aptr = '[';
+ }
+ }
+ else {
+ j = -1;
+ rhs = LookupObject(nexttok, CurrentCell);
+ }
+ if ((lhs == NULL) || (rhs == NULL)) {
+ if (rhs != NULL) {
+ Printf("Improper assignment; left-hand side cannot "
+ "be parsed.\n");
+ Printf("Right-hand side is \"%s\".\n", rhs->name);
+ break;
+ }
+ if (lhs != NULL) {
+ Printf("Improper assignment; right-hand side cannot "
+ "be parsed.\n");
+ Printf("Left-hand side is \"%s\".\n", lhs->name);
+ /* Not parsable, probably behavioral verilog? */
+ Printf("Module '%s' is not structural verilog, "
+ "making black-box.\n", model);
+ SetClass(CLASS_MODULE);
+ goto skip_endmodule;
+ }
+ }
+ while (1) {
+ /* Assign bits in turn from bundle in RHS to bits of LHS */
+ /* until bits in signal are exhausted or LHS is full. */
+
+ if (i != -1)
+ sprintf(nodename, "%s[%d]", noderoot, i);
+ else
+ sprintf(nodename, lhs->name);
+ if (j != -1)
+ sprintf(assignname, "%s[%d]", assignroot, j);
+ else
+ sprintf(assignname, rhs->name);
+
+ join(nodename, assignname);
+
+ if (i == wb.end) break;
+ i += (wb.end > wb.start) ? 1 : -1;
+
+ if (j == wb2.end) break;
+ j += (wb2.end > wb2.start) ? 1 : -1;
+ }
+ }
+ }
+ }
+ while (nexttok && !match(nexttok, ";"))
+ SkipTokComments(VLOG_DELIMITERS);
}
else if (match(nexttok, "endmodule")) {
// No action---new module is started with next 'module' statement,
// if any.
SkipNewLine(VLOG_DELIMITERS);
+ in_module = (char)0; /* Should have been done already */
}
else if (nexttok[0] == '`') {
- // Ignore any other directive starting with a backtick
+ // Ignore any other directive starting with a backtick (e.g., `timescale)
SkipNewLine(VLOG_DELIMITERS);
}
- else if (match(nexttok, "reg") || match(nexttok, "always")) {
+ else if (match(nexttok, "reg") || match(nexttok, "always") ||
+ match(nexttok, "specify") || match(nexttok, "initial")) {
+ Printf("Behavioral keyword '%s' found in source.\n", nexttok);
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
@@ -1145,6 +1300,7 @@ skip_endmodule:
else { /* module instances */
char instancename[100], modulename[100];
int itype, arraystart, arrayend, arraymax, arraymin;
+ char ignore;
instancename[99] = '\0';
modulename[99] = '\0';
@@ -1164,9 +1320,12 @@ skip_endmodule:
PushStack(fname, CellStackPtr);
}
+ SkipTokComments(VLOG_DELIMITERS);
+
+nextinst:
+ ignore = FALSE;
head = NULL;
tail = NULL;
- SkipTokComments(VLOG_DELIMITERS);
// Next token must be '#(' (parameters) or an instance name
@@ -1239,19 +1398,21 @@ skip_endmodule:
// Read the pin list
while (nexttok != NULL) {
SkipTokComments(VLOG_DELIMITERS);
- // NOTE: Deal with `ifdef et al. properly. Ignoring for now.
- while (nexttok[0] == '`') {
- SkipNewLine(VLOG_DELIMITERS);
- SkipTokComments(VLOG_DELIMITERS);
- }
if (match(nexttok, ")")) break;
else if (match(nexttok, ",")) continue;
// We need to look for pins of the type ".name(value)"
if (nexttok[0] != '.') {
- Printf("Badly formed subcircuit pin line at \"%s\"\n", nexttok);
- SkipNewLine(VLOG_DELIMITERS);
+ Printf("Warning: Ignoring subcircuit with no pin names "
+ "at \"%s\"\n", nexttok);
+ InputParseError(stderr);
+ while (nexttok != NULL) {
+ SkipTokComments(VLOG_DELIMITERS);
+ if (match(nexttok, ";")) break;
+ }
+ ignore = TRUE;
+ break;
}
else {
new_port = (struct portelement *)CALLOC(1, sizeof(struct portelement));
@@ -1261,31 +1422,61 @@ 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
savetok = (char)1;
- sprintf(localnet, "_noconnect_%d_", localcount++);
+ if (arraystart != -1) {
+ /* No-connect on an instance array must also be an array */
+ sprintf(localnet, "_noconnect_%d_[%d:%d]", localcount++,
+ arraystart, arrayend);
+ }
+ else
+ sprintf(localnet, "_noconnect_%d_", localcount++);
new_port->net = strsave(localnet);
}
else {
- new_port->net = strsave(nexttok);
+ if (!strcmp(nexttok, "{")) {
+ char *in_line_net = (char *)MALLOC(1);
+ char *new_in_line_net = NULL;
+ *in_line_net = '\0';
+ /* In-line array---read to "}" */
+ while (nexttok) {
+ new_in_line_net = (char *)MALLOC(strlen(in_line_net) +
+ strlen(nexttok) + 1);
+ /* Roundabout way to do realloc() becase there is no REALLOC() */
+ 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, "[")) {
+ SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
+ if (match(nexttok, "[")) {
/* Check for space between name and array identifier */
- SkipTokComments(VLOG_PIN_NAME_DELIMITERS);
- if (!match(nexttok, ")")) {
- char *expnet;
- expnet = (char *)MALLOC(strlen(new_port->net)
- + strlen(nexttok) + 2);
- sprintf(expnet, "%s[%s", new_port->net, nexttok);
- FREE(new_port->net);
- new_port->net = expnet;
+ SkipTokComments(VLOG_PIN_NAME_DELIMITERS);
+ if (!match(nexttok, ")")) {
+ char *expnet;
+ expnet = (char *)MALLOC(strlen(new_port->net)
+ + strlen(nexttok) + 2);
+ sprintf(expnet, "%s[%s", new_port->net, nexttok);
+ FREE(new_port->net);
+ new_port->net = expnet;
}
SkipTokComments(VLOG_DELIMITERS);
- }
+ }
+
if (!match(nexttok, ")")) {
Printf("Badly formed subcircuit pin line at \"%s\"\n", nexttok);
SkipNewLine(VLOG_DELIMITERS);
@@ -1302,10 +1493,21 @@ skip_endmodule:
else {
Printf("Expected to find instance pin block but got \"%s\"\n", nexttok);
}
- /* Instance should end with a semicolon */
+ if (ignore == TRUE) continue; /* moving along. . . */
+
+ /* Verilog allows multiple instances of a single cell type to be chained */
+ /* together with commas. */
+
SkipTokComments(VLOG_DELIMITERS);
- if (!match(nexttok, ";")) {
+ if (match(nexttok, ",")) {
+ goto nextinst;
+ }
+
+ /* Otherwise, instance must end with a semicolon */
+
+ else if (!match(nexttok, ";")) {
Printf("Expected to find end of instance but got \"%s\"\n", nexttok);
+ InputParseError(stderr);
}
/* Check for ignored class */
@@ -1482,14 +1684,44 @@ skip_endmodule:
// Otherwise, net is bit-sliced across array of instances.
}
else if (wb.start > wb.end) {
+ char *bptr, *cptr, cchar, *netname;
+ unsigned char is_bundle = 0;
+ struct bus wbb;
+
i = wb.start;
j = portstart;
+
+ netname = scan->net;
+ if (*netname == '{') {
+ is_bundle = 1;
+ netname++;
+ cptr = strchr(netname, ',');
+ if (cptr == NULL) cptr = strchr(netname, '}');
+ if (cptr == NULL) cptr = netname + strlen(netname) - 1;
+ cchar = *cptr;
+ *cptr = '\0';
+ }
+
+ // Remove indexed part of scan->net
+ if (GetBus(netname, &wbb) == 0) {
+ i = wbb.start;
+ if ((bptr = strchr(netname, '[')) != NULL)
+ *bptr = '\0';
+ }
+ else
+ i = -1;
+
+ if (is_bundle) *cptr = cchar; /* Restore bundle delimiter */
+
while (1) {
new_port = (struct portelement *)CALLOC(1,
sizeof(struct portelement));
sprintf(vname, "%s[%d]", scan->name, j);
new_port->name = strsave(vname);
- sprintf(vname, "%s[%d]", scan->net, i);
+ if (i == -1)
+ sprintf(vname, "%s", netname);
+ else
+ sprintf(vname, "%s[%d]", netname, i);
new_port->net = strsave(vname);
if (last == NULL)
@@ -1504,8 +1736,31 @@ skip_endmodule:
if (portstart > portend) j--;
else j++;
- if (wb.start > wb.end) i--;
+ if (wbb.start > wbb.end) i--;
else i++;
+
+ if (is_bundle &&
+ ((i == -1) ||
+ ((wbb.start > wbb.end) && (i < wbb.end)) ||
+ ((wbb.start < wbb.end) && (i > wbb.end)))) {
+ if (bptr) *bptr = '[';
+
+ netname = cptr + 1;
+ cptr = strchr(netname, ',');
+ if (cptr == NULL) cptr = strchr(netname, '}');
+ if (cptr == NULL) cptr = netname + strlen(netname) - 1;
+ cchar = *cptr;
+ *cptr = '\0';
+
+ if (GetBus(netname, &wbb) == 0) {
+ i = wbb.start;
+ if ((bptr = strchr(netname, '[')) != NULL)
+ *bptr = '\0';
+ }
+ else i = -1;
+
+ *cptr = cchar; /* Restore delimiter */
+ }
}
FREE(scan);
scan = last;
@@ -1600,7 +1855,7 @@ skip_endmodule:
// Instance must be an array
char netname[128];
int slice;
- if (wb.start > wb.end && arraystart > arrayend)
+ if (wb.start >= wb.end && arraystart >= arrayend)
slice = wb.start - (arraystart - i);
else if (wb.start < wb.end && arraystart > arrayend)
slice = wb.start + (arraystart - i);
@@ -1608,6 +1863,7 @@ skip_endmodule:
slice = wb.start - (arraystart + i);
else // (wb.start < wb.end && arraystart < arrayend)
slice = wb.start + (arraystart + i);
+
sprintf(netname, "%s[%d]", scanroot, slice);
if (LookupObject(netname, CurrentCell) == NULL) Node(netname);
join(netname, obptr->name);
@@ -1696,6 +1952,7 @@ char *ReadVerilogTop(char *fname, int *fnum, int blackbox)
InitializeHashTable(&verilogparams, OBJHASHSIZE);
InitializeHashTable(&verilogdefs, OBJHASHSIZE);
+ definitions = &verilogdefs;
/* Add the pre-defined key "LVS" to verilogdefs */
@@ -1718,6 +1975,7 @@ char *ReadVerilogTop(char *fname, int *fnum, int blackbox)
HashKill(&verilogparams);
RecurseHashTable(&verilogdefs, freeprop);
HashKill(&verilogdefs);
+ definitions = (struct hashdict *)NULL;
// Record the top level file.
if (LookupCellFile(fname, filenum) == NULL) CellDef(fname, filenum);
@@ -1778,10 +2036,10 @@ void IncludeVerilog(char *fname, int parent, struct cellstack **CellStackPtr,
if (strchr(fname, '.') == NULL) {
SetExtension(name, fname, VERILOG_EXTENSION);
filenum = OpenParseFile(name, parent);
- }
- if (filenum < 0) {
- Fprintf(stderr,"Error in Verilog file include: No file %s\n",name);
- return;
+ }
+ if (filenum < 0) {
+ fprintf(stderr,"Error in Verilog file include: No file %s\n", fname);
+ return;
}
}
}
diff --git a/configure b/configure
index 5361403..8df0ef3 100755
--- a/configure
+++ b/configure
@@ -4,4 +4,4 @@
# all of its config scripts in a different directory than the configure
# script itself.
-( CFLAGS="-g" ; export CFLAGS ; cd scripts ; ./configure $* )
+( CFLAGS="-g" ; export CFLAGS ; cd scripts ; ./configure "$@" )
diff --git a/scripts/configure b/scripts/configure
index c6d171b..001921b 100755
--- a/scripts/configure
+++ b/scripts/configure
@@ -6413,7 +6413,7 @@ fi
# Not available on all versions: check for include file.
SHLIB_CFLAGS="-fpic"
LDDL_FLAGS="-shared ${LIB_SPECS}"
- CFLAGS="${CFLAGS} -l/usr/X11R6/include"
+ CFLAGS="${CFLAGS} -L/usr/X11R6/include"
;;
*-netbsd*|*-openbsd*)
diff --git a/scripts/configure.in b/scripts/configure.in
index 2f951c2..601a6df 100644
--- a/scripts/configure.in
+++ b/scripts/configure.in
@@ -1120,7 +1120,7 @@ if test $usingTcl ; then
# Not available on all versions: check for include file.
SHLIB_CFLAGS="-fpic"
LDDL_FLAGS="-shared ${LIB_SPECS}"
- CFLAGS="${CFLAGS} -l/usr/X11R6/include"
+ CFLAGS="${CFLAGS} -L/usr/X11R6/include"
;;
*-netbsd*|*-openbsd*)
diff --git a/scripts/makedbh b/scripts/makedbh
deleted file mode 100755
index 3338a35..0000000
--- a/scripts/makedbh
+++ /dev/null
@@ -1,187 +0,0 @@
-#!/bin/csh -f
-#
-# makes the "database.h" (1st argument, $1) file from "database.h.in"
-# (2nd argument, $2), setting various mask operation definitions
-# according to the number of words implied by the value of TT_MAXTYPES
-
-# The following mess grabs the value of TT_MAXTYPES from database.h.in
-#
-set maxtypes=`sed -n -e '/^#define[[:space:]]*TT_MAXTYPES/s/#define[[:space:]]*TT_MAXTYPES[[:space:]]*//p' < $1 | sed -e 's/\/\*[[:print:]]*\*\/[[:space:]]*//g' `
-#
-# Alternative method works with outdated versions of sed/ed.
-#
-if ($maxtypes == "") then
- set maxtypes=`sed -n -e '/^#define[ ]*TT_MAXTYPES/s/#define[ ]*TT_MAXTYPES[ ]*//p' < $1 | sed -e 's/\/\*.*\*\/[ ]*//g' `
-endif
-#
-# If we can't generate database.h correctly, nothing is going to compile.
-#
-if ($maxtypes == "") then
- echo "Bad sed script in scripts/makedbh: Cannot generate database/database.h!"
- exit
-endif
-
-# Find derived values from bits per word
-# Note that bits-per-word should be determined from the compiler, but
-# 32 bits per word has always been hardwired into magic.
-#
-set bpw = 32
-
-# @ wordmask=$bpw - 1
-# set wordshift=`echo "c=l($bpw); d=l(2); scale=0; c/d" | bc -l`
-# @ maskwords=$maxtypes + $bpw - 1
-# @ maskwords/=$bpw
-
-@ maskwords=$maxtypes + $bpw - 1
-@ maskwords/=$bpw
-
-
-# Generate the main part of the database.h file from database.h.in
-cat $1 > $2
-
-# Generate a list of integers from 0 to the value of "maskwords" - 1
-set count=""
-@ maskwords--
-while (${maskwords} >= 0)
- set count=`echo ${count} ${maskwords}`
- @ maskwords--
-end
-
-# Definitions
-
-echo "#define TTMaskZero(m) ( \" >> $2
-foreach i (${count})
- echo -n " (m)->tt_words[$i] = 0" >> $2
- if ($i == 0) then
- echo ")" >> $2
- echo "" >> $2
- else
- echo ", \" >> $2
- endif
-end
-
-echo "#define TTMaskIsZero(m) ( \" >> $2
-foreach i (${count})
- echo -n " (m)->tt_words[$i] == 0" >> $2
- if ($i == 0) then
- echo ")" >> $2
- echo "" >> $2
- else
- echo " && \" >> $2
- endif
-end
-
-echo "#define TTMaskEqual(m, n) ( \" >> $2
-foreach i (${count})
- echo -n " (m)->tt_words[$i] == (n)->tt_words[$i]" >> $2
- if ($i == 0) then
- echo ")" >> $2
- echo "" >> $2
- else
- echo " && \" >> $2
- endif
-end
-
-echo "#define TTMaskIntersect(m, n) ( \" >> $2
-foreach i (${count})
- echo -n " ((m)->tt_words[$i] & (n)->tt_words[$i])" >> $2
- if ($i == 0) then
- echo ")" >> $2
- echo "" >> $2
- else
- echo " || \" >> $2
- endif
-end
-
-echo "#define TTMaskCom(m) ( \" >> $2
-foreach i (${count})
- echo -n " ((m)->tt_words[$i] = ~(m)->tt_words[$i])" >> $2
- if ($i == 0) then
- echo ")" >> $2
- echo "" >> $2
- else
- echo ", \" >> $2
- endif
-end
-
-echo "#define TTMaskCom2(m, n) ( \" >> $2
-foreach i (${count})
- echo -n " ((m)->tt_words[$i] = ~(n)->tt_words[$i])" >> $2
- if ($i == 0) then
- echo ")" >> $2
- echo "" >> $2
- else
- echo ", \" >> $2
- endif
-end
-
-echo "#define TTMaskSetMask(m, n) ( \" >> $2
-foreach i (${count})
- echo -n " ((m)->tt_words[$i] |= (n)->tt_words[$i])" >> $2
- if ($i == 0) then
- echo ")" >> $2
- echo "" >> $2
- else
- echo ", \" >> $2
- endif
-end
-
-echo "#define TTMaskSetMask3(m, n, o) ( \" >> $2
-foreach i (${count})
- echo -n " ((m)->tt_words[$i] |= (n)->tt_words[$i] | (o)->tt_words[$i])" \
- >> $2
- if ($i == 0) then
- echo ")" >> $2
- echo "" >> $2
- else
- echo ", \" >> $2
- endif
-end
-
-echo "#define TTMaskAndMask(m, n) ( \" >> $2
-foreach i (${count})
- echo -n " ((m)->tt_words[$i] &= (n)->tt_words[$i])" >> $2
- if ($i == 0) then
- echo ")" >> $2
- echo "" >> $2
- else
- echo ", \" >> $2
- endif
-end
-
-echo "#define TTMaskAndMask3(m, n, o) ( \" >> $2
-foreach i (${count})
- echo -n " ((m)->tt_words[$i] = (n)->tt_words[$i] & (o)->tt_words[$i])" \
- >> $2
- if ($i == 0) then
- echo ")" >> $2
- echo "" >> $2
- else
- echo ", \" >> $2
- endif
-end
-
-echo "#define TTMaskClearMask(m, n) ( \" >> $2
-foreach i (${count})
- echo -n " ((m)->tt_words[$i] &= ~(n)->tt_words[$i])" >> $2
- if ($i == 0) then
- echo ")" >> $2
- echo "" >> $2
- else
- echo ", \" >> $2
- endif
-end
-
-echo "#define TTMaskClearMask3(m, n, o) ( \" >> $2
-foreach i (${count})
- echo -n " ((m)->tt_words[$i] = (n)->tt_words[$i] & ~(o)->tt_words[$i])" \
- >> $2
- if ($i == 0) then
- echo ")" >> $2
- else
- echo ", \" >> $2
- endif
-end
-
-echo "" >> $2
-echo "#endif /* _DATABASE_H */" >> $2
diff --git a/tcltk/tclnetgen.c b/tcltk/tclnetgen.c
index 14cdd2c..faeba22 100644
--- a/tcltk/tclnetgen.c
+++ b/tcltk/tclnetgen.c
@@ -3811,8 +3811,8 @@ _netcmp_permute(ClientData clientData,
if (PermuteForget(tp->name, fnum, NULL, NULL))
Fprintf(stdout, "No permutations on circuit %s\n", tp->name);
else
- Fprintf(stderr, "Unable to reset model %s pin permutation %s, %s.\n",
- tp->name, pin1, pin2);
+ Fprintf(stderr, "Unable to reset model %s pin permutations.\n",
+ tp->name);
}
return TCL_OK;
}
diff --git a/tcltk/tkcon.tcl b/tcltk/tkcon.tcl
index 609220a..ea49ae6 100755
--- a/tcltk/tkcon.tcl
+++ b/tcltk/tkcon.tcl
@@ -741,9 +741,9 @@ proc ::tkcon::EvalCmd {w cmd} {
set tag [UniqueTag $w]
$w insert output $res [list stderr $tag] \n stderr
$w tag bind $tag <Enter> \
- [list $w tag configure $tag -under 1]
+ [list $w tag configure $tag -underline 1]
$w tag bind $tag <Leave> \
- [list $w tag configure $tag -under 0]
+ [list $w tag configure $tag -underline 0]
$w tag bind $tag <ButtonRelease-1> \
"if {!\[info exists tkPriv(mouseMoved)\] || !\$tkPriv(mouseMoved)} \
{[list edit -attach [Attach] -type error -- $PRIV(errorInfo)]}"
@@ -2472,8 +2472,8 @@ proc ::tkcon::ErrorHighlight w {
set tag [UniqueTag $w]
$w tag add $tag $start+${c0}c $start+1c+${c1}c
$w tag configure $tag -foreground $COLOR(stdout)
- $w tag bind $tag <Enter> [list $w tag configure $tag -under 1]
- $w tag bind $tag <Leave> [list $w tag configure $tag -under 0]
+ $w tag bind $tag <Enter> [list $w tag configure $tag -underline 1]
+ $w tag bind $tag <Leave> [list $w tag configure $tag -underline 0]
$w tag bind $tag <ButtonRelease-1> "if {!\$tkPriv(mouseMoved)} \
{[list edit -attach $app -type proc -find $what -- $cmd]}"
}
@@ -2501,8 +2501,8 @@ proc ::tkcon::ErrorHighlight w {
set tag [UniqueTag $w]
$w tag add $tag $ix+1c $start
$w tag configure $tag -foreground $COLOR(proc)
- $w tag bind $tag <Enter> [list $w tag configure $tag -under 1]
- $w tag bind $tag <Leave> [list $w tag configure $tag -under 0]
+ $w tag bind $tag <Enter> [list $w tag configure $tag -underline 1]
+ $w tag bind $tag <Leave> [list $w tag configure $tag -underline 0]
$w tag bind $tag <ButtonRelease-1> "if {!\$tkPriv(mouseMoved)} \
{[list edit -attach $app -type proc -- $cmd]}"
}
@@ -2954,14 +2954,14 @@ proc edit {args} {
##
set text $w.text
set m [menu [::tkcon::MenuButton $menu Edit edit]]
- $m add command -label "Cut" -under 2 \
+ $m add command -label "Cut" -underline 2 \
-command [list tk_textCut $text]
- $m add command -label "Copy" -under 0 \
+ $m add command -label "Copy" -underline 0 \
-command [list tk_textCopy $text]
- $m add command -label "Paste" -under 0 \
+ $m add command -label "Paste" -underline 0 \
-command [list tk_textPaste $text]
$m add separator
- $m add command -label "Find" -under 0 \
+ $m add command -label "Find" -underline 0 \
-command [list ::tkcon::FindBox $text]
## Send To Menu