Compare commits

...
14 Commits
Author SHA1 Message Date
Tim Edwards bb8a6108b9 Merge branch 'master' into netgen-1.5 2026-07-07 02:00:05 -04:00
R. Timothy Edwards e1528a797c Corrected the parsing for assignment left-hand-side to allow for
whitespace inside the array declaration, as was (correctly) done
for pin connections.  Previously, "assign x[ 0] = 1'b1" would
fail due to "x[" being parsed as a token by itself.  Now, upon
reading an array opening bracket delimiter, the verilog parser
will continue to read tokens until it finds the closing bracket,
as it does for pin connections.
2026-07-06 10:22:02 -04:00
Tim Edwards 5e48c4e876 Merge branch 'master' into netgen-1.5 2026-06-29 02:00:02 -04:00
R. Timothy Edwards 2c94087510 Corrected an error in delimiter parsing, which is due to the lack of
any standard array delimiter character in SPICE.  Often brackets are
used, but just as often angle brackets are used instead, and do not
match the bracket syntax of verilog.  The "matchnocase" function
automatically casts common delimiter characters to a single type to
facilitate matching between names using different delimiters.
However, some code in MatchPins() was assuming square brackets and
breaking this allowance, causing pins to be marked mismatch in spite
of the handling in "matchnocase".  The code has been corrected to
make the same allowance for different delimiter characters everywhere.
2026-06-28 11:44:42 -04:00
Tim Edwards 0b4a8fe9d6 Merge branch 'master' into netgen-1.5 2026-06-09 02:00:04 -04:00
R. Timothy Edwards 3eadc8b0dc Corrected some issues in the SPICE parser where a subcircuit name
was checked using "subcktname" before its initialization.  Added
a check for a subcircuit called inside itself, which causes an
immediate failure (see issue tracker issue #106).  If allowed to
continue, netgen will either crash or produce inscrutable output
that doesn't pinpoint the issue.
2026-06-08 14:11:07 -04:00
Tim Edwards b3af7b98b4 Merge branch 'master' into netgen-1.5 2026-05-22 02:00:04 -04:00
R. Timothy Edwards 9630670071 The example cited in the last commit is not completely solved by
the code changes in the last commit.  There is still an issue in
which pins should match between name X on one side and X[Y] on
the other side, if there is no X[Z] where Z != Y, specifically if
one or both cells is a black box, since the equivalence cannot
be determined by net matching.

The pin matching has gotten out of hand and really should be
completely redone. . .
2026-05-21 15:35:57 -04:00
R. Timothy Edwards f29452e550 An example found by Leo Moser showed that netgen makes an incorrect
pin assignment when a verilog input file declares a signal "bundle"
with only one signal in it.  The solution is to detect bundles which
have only one component in them, and remove the bundle delimiters
("{...}") so that the pin connection is treated as a simple signal
or vector.
2026-05-21 14:19:24 -04:00
Tim Edwards da3b96ae9e Merge branch 'master' into netgen-1.5 2026-04-28 02:00:02 -04:00
R. Timothy Edwards 8a2bbe0723 Updated version to go along with PR #105 from user jalcim on github. 2026-04-27 09:50:37 -04:00
jalcim a0c49a026a fix(netcmp): correct signal handler type for K&R declaration
netcmp.c:55 declares oldinthandler with empty parameter list:
    void (*oldinthandler)() = SIG_DFL;

In K&R / pre-C23, this means 'function with unspecified parameters'.
GCC 14+ infers void(*)(void), which is incompatible with signal(2)'s
expected void(*)(int) handler. The signal(SIGINT, oldinthandler) calls
at lines 8777 and 8784 then fail with -Wincompatible-pointer-types
(now a default error in GCC 14+).

This 1-line fix matches the actual usage as a SIGINT handler with int
signum parameter, and restores tclnetgen.so build on Fedora 41+ /
Debian 13+ / Ubuntu 24.04+ (any system with GCC 14+).

Tested: tclnetgen.so now builds successfully and 'netgen -batch lvs'
mode works again.
2026-04-26 22:06:07 +02:00
Tim Edwards 1520e276bc Merge branch 'master' into netgen-1.5 2026-04-04 02:00:02 -04:00
R. Timothy Edwards 665203bba1 Corrected genhash() after Mitch Bailey pointed out that the function
was no longer hashing on both values passed to the function, as it
is supposed to.
2026-04-03 08:48:34 -04:00
7 changed files with 144 additions and 7 deletions
+1 -1
View File
@@ -1 +1 @@
1.5.317
1.5.323
+3 -1
View File
@@ -164,8 +164,10 @@ unsigned long hashcase(char *s, int hashsize)
unsigned long genhash(char *s, int c, int hashsize)
{
unsigned long hashval = 2166136261ul;
hashval ^= (unsigned long)c;
hashval *= 16777619ul;
for (; *s != '\0'; s++) {
hashval ^= (unsigned long)c;
hashval ^= (unsigned char)(*s);
hashval *= 16777619ul;
}
return (hashsize == 0) ? hashval : (hashval % hashsize);
+56 -2
View File
@@ -52,7 +52,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef TCL_NETGEN
int InterruptPending = 0;
void (*oldinthandler)() = SIG_DFL;
void (*oldinthandler)(int) = SIG_DFL;
extern Tcl_Interp *netgeninterp;
extern int check_interrupt();
#endif
@@ -7896,7 +7896,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (*(cover + i) == (char)0) {
j = 0;
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
char *name1, *name2;
char *name1, *name2, *aptr1 = NULL, *aptr2 = NULL;
char delim1, delim2;
if (!IsPort(ob2)) break;
@@ -7914,8 +7915,59 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (!strncmp(name1, "proxy", 5) && (ob2->node == -1)) name1 +=5;
if (!strncmp(name2, "proxy", 5) && (ob1->node == -1)) name2 +=5;
/* Recognize an array as matching a non-array of the same */
/* name if the array is size 1. There must be a better way */
/* to do this; this method makes excessive calls to */
/* matchfunc(). */
if ((tc1->flags & CELL_PLACEHOLDER) || (tc2->flags && CELL_PLACEHOLDER)) {
aptr1 = get_array_delimiter(name1, &delim1);
aptr2 = get_array_delimiter(name2, &delim2);
if ((aptr1 != NULL) && (aptr2 == NULL)) {
*aptr1 = '\0';
if ((*matchfunc)(name1, name2)) {
/* Check that name1 does not have another array
* component in ob1
*/
struct objlist *ob3;
for (ob3 = tc1->cell; ob3; ob3 = ob3->next) {
if (!IsPort(ob3)) break;
if (ob3 == ob1) continue;
if (!strncmp(ob3->name, name1, strlen(name1)) &&
is_delimiter(*(ob3->name + strlen(name1)))) {
*aptr1 = delim1;
break;
}
}
}
}
if ((aptr1 == NULL) && (aptr2 != NULL)) {
*aptr2 = '\0';
if ((*matchfunc)(name1, name2)) {
/* Check that name2 does not have another array
* component in ob1
*/
struct objlist *ob3;
for (ob3 = tc2->cell; ob3; ob3 = ob3->next) {
if (!IsPort(ob3)) break;
if (ob3 == ob2) continue;
if (!strncmp(ob3->name, name2, strlen(name2)) &&
is_delimiter(*(ob3->name + strlen(name2)))) {
*aptr2 = delim2;
break;
}
}
}
}
}
if ((*matchfunc)(name1, name2)) {
if (aptr1) *aptr1 = delim1;
if (aptr2) *aptr2 = delim2;
/* If both sides have unconnected nodes, then pins with */
/* matching names are an automatic match. Otherwise, if */
/* matching black-box entries, then pins are always */
@@ -8069,6 +8121,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
}
}
if (bangptr2) *bangptr2 = '!';
if (aptr1) *aptr1 = delim1;
if (aptr2) *aptr2 = delim2;
j++;
}
}
+27
View File
@@ -282,6 +282,33 @@ int matchfilenocase(char *st1, char *st2, int f1, int f2)
return 1;
}
/* Delimiter matching---Find an opening delimiter in a string. */
/* Return the position of the first opening delimeter in the string, */
/* like strchr(). Place the actual delimeter character in *delim. */
char *get_array_delimiter(char *name, char *delim)
{
char *stest = name;
while (*stest != '\0')
{
if (to_lower[*stest] == '<') {
*delim = *stest;
return stest;
}
stest++;
}
return NULL;
}
/* Delimiter parsing---Check if a character is an opening array delimiter. */
/* Return TRUE if the character is an opening delimiter, FALSE if not. */
int is_delimiter(char testc)
{
return (to_lower[testc] == '<') ? TRUE : FALSE;
}
#ifdef HAVE_MALLINFO
void PrintMemoryStats(void)
{
+2
View File
@@ -309,6 +309,8 @@ extern int match(char *, char *);
extern int matchnocase(char *, char *);
extern int matchfile(char *, char *, int, int);
extern int matchfilenocase(char *, char *, int, int);
extern int is_delimiter(char);
extern char *get_array_delimiter(char *, char *);
extern void GarbageCollect(void);
extern void InitGarbageCollection(void);
+12 -3
View File
@@ -1783,10 +1783,19 @@ skip_ends:
if (scan->next != NULL) scan = scan->next;
tail->next = NULL;
/* Check for class defined inside itself (self-referential loop) */
if (!strcasecmp(model, scan->name)) {
Fprintf(stderr, "Fatal: Class \"%s\" is instanced inside of itself!\n",
scan->name);
InputParseError(stderr);
return;
}
/* Check for ignored class */
if ((itype = IsIgnored(subcktname, filenum)) == IGNORE_CLASS) {
Printf("Class '%s' instanced in input but is being ignored.\n", model);
if ((itype = IsIgnored(scan->name, filenum)) == IGNORE_CLASS) {
Printf("Class '%s' instanced in input but is being ignored.\n", scan->name);
return;
}
@@ -1801,7 +1810,7 @@ skip_ends:
break;
}
if (shorted == (unsigned char)1) {
Printf("Instance of '%s' is shorted, ignoring.\n", subcktname);
Printf("Instance of '%s' is shorted, ignoring.\n", scan->name);
while (head) {
p = head->next;
FREE(head);
+43
View File
@@ -1914,6 +1914,38 @@ skip_endmodule:
else { /* "assign" */
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
char *aptr = strvchr(nexttok, '[');
/* This is a repeat of code to handle reading of pins, and
* makes sure that all input has been read to the closing
* bracket. There needs to be a single routine to do this,
* or (better) rewrite the parser with lex instead of trying
* to enumerate all the syntax cases separately.
*/
if ((aptr != NULL) && (strvchr(nexttok, ']') == NULL))
{
/* If a bus expressions has whitespace, then concatenate
* to the closing ']'.
*/
char *array_expr = (char *)MALLOC(1);
char *new_array_expr = NULL;
*array_expr = '\0';
/* Read to "]" */
while (nexttok) {
new_array_expr = (char *)MALLOC(strlen(array_expr) +
strlen(nexttok) + 1);
/* Roundabout way to do realloc() becase there is no REALLOC() */
strcpy(new_array_expr, array_expr);
strcat(new_array_expr, nexttok);
FREE(array_expr);
array_expr = new_array_expr;
if (strchr(nexttok, ']')) break;
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
}
if (!nexttok) {
Printf("Unterminated array in assignment %s\n", array_expr);
}
}
if (((aptr == NULL) && (GetBusTok(&wb) == 0)) ||
((aptr != NULL) && (GetBus(aptr, &wb) == 0))) {
if (aptr != NULL) {
@@ -2295,7 +2327,18 @@ nextinst:
FREE(wire_bundle);
wire_bundle = new_wire_bundle;
if (!strcmp(nexttok, "}"))
{
/* If a "bundle" has only one component, then it is
* not really a bundle and should be treated as a
* single wire.
*/
if (strchr(wire_bundle, ',') == NULL) {
int blen = strlen(wire_bundle + 1) - 1;
memmove(wire_bundle, wire_bundle + 1, blen);
*(wire_bundle + blen) = '\0';
}
break;
}
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
}
if (!nexttok) {