Compare commits

...
25 Commits
Author SHA1 Message Date
Tim Edwards ba7004fd5b Merge branch 'master' into netgen-1.5 2025-03-10 02:00:02 -04:00
Tim Edwards 4f315d33d6 Fixed a corner case found by Sylvain Munaut (see github issue
tracker #96) in which a subcircuit with only one port (in this
case, a pad) but which has properties (in this case, "M") will
fail to set the pointer position ahead of the property because
the loop starts after the first pin, so it has already missed
the position that needs to be saved.  Fixed by initializing
the value to the first pin position before starting the loop.
2025-03-09 11:07:58 -04:00
Tim Edwards 704bfbc871 Merge branch 'master' into netgen-1.5 2025-02-10 02:00:03 -05:00
Tim Edwards 4457248ecd Corrected a long-standing issue with permutation, which turned out
to be caused by failing to have a systematic way of determining
which pin's hash value would be used for the hash value of all the
pins.  Because equivalent cells in the two netlists may have pins in
different order, it was possible that they might end up with
different hashes.  This was solved simply by always taking the
larger hash value of the two pins belonging to the permutable pair.
Now permutation works correctly for arbitrary subcircuits.
(Previously it worked for low-level components like MOSFETs because
the pin order is always the same.)
2025-02-09 21:26:54 -05:00
Tim Edwards 7bee1851fa Merge branch 'master' into netgen-1.5 2025-01-05 02:00:04 -05:00
Tim Edwards 021dfa6e8a Made changes to tkcon.tcl to ensure compatibility with Tcl version 9. 2025-01-04 14:18:21 -05:00
Tim Edwards e4a4621b96 Merge branch 'master' into netgen-1.5 2025-01-02 02:00:01 -05:00
Tim Edwards 1d286f9973 Corrected an issue with generating proxy pins that had previously
forced flattening to be done whenever any pin mismatch occurred,
which undermined the whole proxy pin method.  With the proxy pins
fixed, reinstated the method of avoiding flattening when pin
issues can be trivially corrected.  Also:  Added output to the
pin matching for one mismatch case that was being missed.
2025-01-01 13:27:39 -05:00
Tim Edwards 3ca77300ac Merge branch 'master' into netgen-1.5 2024-12-28 02:00:02 -05:00
Tim Edwards 6d2ef396ef After giving the previous code change some more thought, I
decided that it is beneficial to break symmetries by net name;
it's just that net names should not be used before all symmetries
related to pins have been broken.  So I rewrote the compare
routine to take an argument allowing or disallowing net name
matches, and make one call to break symmetries by pin name
followed by another call to break symmetries by net name.  This
still solves the original problem, but does not allow symmetries
to be broken randomly on internal nets if names have been matched
in both netlists.  Otherwise the output may report nets that
appear to be swapped, making the output confusing.
2024-12-27 16:20:00 -05:00
Tim Edwards 2483b7440f Corrected an error in "ResolveAutomorphsByPin" where the code states
to check that the nodes with matching names are pins, but never does.
This results in an attempt to resolve automorphs by matching pin
names AND net names.  However, net names can match without the nets
matching, as pointed out by Andrey Bondar (private communication).
Fixed simply by adding the specified check that the node being name-
matched is actually a pin.
2024-12-26 21:20:24 -05:00
Tim Edwards 236fba18aa Merge branch 'master' into netgen-1.5 2024-11-15 02:00:04 -05:00
Tim Edwards 49c0de0433 Corrected an error found by Sylvain Munaut and discussed on
open-source-silicon slack on Nov. 3 in which the simple verilog
expression "assign name1 = name2[a:b]";  this revealed an error
where the parsing of "name2" was being incorrectly run with
GetBusTok() which must be called when the token starts with "[".
This problem existed both for the left-hand-side parsing and
the right-hand-side parsing, and has been fixed for both (where
either side may be a subset of a bus and the other a complete
bus).
2024-11-14 21:28:51 -05:00
Tim Edwards 3b9dca0cf2 Implemented the patch from Sylvain Munaut in github PR#90 (issue
that the position in the code has shifted quite a bit and I
don't really trust that git will do a clean merge.
2024-11-14 20:39:19 -05:00
Tim Edwards 1272ed22fe Merge branch 'master' into netgen-1.5 2024-10-20 02:00:02 -04:00
Tim Edwards 7d910b616c Modified the string matching "matchnocase()" routine to compare
a verilog escaped string against an equivalent non-escaped
string (requires that the escaped string differs from the non-
escaped string by having a "\" at the front and " " at the end.
The space character is always maintained as part of the string).
2024-10-19 17:07:09 -04:00
Tim Edwards 6179ba8cb8 Merge branch 'master' into netgen-1.5 2024-10-17 02:00:02 -04:00
Tim Edwards b1032f846b Refactored code in netcmp.c involved in printing side-by-side
formatted output to make it much cleaner and easier to read.  This
is in preparation of correcting the circuit1<-->circuit2 asymmetry
in the MatchPins() routine.
2024-10-16 20:38:44 -04:00
Tim Edwards 4c546d1472 Corrected an error that prevents property errors from being
printed in detail if a port error is also found.
2024-10-16 09:44:48 -04:00
Tim Edwards aaf8fefc1a Merge branch 'master' into netgen-1.5 2024-10-16 02:00:02 -04:00
Tim Edwards e1aa231db1 Corrected another error discovered by Andrei Bondar in which
the critical property (e.g., L for transistors) is required to
match exactly between devices in order to allow the additive
property (e.g., W for transistors) to be summed.  The critical
property should match if all values are within the slop value,
for floating-point values.  Note:  The implementation is still
not rigorous, as the saved critical value may shift from
device to device;  so comparing, e.g., 1.00 to 1.01 to 1.02 to
1.03, etc., can find that all individual comparisons are within
the slop value even though the slop is exceeded across all values.
2024-10-15 20:52:23 -04:00
Tim Edwards abaf896f7f Merge branch 'master' into netgen-1.5 2024-10-15 02:00:02 -04:00
Tim Edwards df8fa29b2f Fixed an issue with property matching that was preventing the last-
ditch effort of matching based on combining devices with the same
critical property (e.g., adding gate widths together for transistors
of the same gate length, if the property records remain stubbornly
mismatched to the end).  Thanks to Bondar Andrey Renatovich for
surfacing this issue and providing a reproducible example.
2024-10-14 13:24:35 -04:00
Tim Edwards e94d25b3f1 Merge branch 'master' into netgen-1.5 2024-10-08 02:00:03 -04:00
Tim Edwards d14bf70f1c Working to get some MatchPins improvements from Mitch Bailey from
a long time ago into the code.  The improvements collided with
intervening changes to the same routines and would not merge
cleanly, which is why they were never merged.  Step 1:  Show the
net name of a matching net that is missing a pin.  Remove output
of missing pins that is redundant (pin names being output twice).
2024-10-07 11:10:33 -04:00
9 changed files with 536 additions and 326 deletions
+1 -1
View File
@@ -1 +1 @@
1.5.281
1.5.293
+40
View File
@@ -1306,6 +1306,14 @@ int UniquePins(char *name, int filenum)
return 1;
}
/* Structure used below for keeping track of node numbers
* belonging to removed nodes.
*/
struct LinkedNum {
int node;
struct LinkedNum *next;
};
/*------------------------------------------------------*/
/* Callback function for CleanupPins */
/* Note that if the first pin of the instance is a */
@@ -1318,6 +1326,7 @@ struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
struct nlist *ptr;
struct objlist *ob, *obt, *lob, *nob, *firstpin, *pob;
struct nlist *tc = (struct nlist *)clientdata;
struct LinkedNum *newnodenum, *removedNodes = (struct LinkedNum *)NULL;
int pinnum;
char *saveinst = NULL;
@@ -1373,6 +1382,15 @@ struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
saveinst = ob->instance.name;
}
if (ob->model.class != NULL) FREE(ob->model.class);
// Record the net number of the pin being removed, to
// check at the end if the net belonged to a pin that
// got orphaned.
newnodenum = (struct LinkedNum *)MALLOC(sizeof(struct LinkedNum));
newnodenum->node = ob->node;
newnodenum->next = removedNodes;
removedNodes = newnodenum;
FREE(ob);
}
else {
@@ -1416,6 +1434,28 @@ struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
}
}
while (removedNodes != NULL) {
int nodenum = removedNodes->node;
struct objlist *ob2;
/* Only concerned with nodes that are in the pin list of ptr->cell */
for (ob = ptr->cell; ob != NULL; ob = ob->next) {
if (ob->type != PORT) break;
if (ob->node == nodenum) break;
}
if (ob && (ob->type == PORT)) {
/* Check if this node number exists only in the port record */
for (nob = ob->next; nob != NULL; nob = nob->next)
if (nob->node == nodenum) break;
if (nob == NULL) {
ob->node = -1; /* This pin is now disconnected */
}
}
newnodenum = removedNodes;
removedNodes = removedNodes->next;
FREE(newnodenum);
}
if (saveinst != NULL) FREE(saveinst);
return NULL; /* Keep the search going */
}
+316 -237
View File
@@ -21,6 +21,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <stdlib.h> /* for rand(), abs(), etc */
#include <stdarg.h>
#include <setjmp.h>
#include <signal.h>
#include <time.h> /* for time() as a seed for random number generator */
@@ -1216,7 +1217,8 @@ SortFanoutLists(nlist1, nlist2)
f2 -= 1;
matched[f1] = -1;
total++;
if (f2 != f1) {
if ((f2 != f1) && (nlist2->flist[f1].permute != 0) &&
(nlist2->flist[f2].permute != 0)) {
temp = nlist2->flist[f2];
nlist2->flist[f2] = nlist2->flist[f1];
nlist2->flist[f1] = temp;
@@ -1250,7 +1252,8 @@ SortFanoutLists(nlist1, nlist2)
f1 -= 1;
matched[f2] = -1;
total++;
if (f1 != f2) {
if ((f1 != f2) && (nlist1->flist[f1].permute != 0) &&
(nlist1->flist[f2].permute != 0)) {
temp = nlist1->flist[f1];
nlist1->flist[f1] = nlist1->flist[f2];
nlist1->flist[f2] = temp;
@@ -1496,6 +1499,112 @@ void SortUnmatchedLists(nlists1, nlists2, n1max, n2max)
HashKill(&n2hash);
}
/*--------------------------------------------------------------*/
/* Output string formatting routines */
/* for two-column side-by-side comparisons */
/*--------------------------------------------------------------*/
/*--------------------------------------------------------------*/
/* Fill left and right columns with spaces */
/*--------------------------------------------------------------*/
void output_string_fill(char *ostr)
{
int m;
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
}
/*--------------------------------------------------------------*/
/* Write a formatted string in the usual format of sprintf() to */
/* the left column. */
/*--------------------------------------------------------------*/
void output_string_left(char *ostr, char *format, ...)
{
va_list ap;
va_start(ap, format);
vsnprintf(ostr, left_col_end, format, ap);
va_end(ap);
}
/*--------------------------------------------------------------*/
/* Write a formatted string in the usual format of sprintf() to */
/* the right column. */
/*--------------------------------------------------------------*/
void output_string_right(char *ostr, char *format, ...)
{
va_list ap;
va_start(ap, format);
vsnprintf(ostr + left_col_end + 1, left_col_end, format, ap);
va_end(ap);
}
/*--------------------------------------------------------------*/
/* Remove any string breaks within the output string, then */
/* print the string to stdout. */
/*--------------------------------------------------------------*/
void output_string_print(char *ostr)
{
int m;
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0')
*(ostr + m) = ' ';
Fprintf(stdout, ostr);
}
/*--------------------------------------------------------------*/
/* Draw a divider line to the output. If "colbrk" is TRUE, */
/* then leave the center character as a vertical bar. */
/* Print the divider line to stdout, then reinstate the */
/* vertical bar. */
/*--------------------------------------------------------------*/
void output_string_print_divider(char *ostr, char colbrk)
{
int m;
for (m = 0; m < right_col_end; m++) *(ostr + m) = '-';
if (colbrk) *(ostr + left_col_end) = '|';
output_string_print(ostr);
*(ostr + left_col_end) = '|';
}
/*--------------------------------------------------------------*/
/* Initialize the output string with an empty line and divider */
/*--------------------------------------------------------------*/
char *output_string_init()
{
char *ostr = CALLOC(right_col_end + 2, sizeof(char));
*(ostr + left_col_end) = '|';
*(ostr + right_col_end) = '\n';
*(ostr + right_col_end + 1) = '\0';
output_string_fill(ostr);
return ostr;
}
/*--------------------------------------------------------------*/
/* Write the header for the comparison output */
/* Print the header to stdout. */
/*--------------------------------------------------------------*/
void output_string_print_header(char *ostr, struct nlist *tc1, struct nlist *tc2)
{
if (tc1)
output_string_left(ostr, "Circuit 1: %s", tc1->name);
if (tc2)
output_string_right(ostr, "Circuit 2: %s", tc2->name);
output_string_print(ostr);
}
/*
*---------------------------------------------------------------------
*---------------------------------------------------------------------
@@ -1512,9 +1621,9 @@ void FormatIllegalElementClasses()
char *permcount;
int bytesleft;
ostr = CALLOC(right_col_end + 2, sizeof(char));
permname = CALLOC(right_col_end + 2, sizeof(char));
permcount = CALLOC(right_col_end + 2, sizeof(char));
ostr = output_string_init();
found = 0;
for (escan = ElementClasses; escan != NULL; escan = escan->next)
@@ -1527,15 +1636,7 @@ void FormatIllegalElementClasses()
/* Print in side-by-side format */
*(ostr + left_col_end) = '|';
*(ostr + right_col_end) = '\n';
*(ostr + right_col_end + 1) = '\0';
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
snprintf(ostr, left_col_end, "Circuit 1: %s", Circuit1->name);
snprintf(ostr + left_col_end + 1, left_col_end, "Circuit 2: %s", Circuit2->name);
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
Fprintf(stdout, ostr);
output_string_print_header(ostr, Circuit1, Circuit2);
}
found = 1;
@@ -1579,32 +1680,27 @@ void FormatIllegalElementClasses()
Fprintf(stdout, "\n");
for (n = 0; n < ((n1 > n2) ? n1 : n2); n++) {
if (n != 0) {
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
output_string_fill(ostr);
Fprintf(stdout, ostr);
} else {
for (i = 0; i < right_col_end; i++) *(ostr + i) = '-';
Fprintf(stdout, ostr);
*(ostr + left_col_end) = '|';
output_string_print_divider(ostr, FALSE);
}
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
output_string_fill(ostr);
if (n < n1) {
estr = elist1[n]->name;
if (*estr == '/') estr++; // Remove leading slash, if any
snprintf(ostr, left_col_end, "Instance: %s", estr);
output_string_left(ostr, "Instance: %s", estr);
}
else
snprintf(ostr, left_col_end, "(no matching instance)");
output_string_left(ostr, "%s", "(no matching instance)");
if (n < n2) {
estr = elist2[n]->name;
if (*estr == '/') estr++; // Remove leading slash, if any
snprintf(ostr + left_col_end + 1, left_col_end, "Instance: %s", estr);
output_string_right(ostr, "Instance: %s", estr);
}
else
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching instance)");
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
Fprintf(stdout, ostr);
output_string_right(ostr, "%s", "(no matching instance)");
output_string_print(ostr);
if (n >= n1)
maxf = elist2[n]->fanout;
@@ -1616,12 +1712,11 @@ void FormatIllegalElementClasses()
f1 = f2 = 0;
while ((f1 < maxf) || (f2 < maxf)) {
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
output_string_fill(ostr);
if (n < n1) {
if (f1 < elist1[n]->fanout) {
if (elist1[n]->flist[f1].permute == (char)1) {
snprintf(ostr, left_col_end, " %s = %d", elist1[n]->flist[f1].name,
output_string_left(ostr, " %s = %d", elist1[n]->flist[f1].name,
elist1[n]->flist[f1].count);
}
else {
@@ -1643,7 +1738,7 @@ void FormatIllegalElementClasses()
sprintf(value, "%d", elist1[n]->flist[f1].count);
strcat(permcount, value);
strcat(permcount, ")");
snprintf(ostr, left_col_end, " %s = %s", permname, permcount);
output_string_left(ostr, " %s = %s", permname, permcount);
}
}
}
@@ -1651,7 +1746,7 @@ void FormatIllegalElementClasses()
if (n < n2) {
if (f2 < elist2[n]->fanout) {
if (elist2[n]->flist[f2].permute == (char)1) {
snprintf(ostr + left_col_end + 1, left_col_end, " %s = %d", elist2[n]->flist[f2].name,
output_string_right(ostr, " %s = %d", elist2[n]->flist[f2].name,
elist2[n]->flist[f2].count);
}
else {
@@ -1673,21 +1768,18 @@ void FormatIllegalElementClasses()
sprintf(value, "%d", elist2[n]->flist[f2].count);
strcat(permcount, value);
strcat(permcount, ")");
snprintf(ostr + left_col_end + 1, left_col_end, " %s = %s", permname, permcount);
output_string_right(ostr, " %s = %s", permname, permcount);
}
}
}
f2++;
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
Fprintf(stdout, ostr);
output_string_print(ostr);
}
}
FreeFormattedLists(elist1, numlists1);
FreeFormattedLists(elist2, numlists2);
for (i = 0; i < right_col_end; i++) *(ostr + i) = '-';
Fprintf(stdout, ostr);
*(ostr + left_col_end) = '|';
output_string_print_divider(ostr, FALSE);
}
FREE(ostr);
@@ -1875,7 +1967,7 @@ void FormatIllegalNodeClasses()
int found, numlists1, numlists2, n1, n2, n, f, i, maxf;
char *ostr;
ostr = CALLOC(right_col_end + 2, sizeof(char));
ostr = output_string_init();
found = 0;
/*
@@ -1893,15 +1985,7 @@ void FormatIllegalNodeClasses()
Fprintf(stdout, "Class fragments follow (with fanout counts):\n");
/* Print in side-by-side format */
*(ostr + left_col_end) = '|';
*(ostr + right_col_end) = '\n';
*(ostr + right_col_end + 1) = '\0';
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
snprintf(ostr, left_col_end, "Circuit 1: %s", Circuit1->name);
snprintf(ostr + left_col_end + 1, left_col_end, "Circuit 2: %s", Circuit2->name);
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
Fprintf(stdout, ostr);
output_string_print_header(ostr, Circuit1, Circuit2);
}
found = 1;
@@ -1941,26 +2025,21 @@ void FormatIllegalNodeClasses()
Fprintf(stdout, "\n");
for (n = 0; n < ((n1 > n2) ? n1 : n2); n++) {
if (n != 0) {
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
output_string_fill(ostr);
Fprintf(stdout, ostr);
} else {
for (i = 0; i < right_col_end; i++) *(ostr + i) = '-';
Fprintf(stdout, ostr);
*(ostr + left_col_end) = '|';
output_string_print_divider(ostr, FALSE);
}
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
output_string_fill(ostr);
if (n < n1)
snprintf(ostr, left_col_end, "Net: %s", nlists1[n]->name);
output_string_left(ostr, "Net: %s", nlists1[n]->name);
else
snprintf(ostr, left_col_end, "(no matching net)");
output_string_left(ostr, "%s", "(no matching net)");
if (n < n2)
snprintf(ostr + left_col_end + 1, left_col_end, "Net: %s", nlists2[n]->name);
output_string_right(ostr, "Net: %s", nlists2[n]->name);
else
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching net)");
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
Fprintf(stdout, ostr);
output_string_right(ostr, "%s", "(no matching net)");
output_string_print(ostr);
if (n >= n1)
maxf = nlists2[n]->fanout;
@@ -1971,17 +2050,16 @@ void FormatIllegalNodeClasses()
nlists1[n]->fanout : nlists2[n]->fanout;
for (f = 0; f < maxf; f++) {
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
output_string_fill(ostr);
if (n < n1)
if (f < nlists1[n]->fanout) {
if (nlists1[n]->flist[f].permute <= 1)
snprintf(ostr, left_col_end, " %s/%s = %d",
output_string_left(ostr, " %s/%s = %d",
nlists1[n]->flist[f].model,
nlists1[n]->flist[f].name,
nlists1[n]->flist[f].count);
else {
snprintf(ostr, left_col_end, " %s/(%s) = %d",
output_string_left(ostr, " %s/(%s) = %d",
nlists1[n]->flist[f].model,
nlists1[n]->flist[f].name,
nlists1[n]->flist[f].count);
@@ -1991,28 +2069,25 @@ void FormatIllegalNodeClasses()
if (n < n2)
if (f < nlists2[n]->fanout) {
if (nlists2[n]->flist[f].permute <= 1)
snprintf(ostr + left_col_end + 1, left_col_end, " %s/%s = %d",
output_string_right(ostr, " %s/%s = %d",
nlists2[n]->flist[f].model,
nlists2[n]->flist[f].name,
nlists2[n]->flist[f].count);
else {
snprintf(ostr + left_col_end + 1, left_col_end, " %s/(%s) = %d",
output_string_right(ostr, " %s/(%s) = %d",
nlists2[n]->flist[f].model,
nlists2[n]->flist[f].name,
nlists2[n]->flist[f].count);
FREE(nlists2[n]->flist[f].name);
}
}
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
Fprintf(stdout, ostr);
output_string_print(ostr);
}
}
FreeFormattedLists(nlists1, numlists1);
FreeFormattedLists(nlists2, numlists2);
for (i = 0; i < right_col_end; i++) *(ostr + i) = '-';
Fprintf(stdout, ostr);
*(ostr + left_col_end) = '|';
output_string_print_divider(ostr, FALSE);
}
FREE(ostr);
}
@@ -3202,23 +3277,12 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
Tcl_Obj *clist1, *clist2;
#endif
ostr = CALLOC(right_col_end + 2, sizeof(char));
ostr = output_string_init();
if (Debug == 0) {
Fprintf(stdout, "Subcircuit summary:\n");
*(ostr + left_col_end) = '|';
*(ostr + right_col_end) = '\n';
*(ostr + right_col_end + 1) = '\0';
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
snprintf(ostr, left_col_end, "Circuit 1: %s", Circuit1->name);
snprintf(ostr + left_col_end + 1, left_col_end, "Circuit 2: %s", Circuit2->name);
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
Fprintf(stdout, ostr);
for (i = 0; i < left_col_end; i++) *(ostr + i) = '-';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = '-';
Fprintf(stdout, ostr);
output_string_print_header(ostr, Circuit1, Circuit2);
output_string_print_divider(ostr, TRUE);
}
#ifdef TCL_NETGEN
@@ -3272,27 +3336,24 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
}
if (Debug == 0) {
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
output_string_fill(ostr);
if (M1 == C1)
snprintf(ostr, left_col_end, "%s (%d)", Esrch->object->model.class, C1);
output_string_left(ostr, "%s (%d)", Esrch->object->model.class, C1);
else
snprintf(ostr, left_col_end, "%s (%d->%d)", Esrch->object->model.class,
output_string_left(ostr, "%s (%d->%d)", Esrch->object->model.class,
M1, C1);
if (C2 > 0) {
if (M2 == C2)
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)%s", tp2->name,
output_string_right(ostr, "%s (%d)%s", tp2->name,
C2, (C2 == C1) ? "" : " **Mismatch**");
else
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d->%d)%s",
output_string_right(ostr, "%s (%d->%d)%s",
tp2->name, M2, C2, (C2 == C1) ? "" : " **Mismatch**");
}
else {
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching element)");
output_string_right(ostr, "%s", "(no matching element)");
}
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
Fprintf(stdout, ostr);
output_string_print(ostr);
}
#ifdef TCL_NETGEN
if (dolist) {
@@ -3351,17 +3412,15 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
}
if (Debug == 0) {
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
snprintf(ostr, left_col_end, "(no matching element)");
output_string_fill(ostr);
output_string_left(ostr, "%s", "(no matching element)");
if (C2 == M2)
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)",
output_string_right(ostr, "%s (%d)",
Esrch->object->model.class, C2);
else
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d->%d)",
output_string_right(ostr, "%s (%d->%d)",
Esrch->object->model.class, M2, C2);
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
Fprintf(stdout, ostr);
output_string_print(ostr);
}
#ifdef TCL_NETGEN
if (dolist) {
@@ -3405,14 +3464,12 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
C1, C2);
}
else {
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
snprintf(ostr, left_col_end, "Number of devices: %d%s", C1, (C1 == C2) ? "" :
output_string_fill(ostr);
output_string_left(ostr, "Number of devices: %d%s", C1, (C1 == C2) ? "" :
" **Mismatch**");
snprintf(ostr + left_col_end + 1, left_col_end, "Number of devices: %d%s", C2, (C1 == C2) ? "" :
output_string_right(ostr, "Number of devices: %d%s", C2, (C1 == C2) ? "" :
" **Mismatch**");
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
Fprintf(stdout, ostr);
output_string_print(ostr);
}
#ifdef TCL_NETGEN
@@ -3458,23 +3515,14 @@ void FirstNodePass(struct Node *N, int dolist)
char *ostr;
int i;
ostr = CALLOC(right_col_end + 2, sizeof(char));
*(ostr + left_col_end) = '|';
*(ostr + right_col_end) = '\n';
*(ostr + right_col_end + 1) = '\0';
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
snprintf(ostr, left_col_end, "Number of nets: %d%s", C1, (C1 == C2) ? "" :
ostr = output_string_init();
output_string_left(ostr, "Number of nets: %d%s", C1, (C1 == C2) ? "" :
" **Mismatch**");
snprintf(ostr + left_col_end + 1, left_col_end, "Number of nets: %d%s", C2, (C1 == C2) ? "" :
output_string_right(ostr, "Number of nets: %d%s", C2, (C1 == C2) ? "" :
" **Mismatch**");
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
Fprintf(stdout, ostr);
output_string_print(ostr);
for (i = 0; i < right_col_end; i++) *(ostr + i) = '-';
Fprintf(stdout, ostr);
output_string_print_divider(ostr, FALSE);
FREE(ostr);
}
@@ -5169,26 +5217,34 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
// (if any)
if (comb == TRUE) {
double pd;
int mult, cidx = -1;
struct valuelist *avl, *cvl = NULL;
critval.type = PROP_ENDLIST;
critval.value.dval = 0.0;
for (i = 0; i < run; i++) {
avl = NULL;
if (vlist[0][i] == NULL) continue;
mult = vlist[0][i]->value.ival;
// if (vlist[0][i] == NULL) continue;
// mult = vlist[0][i]->value.ival;
if (vlist[0][i] == NULL)
mult = 1;
else
mult = vlist[0][i]->value.ival;
changed = 0;
/* 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++) {
kl = plist[p];
vl = vlist[p][i];
ctype = clist[p][i];
/* critical properties never combine, but track them */
if ((series == TRUE) && (ctype & MERGE_S_CRIT)) {
if ((vl->type != critval.type) || (vl->value.dval != critval.value.dval))
pd = 2 * fabs(vl->value.dval - critval.value.dval) /
(vl->value.dval + critval.value.dval);
if ((vl->type != critval.type) || (pd > kl->slop.dval))
{
critval.type = vl->type;
critval.value = vl->value;
@@ -5197,7 +5253,9 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
continue;
}
if ((series == FALSE) && (ctype & MERGE_P_CRIT)) {
if ((vl->type != critval.type) || (vl->value.dval != critval.value.dval))
pd = 2 * fabs(vl->value.dval - critval.value.dval) /
(vl->value.dval + critval.value.dval);
if ((vl->type != critval.type) || (pd > kl->slop.dval))
{
critval.type = vl->type;
critval.value = vl->value;
@@ -5243,6 +5301,11 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
ctype = clist[p][i];
if (ctype & (MERGE_S_ADD | MERGE_P_ADD)) {
if (!vlist[0][i]) {
/* Create an entry with M = 0 to force removal */
vlist[0][i] = (struct valuelist *)CALLOC(1,
sizeof(struct valuelist));
}
vlist[0][i]->value.ival = 0; /* set M to 0 */
if (cvl && (cvl->type == PROP_INTEGER))
{
@@ -5262,6 +5325,11 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
}
}
else if (ctype & (MERGE_S_PAR | MERGE_P_PAR)) {
if (!vlist[0][i]) {
/* Create an entry with M = 0 to force removal */
vlist[0][i] = (struct valuelist *)CALLOC(1,
sizeof(struct valuelist));
}
vlist[0][i]->value.ival = 0; /* set M to 0 */
/* To do parallel combination, both types need to
* be double, so recast them if they are integer.
@@ -5987,6 +6055,9 @@ PropertyMatch(struct Element *E1, struct Element *E2,
#endif
}
obn1 = ob1->next;
obn2 = ob2->next;
/* Find the first property record of each circuit. obn1, obn2 are */
/* the last device record before the properties for each device. */
for (tp1 = ob1->next; (tp1 != NULL) && tp1->type > FIRSTPIN; tp1 = tp1->next)
@@ -6250,22 +6321,20 @@ PropertyMatch(struct Element *E1, struct Element *E2,
int multmatch, count;
PropertyCheckMismatch(tp1, tc1, inst1, tp2, tc2,
inst2, E1, E2, FALSE, FALSE, &multmatch, NULL);
if (multmatch == 1) {
/* Final attempt: Reduce M to 1 on both devices */
run1 = run2 = 0;
for (tpc = tp1; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run1++;
for (tpc = tp2; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run2++;
PropertyOptimize(tp1, tc1, run1, FALSE, TRUE);
PropertyOptimize(tp2, tc2, run2, FALSE, TRUE);
}
else if (multmatch == 2) {
run1 = run2 = 0;
for (tpc = tp1; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run1++;
for (tpc = tp2; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run2++;
if (multmatch == 2) {
/* Final attempt: Reduce S to 1 on both devices */
run1 = run2 = 0;
for (tpc = tp1; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run1++;
for (tpc = tp2; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run2++;
PropertyOptimize(tp1, tc1, run1, TRUE, TRUE);
PropertyOptimize(tp2, tc2, run2, TRUE, TRUE);
}
else if ((multmatch == 1) || (run1 != run2)) {
/* Final attempt: Reduce M to 1 on both devices */
PropertyOptimize(tp1, tc1, run1, FALSE, TRUE);
PropertyOptimize(tp2, tc2, run2, FALSE, TRUE);
}
#ifdef TCL_NETGEN
mlist =
#endif
@@ -6503,11 +6572,16 @@ void PrintAutomorphisms(void)
* separating out those devices that are connected to matching pins
* in each circuit.
*
* If match_nets == TRUE, then also match internal nets by name. Pins
* should always be matched by name without considering nets first;
* once all symmetries related to pins have been broken, then matching
* symmetries by net can keep the output from looking confusing.
*
* Return value is the same as VerifyMatching()
*-------------------------------------------------------------------------
*/
int ResolveAutomorphsByPin()
int ResolveAutomorphsByPin(int match_nets)
{
struct NodeClass *NC;
struct Node *N;
@@ -6516,7 +6590,10 @@ int ResolveAutomorphsByPin()
int portnum;
/* Diagnostic */
Fprintf(stdout, "Resolving symmetries by pin name.\n");
if (match_nets)
Fprintf(stdout, "Resolving symmetries by net name.\n");
else
Fprintf(stdout, "Resolving symmetries by pin name.\n");
for (NC = NodeClasses; NC != NULL; NC = NC->next) {
struct Node *N1, *N2;
@@ -6540,7 +6617,9 @@ int ResolveAutomorphsByPin()
if (N1->hashval != orighash) continue;
for (N2 = N1->next; N2 != NULL; N2 = N2->next) {
if ((N2->graph != N1->graph) &&
(*matchfunc)(N2->object->name, N1->object->name)) {
(*matchfunc)(N2->object->name, N1->object->name) &&
(N1->object->type == PORT || N2->object->type == PORT)) {
if (Debug == TRUE)
Printf("Symmetry group broken by name match (pin %s)\n", N2->object->name);
Magic(newhash);
@@ -6939,10 +7018,21 @@ int Permute()
return (0);
}
/* update magic numbers */
for (NL = E->nodelist; NL != NULL; NL = NL->next)
if (NL->pin_magic == one)
NL->pin_magic = two;
/* Update magic numbers. To ensure that this works */
/* regardless of the pin order of the pins in each */
/* netlist, always set both pins to the larger of */
/* the two pin_magic values. */
if (one > two) {
for (NL = E->nodelist; NL != NULL; NL = NL->next)
if (NL->pin_magic == two)
NL->pin_magic = one;
}
else {
for (NL = E->nodelist; NL != NULL; NL = NL->next)
if (NL->pin_magic == one)
NL->pin_magic = two;
}
}
}
}
@@ -7518,6 +7608,10 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
if (ob2->type != PORT) break;
else haspins = 1;
/* The model.port record for pins will be used to match the pin order
* of the cells in each netlist. Make sure the value is reset on
* entering this subroutine.
*/
ob2->model.port = -1;
}
numnodes = 0;
@@ -7546,23 +7640,13 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
}
#endif
ostr = CALLOC(right_col_end + 2, sizeof(char));
ostr = output_string_init();
if (Debug == 0) {
/* Format side-by-side comparison of pins */
Fprintf(stdout, "\nSubcircuit pins:\n");
*(ostr + left_col_end) = '|';
*(ostr + right_col_end) = '\n';
*(ostr + right_col_end + 1) = '\0';
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
snprintf(ostr, left_col_end, "Circuit 1: %s", tc1->name);
snprintf(ostr + left_col_end + 1, left_col_end, "Circuit 2: %s", tc2->name);
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
Fprintf(stdout, ostr);
for (i = 0; i < left_col_end; i++) *(ostr + i) = '-';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = '-';
Fprintf(stdout, ostr);
output_string_print_header(ostr, tc1, tc2);
output_string_print_divider(ostr, TRUE);
}
for (NC = NodeClasses; NC != NULL; NC = NC->next) {
@@ -7601,13 +7685,12 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
nomatch = FALSE;
if ((IsPort(ob2)) && (ob2->node == obp->node)) {
if (Debug == 0) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, left_col_end, "%s", ob1->name);
output_string_fill(ostr);
output_string_left(ostr, "%s", ob1->name);
}
if ((*matchfunc)(ob1->name, ob2->name)) {
if (Debug == 0)
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
output_string_right(ostr, "%s", ob2->name);
}
else {
/* Check remainder of ports to see if there is a name match on the
@@ -7619,7 +7702,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if ((*matchfunc)(ob3->name, ob1->name)) {
ob2 = ob3;
if (Debug == 0)
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
output_string_right(ostr, "%s", ob2->name);
break;
}
}
@@ -7627,9 +7710,10 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (ob3 == NULL) {
if (Debug == 0) {
if (ob2->model.port == -1)
snprintf(ostr + left_col_end + 1, left_col_end, "%s **Mismatch**", ob2->name);
output_string_right(ostr, "%s **Mismatch**",
ob2->name);
else
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
output_string_right(ostr, "%s", "(no matching pin)");
}
nomatch = TRUE;
/* Pins with different names are on different nets,
@@ -7640,9 +7724,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
}
if (Debug == 0) {
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
output_string_print(ostr);
}
else if (nomatch) {
Fprintf(stderr, "No matching pin in cell %s for "
@@ -7681,13 +7763,11 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
// so don't print out the "no pins" entry.
if (strcmp(obn->name, "(no pins)")) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, 32, "%s", obn->name);
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
output_string_fill(ostr);
output_string_left(ostr, "%s", obn->name);
output_string_right(ostr, "(no pin, node is %s)",
obp->name);
output_string_print(ostr);
}
}
else {
@@ -7729,13 +7809,10 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (ob1 == NULL) {
if (Debug == 0) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, left_col_end, "%s", obn->name);
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
output_string_fill(ostr);
output_string_left(ostr, "%s", obn->name);
output_string_right(ostr, "%s", "(no matching pin)");
output_string_print(ostr);
}
else {
Fprintf(stderr, "No netlist match for cell %s pin %s\n",
@@ -7815,13 +7892,10 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
*(cover + i) = (char)1;
if (Debug == 0) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, left_col_end, "%s", ob1->name);
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
output_string_fill(ostr);
output_string_left(ostr, "%s", ob1->name);
output_string_right(ostr, "%s", ob2->name);
output_string_print(ostr);
}
else {
Fprintf(stdout, "Circuit %s port %d \"%s\""
@@ -7870,13 +7944,10 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
*(cover + i) = (char)1;
if (Debug == 0) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, left_col_end, "%s", ob1->name);
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
output_string_fill(ostr);
output_string_left(ostr, "%s", ob1->name);
output_string_right(ostr, "%s", ob2->name);
output_string_print(ostr);
}
else {
Fprintf(stdout, "Circuit %s port %d \"%s\""
@@ -7934,13 +8005,10 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
*(cover + i) = (char)1;
if (Debug == 0) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, left_col_end, "%s", ob1->name);
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
output_string_fill(ostr);
output_string_left(ostr, "%s", ob1->name);
output_string_right(ostr, "%s", ob2->name);
output_string_print(ostr);
}
else {
Fprintf(stdout, "Circuit %s port %d \"%s\""
@@ -7989,16 +8057,38 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (ob2->type != PORT) break;
if (ob2->model.port == -1) {
/* Find this node in NodeClasses and find the corresponding
* net in the other circuit, if there is one (NOTE: Needs
* refactoring; should not be going through NodeClasses
* inside a loop.)
*/
obn = NULL;
for (NC = NodeClasses; NC != NULL; NC = NC->next) {
for (N2 = NC->nodes; N2 != NULL; N2 = N2->next) {
if (N2->graph != Circuit1->file) {
obp = N2->object;
if (IsPort(obp) && (obp->node == ob2->node)) {
for (N1 = NC->nodes; N1 != NULL; N1 = N1->next) {
if (N1->graph == Circuit1->file) {
obn = N1->object;
}
}
}
}
}
}
if (Debug == 0) {
// See above for reverse case
if (strcmp(ob2->name, "(no pins)")) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, left_col_end, "(no matching pin)");
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
output_string_fill(ostr);
if (obn == NULL)
output_string_left(ostr, "%s", "(no matching pin)");
else
output_string_left(ostr, "(no pin, node is %s)",
obn->name);
output_string_right(ostr, "%s", ob2->name);
output_string_print(ostr);
}
}
else {
@@ -8113,12 +8203,15 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (obn == NULL) ob1->node = -1; /* Make disconnected */
}
/* NOTE: Previously kept the port if model.port is -1; however,
* all ports are -1 here so not sure why that was in there. . .
*/
if (ob1 == NULL || ob1->type != PORT || ob1->node >= 0
|| (ob1->node < 0 && tc1->class == CLASS_MODULE)
|| (ob1->node < 0 && ob1->model.port == -1)) {
|| (ob1->node < 0 && tc1->class == CLASS_MODULE)) {
/* Add a proxy pin to tc2 */
obn = (struct objlist *)CALLOC(1, sizeof(struct objlist));
obn->node = -1;
if (ob1 == NULL) {
obn->name = (char *)MALLOC(15);
sprintf(obn->name, "proxy%d", rand() & 0x3ffffff);
@@ -8130,24 +8223,6 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
obn->type = UNKNOWN;
obn->model.port = (i - j);
obn->instance.name = NULL;
obn->node = -1;
/* Note: Has this pin already been accounted for? */
if (Debug == 0) {
if (strcmp(ob1->name, "(no pins)")) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, left_col_end, "%s", ob1->name);
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
}
}
else {
Fprintf(stderr, "No netlist match for cell %s pin %s\n",
tc1->name, ob1->name);
}
if (ob2 == tc2->cell) {
obn->next = ob2;
@@ -8163,9 +8238,16 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
HashPtrInstall(obn->name, obn, &(tc2->objdict));
}
else if (ob1 != NULL && ob1->type == PORT) {
else if (ob1 != NULL && ob1->type == PORT && ob1->node < 0) {
/* Disconnected node was not meaningful, has no pin match in */
/* the compared circuit, and so should be discarded. */
/* the compared circuit, and so should be discarded. This */
/* case is not output above, so do it here. */
output_string_fill(ostr);
output_string_left(ostr, "%s", ob1->name);
output_string_right(ostr, "%s", "(no matching pin)");
output_string_print(ostr);
ob1->node = -2;
needclean1 = 1;
@@ -8178,15 +8260,12 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
}
FREE(cover);
if (Debug == 0) {
for (i = 0; i < right_col_end; i++) *(ostr + i) = '-';
Fprintf(stdout, ostr);
}
if (Debug == 0)
output_string_print_divider(ostr, FALSE);
/* Run cleanuppins on circuit 1 */
if (needclean1) {
if (needclean1)
CleanupPins(tc1->name, tc1->file);
}
/* Add proxy pins to all instances of Circuit1 */
+1 -1
View File
@@ -62,7 +62,7 @@ extern void RegroupDataStructures();
extern void FormatIllegalElementClasses();
extern void FormatIllegalNodeClasses();
extern int ResolveAutomorphsByProperty();
extern int ResolveAutomorphsByPin();
extern int ResolveAutomorphsByPin(int match_nets);
extern void SummarizeElementClasses(struct ElementClass *EC);
extern int remove_group_tags(struct objlist *ob);
+16
View File
@@ -223,6 +223,7 @@ int matchnocase(char *st1, char *st2)
{
char *sp1 = st1;
char *sp2 = st2;
char v1 = FALSE, v2 = FALSE;
/* In case of a property that does not exist in one netlist, matchnocase()
* may be passed a null value, so return 0 to indicate a non-match.
@@ -231,11 +232,26 @@ int matchnocase(char *st1, char *st2)
*/
if (!sp1 || !sp2) return 0;
/* Verilog back-slash escaped names should match an equivalent non-
* back-slashed name. (NOTE: This behavior needs to be added to match().)
*/
if ((*sp1 == '\\') && (*sp2 != '\\')) {
v1 = TRUE;
sp1++;
}
if ((*sp2 == '\\') && (*sp1 != '\\')) {
v2 = TRUE;
sp2++;
}
while (*sp1 != '\0' && *sp2 != '\0') {
if (to_lower[*sp1] != to_lower[*sp2]) break;
sp1++;
sp2++;
}
if (v1 && (*sp1 == ' ')) sp1++;
if (v2 && (*sp2 == ' ')) sp2++;
if ((*sp1 != '\0') || (*sp2 != '\0')) return 0;
return 1;
}
+17 -4
View File
@@ -717,10 +717,12 @@ int GetBus(char *astr, struct bus *wb)
return 0;
}
//--------------------------------------------------------------------
// Output a Verilog Module. Note that since Verilog does not describe
// low-level devices like transistors, capacitors, etc., then this
// format is limited to black-box subcircuits. Cells containing any
// such low-level devices are ignored.
//--------------------------------------------------------------------
void VerilogModule(struct nlist *tp)
{
@@ -1833,8 +1835,9 @@ skip_endmodule:
}
else { /* "assign" */
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
if (GetBusTok(&wb) == 0) {
char *aptr = strvchr(nexttok, '[');
char *aptr = strvchr(nexttok, '[');
if (((aptr == NULL) && (GetBusTok(&wb) == 0)) ||
((aptr != NULL) && (GetBus(aptr, &wb) == 0))) {
if (aptr != NULL) {
*aptr = '\0';
/* Find object of first net in bus */
@@ -1852,6 +1855,15 @@ skip_endmodule:
}
else {
lhs = LookupObject(nexttok, CurrentCell);
/* Handle the case in which an assignment is made
* without first declaring a wire for the signal,
* which is considered valid syntax (patch by
* Sylvain Munaut).
*/
if (lhs == NULL) {
Node(nexttok);
lhs = LookupObject(nexttok, CurrentCell);
}
strcpy(noderoot, nexttok);
}
SkipTokComments(VLOG_DELIMITERS);
@@ -1900,8 +1912,9 @@ skip_endmodule:
break;
}
else {
if (GetBusTok(&wb2) == 0) {
char *aptr = strvchr(nexttok, '[');
char *aptr = strvchr(nexttok, '[');
if (((aptr == NULL) && (GetBusTok(&wb2) == 0)) ||
((aptr != NULL) && (GetBus(aptr, &wb2) == 0))) {
j = wb2.start;
if (aptr != NULL) {
*aptr = '\0';
+5
View File
@@ -655,6 +655,11 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
}
} elseif {[netgen::print queue] == {} && $result == 0} {
set pinMismatch 1
} else {
# This assumes that proxy pins are added correctly. Previously,
# that was not trusted, and so an initial pin mismatch would
# always force subcells to be flattened.
set doFlatten 0
}
}
if {$doFlatten} {
+17 -3
View File
@@ -2512,7 +2512,13 @@ _netcmp_run(ClientData clientData,
if (automorphisms > 0) {
// Next, attempt to resolve automorphisms uniquely by
// using the pin names
automorphisms = ResolveAutomorphsByPin();
automorphisms = ResolveAutomorphsByPin(FALSE);
}
if (automorphisms > 0) {
// Next, attempt to resolve automorphisms uniquely by
// using the net names (should only be done after
// resolving by pin).
automorphisms = ResolveAutomorphsByPin(TRUE);
}
if (automorphisms > 0) {
// Anything left is truly indistinguishable
@@ -2522,8 +2528,16 @@ _netcmp_run(ClientData clientData,
if (automorphisms == -1)
Fprintf(stdout, "Netlists do not match.\n");
else if (automorphisms == -2)
Fprintf(stdout, "Netlists match uniquely with port errors.\n");
else if (automorphisms == -2) {
Fprintf(stdout, "Netlists match uniquely with port");
if (PropertyErrorDetected) {
Fprintf(stdout, " and property errors.\n");
PrintPropertyResults(dolist);
}
else {
Fprintf(stdout, " errors.\n");
}
}
else {
if (automorphisms == 0)
Fprintf(stdout, "Netlists match uniquely");
+123 -80
View File
@@ -36,7 +36,7 @@ exec ${NETGEN_WISH:=wish} "$0" ${1+"$@"}
#
# set ::tkcon::PRIV(proxy) {wwwproxy:8080 1}
#
# Or you can set the above variable from within tkcon by calling
# Or you can set the above variable from within tkcon by calling
#
# tkcon master set ::tkcon:PRIV(proxy) wwwproxy:8080
#
@@ -44,6 +44,8 @@ exec ${NETGEN_WISH:=wish} "$0" ${1+"$@"}
if {$tcl_version < 8.0} {
return -code error "tkcon requires at least Tcl/Tk8"
} else {
# Prevent breaking on version 8.5.2
# package require -exact Tk $tcl_version
package require Tk $tcl_version
}
@@ -59,18 +61,6 @@ foreach pkg [info loaded {}] {
}
catch {unset pkg file name version}
# Tk 8.4 makes previously exposed stuff private.
# FIX: Update tkcon to not rely on the private Tk code.
#
if {![llength [info globals tkPriv]]} {
::tk::unsupported::ExposePrivateVariable tkPriv
}
foreach cmd {SetCursor UpDownLine Transpose ScrollPages} {
if {![llength [info commands tkText$cmd]]} {
::tk::unsupported::ExposePrivateCommand tkText$cmd
}
}
# Initialize the ::tkcon namespace
#
namespace eval ::tkcon {
@@ -196,7 +186,7 @@ proc ::tkcon::Init {} {
tkcon_puts tkcon_gets observe observe_var unalias which what
}
version 2.3
RCS {RCS: @(#) $Id: tkcon.tcl,v 1.2 2008/05/23 00:20:17 tim Exp $}
RCS {RCS: @(#) $Id: tkcon.tcl,v 1.2 2008/04/18 16:28:13 tim Exp $}
HEADURL {http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/tkcon/tkcon/tkcon.tcl?rev=HEAD}
docs "http://tkcon.sourceforge.net/"
email {jeff@hobbs.org}
@@ -654,7 +644,7 @@ proc ::tkcon::GarbageCollect {} {
## ::tkcon::EvalCmd) in turn. Any uncompleted command will not be eval'ed.
# ARGS: w - console text widget
# Calls: ::tkcon::CmdGet, ::tkcon::CmdSep, ::tkcon::EvalCmd
##
##
proc ::tkcon::Eval {w} {
set incomplete [CmdSep [CmdGet $w] cmds last]
$w mark set insert end-1c
@@ -674,7 +664,7 @@ proc ::tkcon::Eval {w} {
# Calls: ::tkcon::Prompt
# Outputs: result of command to stdout (or stderr if error occured)
# Returns: next event number
##
##
proc ::tkcon::EvalCmd {w cmd} {
variable OPT
variable PRIV
@@ -745,7 +735,7 @@ proc ::tkcon::EvalCmd {w cmd} {
$w tag bind $tag <Leave> \
[list $w tag configure $tag -underline 0]
$w tag bind $tag <ButtonRelease-1> \
"if {!\[info exists tkPriv(mouseMoved)\] || !\$tkPriv(mouseMoved)} \
"if {!\[info exists ::tk::Priv(mouseMoved)\] || !\$::tk::Priv(mouseMoved)} \
{[list edit -attach [Attach] -type error -- $PRIV(errorInfo)]}"
} else {
$w insert output $res\n stderr
@@ -905,7 +895,7 @@ proc ::tkcon::EvalSocketClosed {} {
## ::tkcon::EvalNamespace - evaluates the args in a particular namespace
## This is an override for ::tkcon::EvalAttached for when the user wants
## to attach to a particular namespace of the attached interp
# ARGS: attached
# ARGS: attached
# namespace the namespace to evaluate in
# args the args to evaluate
# RETURNS: the result of the command
@@ -933,7 +923,7 @@ proc ::tkcon::Namespaces {{ns ::} {l {}}} {
## ::tkcon::CmdGet - gets the current command from the console widget
# ARGS: w - console text widget
# Returns: text which compromises current command line
##
##
proc ::tkcon::CmdGet w {
if {![llength [$w tag nextrange prompt limit end]]} {
$w tag add stdin limit end-1c
@@ -947,7 +937,7 @@ proc ::tkcon::CmdGet w {
# last - varname of any remainder (like an incomplete final command).
# If there is only one command, it's placed in this var.
# Returns: constituent command info in varnames specified by list & rmd.
##
##
proc ::tkcon::CmdSep {cmd list last} {
upvar 1 $list cmds $last inc
set inc {}
@@ -974,7 +964,7 @@ proc ::tkcon::CmdSep {cmd list last} {
## ::tkcon::CmdSplit - splits multiple commands into a list
# ARGS: cmd - (possible) multiple command to separate
# Returns: constituent commands in a list
##
##
proc ::tkcon::CmdSplit {cmd} {
set inc {}
set cmds {}
@@ -998,7 +988,7 @@ proc ::tkcon::CmdSplit {cmd} {
## Called by ::tkcon::EvalCmd
# ARGS: w - text widget
# Outputs: tag name guaranteed unique in the widget
##
##
proc ::tkcon::UniqueTag {w} {
set tags [$w tag names]
set idx 0
@@ -1011,7 +1001,7 @@ proc ::tkcon::UniqueTag {w} {
# ARGS: w - console text widget
# size - # of lines to constrain to
# Outputs: may delete data in console widget
##
##
proc ::tkcon::ConstrainBuffer {w size} {
if {[$w index end] > $size} {
$w delete 1.0 [expr {int([$w index end])-$size}].0
@@ -1021,7 +1011,7 @@ proc ::tkcon::ConstrainBuffer {w size} {
## ::tkcon::Prompt - displays the prompt in the console widget
# ARGS: w - console text widget
# Outputs: prompt (specified in ::tkcon::OPT(prompt1)) to console
##
##
proc ::tkcon::Prompt {{pre {}} {post {}} {prompt {}}} {
variable OPT
variable PRIV
@@ -1053,7 +1043,7 @@ proc ::tkcon::Prompt {{pre {}} {post {}} {prompt {}}} {
}
## ::tkcon::About - gives about info for tkcon
##
##
proc ::tkcon::About {} {
variable OPT
variable PRIV
@@ -1088,7 +1078,7 @@ proc ::tkcon::About {} {
## ::tkcon::InitMenus - inits the menubar and popup for the console
# ARGS: w - console text widget
##
##
proc ::tkcon::InitMenus {w title} {
variable OPT
variable PRIV
@@ -1521,7 +1511,7 @@ proc ::tkcon::NamespaceMenu m {
}
}
## Namepaces List
## Namepaces List
##
proc ::tkcon::NamespacesList {names} {
variable PRIV
@@ -1894,7 +1884,7 @@ proc ::tkcon::NewSocket {} {
## The file is actually sourced in the currently attached's interp
# ARGS: fn - (optional) filename to source in
# Returns: selected filename ({} if nothing was selected)
##
##
proc ::tkcon::Load { {fn ""} } {
set types {
{{Tcl Files} {.tcl .tk}}
@@ -1913,7 +1903,7 @@ proc ::tkcon::Load { {fn ""} } {
## This does not eval in a slave because it's not necessary
# ARGS: w - console text widget
# fn - (optional) filename to save to
##
##
proc ::tkcon::Save { {fn ""} {type ""} {opt ""} {mode w} } {
variable PRIV
@@ -1983,7 +1973,7 @@ proc ::tkcon::MainInit {} {
## Creates a slave interpreter and sources in this script.
## All other interpreters also get a command to eval function in the
## new interpreter.
##
##
proc ::tkcon::New {} {
variable PRIV
global argv0 argc argv
@@ -2020,7 +2010,7 @@ proc ::tkcon::MainInit {} {
## ::tkcon::Exit - full exit OR destroy slave console
## This proc should only be called in the main interpreter from a slave.
## The master determines whether we do a full exit or just kill the slave.
##
##
proc ::tkcon::Exit {slave args} {
variable PRIV
variable OPT
@@ -2043,7 +2033,7 @@ proc ::tkcon::MainInit {} {
## This proc should only be called by the main interpreter. If it is
## called from there, it will ask before exiting tkcon. All others
## (slaves) will just have their slave interpreter deleted, closing them.
##
##
proc ::tkcon::Destroy {{slave {}}} {
variable PRIV
@@ -2474,7 +2464,7 @@ proc ::tkcon::ErrorHighlight w {
$w tag configure $tag -foreground $COLOR(stdout)
$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)} \
$w tag bind $tag <ButtonRelease-1> "if {!\$::tk::Priv(mouseMoved)} \
{[list edit -attach $app -type proc -find $what -- $cmd]}"
}
set info [string range $info $c1 end]
@@ -2503,7 +2493,7 @@ proc ::tkcon::ErrorHighlight w {
$w tag configure $tag -foreground $COLOR(proc)
$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)} \
$w tag bind $tag <ButtonRelease-1> "if {!\$::tk::Priv(mouseMoved)} \
{[list edit -attach $app -type proc -- $cmd]}"
}
}
@@ -2513,7 +2503,7 @@ proc ::tkcon::ErrorHighlight w {
## This always exists in the main interpreter, and is aliased into
## other connected interpreters
# ARGS: totally variable, see internal comments
##
##
proc tkcon {cmd args} {
global errorInfo
@@ -2552,8 +2542,8 @@ proc tkcon {cmd args} {
## 'congets' a replacement for [gets stdin]
# Use the 'gets' alias of 'tkcon_gets' command instead of
# calling the *get* methods directly for best compatability
if {[llength $args]} {
return -code error "wrong # args: must be \"tkcon congets\""
if {[llength $args] > 1} {
return -code error "wrong # args: must be \"tkcon congets [pfix]\""
}
tkcon show
set old [bind TkConsole <<TkCon_Eval>>]
@@ -2561,7 +2551,12 @@ proc tkcon {cmd args} {
set w $::tkcon::PRIV(console)
# Make sure to move the limit to get the right data
$w mark set insert end
$w mark set limit insert
if {[llength $args]} {
$w mark set limit insert
$w insert end $args
} else {
$w mark set limit insert
}
$w see end
vwait ::tkcon::PRIV(wait)
set line [::tkcon::CmdGet $w]
@@ -2790,21 +2785,27 @@ proc tkcon {cmd args} {
## This allows me to capture all stdout/stderr to the console window
## This will be renamed to 'puts' at the appropriate time during init
##
# ARGS: same as usual
# ARGS: same as usual
# Outputs: the string with a color-coded text tag
##
##
proc tkcon_puts args {
set len [llength $args]
foreach {arg1 arg2 arg3} $args { break }
if {$len == 1} {
tkcon console insert output "$arg1\n" stdout
set sarg $arg1
set nl 1
set farg stdout
} elseif {$len == 2} {
if {![string compare $arg1 -nonewline]} {
tkcon console insert output $arg2 stdout
set sarg $arg2
set farg stdout
set nl 0
} elseif {![string compare $arg1 stdout] \
|| ![string compare $arg1 stderr]} {
tkcon console insert output "$arg2\n" $arg1
set sarg $arg2
set farg $arg1
set nl 1
} else {
set len 0
}
@@ -2812,11 +2813,15 @@ proc tkcon_puts args {
if {![string compare $arg1 -nonewline] \
&& (![string compare $arg2 stdout] \
|| ![string compare $arg2 stderr])} {
tkcon console insert output $arg3 $arg2
set sarg $arg3
set farg $arg2
set nl 0
} elseif {(![string compare $arg1 stdout] \
|| ![string compare $arg1 stderr]) \
&& ![string compare $arg3 nonewline]} {
tkcon console insert output $arg2 $arg1
set sarg $arg2
set farg $arg1
set nl 0
} else {
set len 0
}
@@ -2826,7 +2831,42 @@ proc tkcon_puts args {
## $len == 0 means it wasn't handled by tkcon above.
##
if {$len == 0} {
if {$len != 0} {
## "poor man's" \r substitution---erase everything on the output
## line and print from character after the \r
set rpt [string last \r $sarg]
if {$rpt >= 0} {
tkcon console delete "insert linestart" "insert lineend"
set sarg [string range $sarg [expr {$rpt + 1}] end]
}
set bpt [string first \b $sarg]
if {$bpt >= 0} {
set narg [string range $sarg [expr {$bpt + 1}] end]
set sarg [string range $sarg 0 [expr {$bpt - 1}]]
set nl 0
}
if {$nl == 0} {
tkcon console insert output $sarg $farg
} else {
tkcon console insert output "$sarg\n" $farg
}
if {$bpt >= 0} {
tkcon console delete "insert -1 char" insert
if {$nl == 0} {
tkcon_puts $farg $narg nonewline
} else {
tkcon_puts $farg $narg
}
}
} else {
global errorCode errorInfo
if {[catch "tkcon_tcl_puts $args" msg]} {
regsub tkcon_tcl_puts $msg puts msg
@@ -2849,7 +2889,7 @@ proc tkcon_puts args {
## This allows me to capture all stdin input without needing to stdin
## This will be renamed to 'gets' at the appropriate time during init
##
# ARGS: same as gets
# ARGS: same as gets
# Outputs: same as gets
##
proc tkcon_gets args {
@@ -2873,12 +2913,12 @@ proc tkcon_gets args {
}
## edit - opens a file/proc/var for reading/editing
##
##
# Arguments:
# type proc/file/var
# what the actual name of the item
# Returns: nothing
##
##
proc edit {args} {
array set opts {-find {} -type {} -attach {}}
while {[string match -* [lindex $args 0]]} {
@@ -3030,7 +3070,7 @@ proc echo args { puts [concat $args] }
## clear - clears the buffer of the console (not the history though)
## This is executed in the parent interpreter
##
##
proc clear {{pcnt 100}} {
if {![regexp {^[0-9]*$} $pcnt] || $pcnt < 1 || $pcnt > 100} {
return -code error \
@@ -3048,7 +3088,7 @@ proc clear {{pcnt 100}} {
## If called with one arg, returns the alias of that arg (or {} if none)
# ARGS: newcmd - (optional) command to bind alias to
# args - command and args being aliased
##
##
proc alias {{newcmd {}} args} {
if {[string match {} $newcmd]} {
set res {}
@@ -3065,7 +3105,7 @@ proc alias {{newcmd {}} args} {
## unalias - unaliases an alias'ed command
# ARGS: cmd - command to unbind as an alias
##
##
proc unalias {cmd} {
interp alias {} $cmd {}
}
@@ -3085,7 +3125,7 @@ proc unalias {cmd} {
# -- forcibly ends options recognition
#
# Returns: the values of the requested items in a 'source'able form
##
##
proc dump {type args} {
set whine 1
set code ok
@@ -3637,13 +3677,13 @@ proc observe_var {name el op} {
## which - tells you where a command is found
# ARGS: cmd - command name
# Returns: where command is found (internal / external / unknown)
##
##
proc which cmd {
## This tries to auto-load a command if not recognized
set types [uplevel 1 [list what $cmd 1]]
if {[llength $types]} {
set out {}
foreach type $types {
switch -- $type {
alias { set res "$cmd: aliased to [alias $cmd]" }
@@ -3674,7 +3714,7 @@ proc which cmd {
## what - tells you what a string is recognized as
# ARGS: str - string to id
# Returns: id types of command as list
##
##
proc what {str {autoload 0}} {
set types {}
if {[llength [info commands $str]] || ($autoload && \
@@ -3721,7 +3761,7 @@ proc what {str {autoload 0}} {
# -long - list in full format "permissions size date filename"
# -full - displays / after directories and link paths for links
# Returns: a directory listing
##
##
proc dir {args} {
array set s {
all 0 full 0 long 0
@@ -4106,7 +4146,7 @@ proc ::tkcon::Bindings {} {
global tcl_platform tk_version
#-----------------------------------------------------------------------
# Elements of tkPriv that are used in this file:
# Elements of ::tk::Priv that are used in this file:
#
# char - Character position on the line; kept in order
# to allow moving up or down past short lines while
@@ -4131,9 +4171,12 @@ proc ::tkcon::Bindings {} {
}
## Get all Text bindings into TkConsole
foreach ev [bind Text] { bind TkConsole $ev [bind Text $ev] }
foreach ev [bind Text] { bind TkConsole $ev [bind Text $ev] }
## We really didn't want the newline insertion
bind TkConsole <Control-Key-o> {}
## in 8.6b3, the virtual events <<NextLine>> and <<PrevLine>>
# mess up our history feature
bind TkConsole <<NextLine>> {}
bind TkConsole <<PrevLine>> {}
@@ -4342,9 +4385,9 @@ proc ::tkcon::Bindings {} {
bind TkConsole <Control-a> {
if {[%W compare {limit linestart} == {insert linestart}]} {
tkTextSetCursor %W limit
::tk::TextSetCursor %W limit
} else {
tkTextSetCursor %W {insert linestart}
::tk::TextSetCursor %W {insert linestart}
}
}
bind TkConsole <Key-Home> [bind TkConsole <Control-a>]
@@ -4368,14 +4411,14 @@ proc ::tkcon::Bindings {} {
}
bind TkConsole <<TkCon_Previous>> {
if {[%W compare {insert linestart} != {limit linestart}]} {
tkTextSetCursor %W [tkTextUpDownLine %W -1]
::tk::TextSetCursor %W [::tk::TextUpDownLine %W -1]
} else {
::tkcon::Event -1
}
}
bind TkConsole <<TkCon_Next>> {
if {[%W compare {insert linestart} != {end-1c linestart}]} {
tkTextSetCursor %W [tkTextUpDownLine %W 1]
::tk::TextSetCursor %W [::tk::TextUpDownLine %W 1]
} else {
::tkcon::Event 1
}
@@ -4390,7 +4433,7 @@ proc ::tkcon::Bindings {} {
}
bind TkConsole <<TkCon_Transpose>> {
## Transpose current and previous chars
if {[%W compare insert > "limit+1c"]} { tkTextTranspose %W }
if {[%W compare insert > "limit+1c"]} { ::tk::TextTranspose %W }
}
bind TkConsole <<TkCon_ClearLine>> {
## Clear command line (Unix shell staple)
@@ -4408,10 +4451,10 @@ proc ::tkcon::Bindings {} {
::tkcon::Insert %W $::tkcon::PRIV(tmp)
%W see end
}
catch {bind TkConsole <Key-Page_Up> { tkTextScrollPages %W -1 }}
catch {bind TkConsole <Key-Prior> { tkTextScrollPages %W -1 }}
catch {bind TkConsole <Key-Page_Down> { tkTextScrollPages %W 1 }}
catch {bind TkConsole <Key-Next> { tkTextScrollPages %W 1 }}
catch {bind TkConsole <Key-Page_Up> { ::tk::TextScrollPages %W -1 }}
catch {bind TkConsole <Key-Prior> { ::tk::TextScrollPages %W -1 }}
catch {bind TkConsole <Key-Page_Down> { ::tk::TextScrollPages %W 1 }}
catch {bind TkConsole <Key-Next> { ::tk::TextScrollPages %W 1 }}
bind TkConsole <$PRIV(meta)-d> {
if {[%W compare insert >= limit]} {
%W delete insert {insert wordend}
@@ -4429,7 +4472,7 @@ proc ::tkcon::Bindings {} {
}
bind TkConsole <ButtonRelease-2> {
if {
(!$tkPriv(mouseMoved) || $tk_strictMotif) &&
(!$::tk::Priv(mouseMoved) || $tk_strictMotif) &&
![catch {::tkcon::GetSelection %W} ::tkcon::PRIV(tmp)]
} {
if {[%W compare @%x,%y < limit]} {
@@ -4600,7 +4643,7 @@ proc ::tkcon::TagProc w {
# c1 - first char of pair
# c2 - second char of pair
# Calls: ::tkcon::Blink
##
##
proc ::tkcon::MatchPair {w c1 c2 {lim 1.0}} {
if {[string compare {} [set ix [$w search -back $c1 insert $lim]]]} {
while {
@@ -4638,7 +4681,7 @@ proc ::tkcon::MatchPair {w c1 c2 {lim 1.0}} {
## The quote to match is assumed to be at the text index 'insert'.
# ARGS: w - console text widget
# Calls: ::tkcon::Blink
##
##
proc ::tkcon::MatchQuote {w {lim 1.0}} {
set i insert-1c
set j 0
@@ -4664,7 +4707,7 @@ proc ::tkcon::MatchQuote {w {lim 1.0}} {
# i2 - end index of blink region
# dur - duration in usecs to blink for
# Outputs: blinks selected characters in $w
##
##
proc ::tkcon::Blink {w args} {
eval [list $w tag add blink] $args
after $::tkcon::OPT(blinktime) [list $w] tag remove blink $args
@@ -4679,7 +4722,7 @@ proc ::tkcon::Blink {w args} {
# ARGS: w - text window in which to insert the string
# s - string to insert (usually just a single char)
# Outputs: $s to text widget
##
##
proc ::tkcon::Insert {w s} {
if {[string match {} $s] || [string match disabled [$w cget -state]]} {
return
@@ -4695,7 +4738,7 @@ proc ::tkcon::Insert {w s} {
$w see insert
}
## ::tkcon::Expand -
## ::tkcon::Expand -
# ARGS: w - text widget in which to expand str
# type - type of expansion (path / proc / variable)
# Calls: ::tkcon::Expand(Pathname|Procname|Variable)
@@ -4704,7 +4747,7 @@ proc ::tkcon::Insert {w s} {
# match equaled the string to expand, then all possible matches
# are output to stdout. Triggers bell if no matches are found.
# Returns: number of matches found
##
##
proc ::tkcon::Expand {w {type ""}} {
set exp "\[^\\\\\]\[\[ \t\n\r\\\{\"$\]"
set tmp [$w search -backwards -regexp $exp insert-1c limit-1c]
@@ -4743,7 +4786,7 @@ proc ::tkcon::Expand {w {type ""}} {
# Calls: ::tkcon::ExpandBestMatch
# Returns: list containing longest unique match followed by all the
# possible further matches
##
##
proc ::tkcon::ExpandPathname str {
set pwd [EvalAttached pwd]
# Cause a string like {C:/Program\ Files/} to become "C:/Program Files/"
@@ -4825,7 +4868,7 @@ proc ::tkcon::ExpandProcname str {
# Calls: ::tkcon::ExpandBestMatch
# Returns: list containing longest unique match followed by all the
# possible further matches
##
##
proc ::tkcon::ExpandVariable str {
if {[regexp {([^\(]*)\((.*)} $str junk ary str]} {
## Looks like they're trying to expand an array.
@@ -4853,7 +4896,7 @@ proc ::tkcon::ExpandVariable str {
## or $e is {}. $e is extra for compatibility with proc below.
# ARGS: l - list to find best unique match in
# Returns: longest unique match in the list
##
##
proc ::tkcon::ExpandBestMatch2 {l {e {}}} {
set s [lindex $l 0]
if {[llength $l]>1} {
@@ -4873,7 +4916,7 @@ proc ::tkcon::ExpandBestMatch2 {l {e {}}} {
# ARGS: l - list to find best unique match in
# e - currently best known unique match
# Returns: longest unique match in the list
##
##
proc ::tkcon::ExpandBestMatch {l {e {}}} {
set ec [lindex $l 0]
if {[llength $l]>1} {
@@ -5237,7 +5280,7 @@ proc ::tkcon::Retrieve {} {
## ::tkcon::Resource - re'source's this script into current console
## Meant primarily for my development of this program. It follows
## links until the ultimate source is found.
##
##
set ::tkcon::PRIV(SCRIPT) [info script]
if {!$::tkcon::PRIV(WWW) && [string compare $::tkcon::PRIV(SCRIPT) {}]} {
# we use a catch here because some wrap apps choke on 'file type'