Compare commits

..

19 Commits

Author SHA1 Message Date
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
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
R. Timothy Edwards 0192558d4b Updated version corresponding to the last commit. 2026-04-02 21:30:01 -04:00
R. Timothy Edwards 21d329b22d Modified the hash algorithm used by netgen after a discussion with
ChatGPT about hash implementations.  Switched from SDBM to FNV-1a,
which should be a better/stronger hash algorithm.  Could do
something more sophisticated, but this change can be done in a few
minutes.
2026-04-02 21:29:04 -04:00
R. Timothy Edwards 37b1a2a07d Cleaned up some errors (most minor, some not so minor) in the
code that were surfaced by Stefan Thiede running clang on Mac
OS.  Function prototype warnings have not been fixed yet, as
that is a more involved fix, although it needs to be done.
2026-02-02 20:53:13 -05:00
R. Timothy Edwards 777f7ef095 Found a counting issue with netcmp output that will overrun the
output string buffer if the size of the copied string is just
the wrong amount, due to the use of strcpy() instead of
strncpy() in at least one place.  Just hacked a solution by
allocating more space for the string, but this should be fixed
properly.  Also:  Discovered that the "zero valued resistor"
routine looks for shorted ports in the wrong place, and if it
finds shorted ports it wrongly decides that the device it's
looking at is a zero-valued resistor whether or not it really
is zero-valued.
2026-01-15 16:39:18 -05:00
R. Timothy Edwards 9b4185fe62 Reverted a change from a long time ago regarding removal of zero
valued resistors connecting two ports.  I do not recall exactly
why I put that in but it appears to cause incorrect behavior.
2025-12-28 14:54:07 -05:00
R. Timothy Edwards ddd95c4fe6 Added a few lines to the setup file parser so that if there is a
missing brace in the file (a common error), then the fact that
there is an unevaluated command when the file has finished being
read will trigger an evaluation of the unfinished code and emit
an error.  Previously, the command and anything after the
unterminated brace would just silently get ignored, which was not
helpful for debugging setup syntax errors.
2025-12-11 12:08:31 -05:00
R. Timothy Edwards c0c9993980 Corrected a major error with the verilog parser. The verilog
parser was not assigning the correct file number for the first
input file, which resulted in the effect that if the first
file read sets definitions for the netlist, then those definitions
are wiped out on the following file read.  There has been a workaround
to read from /dev/null on the first file read so that the file number
is set on all subsequent reads.  This fix avoids the need for the
workaround.
2025-12-08 16:45:27 -05:00
R. Timothy Edwards 8a20b90074 Corrected an issue that can cause a segfault in an incorrect run
setup when a cell has no pins.  Didn't really analyze the error
condition, just caught and handled the condition to avoid the
segfault.
2025-12-08 13:09:50 -05:00
R. Timothy Edwards 3392159243 Added some extra code to the verilog parser. It now handles some
additional syntax for wire bundles specified as a pin connection
on an array of instances, and a few other things.  These are not
exhaustive but are solving an immediate problem.  I will go back
and clean up the code to make it work for more general cases
later.
2025-11-29 11:55:26 -05:00
R. Timothy Edwards 24c6eb4cb9 Updated the version to go along with the merge of pull request 2025-11-24 12:26:57 -05:00
Mitch Bailey 9048191486 Allow processing of cellnames with $.
When loading a file, also print cellname on errors

Signed-off-by: Mitch Bailey <d.mitch.bailey@gmail.com>
2025-11-24 12:26:30 -05:00
R. Timothy Edwards 72d7d55bbe Corrected an issue with the "-noflatten" switch to "lvs", which is
also a problem with the underlying "flatten prohibit" command
option;  in one place, the cell's subcircuits were being prohibited
from being flattened, causing issues including a potential infinite
loop.
2025-11-21 15:52:14 -05:00
R. Timothy Edwards 04163aedcc One hopefully final modification to ensure that Tcl_InitStubs()
uses the Tcl version that the program has been compiled to.  This
should work with both Tcl 8.X and Tcl 9.X.
2025-11-12 11:32:18 -05:00
R. Timothy Edwards f7d35f9cca Accidentally changed a file in the last commit which gets
overwritten by "configure".  Moved the modification to the source
file that doesn't get overwritten.
2025-11-12 09:55:29 -05:00
R. Timothy Edwards 601277e539 Updated the revision number for the last set of changes. 2025-11-12 09:19:52 -05:00
R. Timothy Edwards 73344329f8 Made some updates for Tcl 9 compatibility; also changed the
Makefile to pass EXTRA_CFLAGS for testing with "-std=c99" and
"-std=gnu99".  Made some additional corrections to ensure a
clean compile using -std=gnu99.
2025-11-12 09:17:46 -05:00
14 changed files with 291 additions and 101 deletions

View File

@ -1 +1 @@
1.5.307
1.5.319

View File

@ -91,7 +91,7 @@ char *ActelName(char *Name)
/* strip physical-pin information, if it exists */
if ((nm = strrchr(name,PHYSICALPIN[0])) != NULL) *nm = '\0';
if (strlen(name) > 13) {
ActelIndex = (++ActelIndex) % ACTELNAMESIZE;
ActelIndex = (ActelIndex + 1) % ACTELNAMESIZE;
/* format the value of the hashed value of the string */
sprintf(ActelNames[ActelIndex], "$%lX", ActelNameHash(name));
if (Debug)
@ -102,7 +102,7 @@ Printf("ActelNameHash returns %s on name %s\n",ActelNames[ActelIndex], name);
NeedsQuoting = 0;
if (NULL != strpbrk(name, ".,:; \t\"'\n\r")) NeedsQuoting = 1;
ActelIndex = (++ActelIndex) % ACTELNAMESIZE;
ActelIndex = (ActelIndex + 1) % ACTELNAMESIZE;
if (!NeedsQuoting) {
strcpy(ActelNames[ActelIndex], name);
return(ActelNames[ActelIndex]);

View File

@ -300,8 +300,6 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
return 0;
}
}
/* Placeholder cells must not be flattened */
if (ThisCell->flags & CELL_PLACEHOLDER) return 0;
FreeNodeNames(ThisCell);
@ -339,6 +337,10 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
LastObj = ParentParams;
continue;
}
if (ChildCell->flags & CELL_PLACEHOLDER) {
LastObj = ParentParams;
continue; // Placeholder cells must not be flattened
}
if (ChildCell == ThisCell) {
LastObj = ParentParams;
continue; // Avoid infinite loop
@ -1753,8 +1755,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell1->name,
name1, file1);
flattenInstancesOf(name1, file1, ecomp->cell1->name);
modified1++;
if (flattenInstancesOf(name1, file1, ecomp->cell1->name) > 0)
modified1++;
}
else if (ecomp->cell1 && (ecomp->num1 > 0)) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
@ -1766,8 +1768,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell2->name,
name2, file2);
flattenInstancesOf(name2, file2, ecomp->cell2->name);
modified2++;
if (flattenInstancesOf(name2, file2, ecomp->cell2->name) > 0)
modified2++;
}
else if (ecomp->cell2 && (ecomp->num2 > 0)) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
@ -1861,8 +1863,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell2->name,
name2, file2);
flattenInstancesOf(name2, file2, ecomp->cell2->name);
modified2++;
if (flattenInstancesOf(name2, file2, ecomp->cell2->name) > 0)
modified2++;
}
else if (ecomp->cell2) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
@ -1932,8 +1934,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell1->name,
name1, file1);
flattenInstancesOf(name1, file1, ecomp->cell1->name);
modified1++;
if (flattenInstancesOf(name1, file1, ecomp->cell1->name) > 0)
modified1++;
}
else if (ecomp->cell1) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
@ -2016,8 +2018,11 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
break;
}
}
if (found) break;
}
/* Do NOT remove shorting devices that */
if (found) {
/* Beware remove shorting devices that */
/* connect two ports. Otherwise the */
/* port lists get screwed up. It is */
/* better in that case to force the */
@ -2025,6 +2030,10 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
/* This is ignored for a top-level cell */
/* because it will just show up as a */
/* port mismatch error as it should. */
/* (12/12/2025---disabling this worked; */
/* may need to go back to a failing */
/* example and determine how pin */
/* matching gets scrambled.) */
if ((not_top == TRUE) &&
(ecomp->cell1->class != CLASS_ISOURCE)) {
@ -2037,14 +2046,18 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
else if (ob2->node == node2)
found2 = TRUE;
if (found1 && found2) {
found = FALSE;
Fprintf(stdout, "Warning: "
"zero-valued device connects "
"port %s to another port; pin "
"matching may be affected.\n",
ob2->name);
// found = FALSE;
break;
}
}
}
if (found) break;
}
if (found) {
Fprintf(stdout, "Removing zero-valued device "
"%s from cell %s (%d) makes a better "
@ -2295,11 +2308,12 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
Fprintf(stdout, "Flattening instances of %s in cell"
" %s (%d) makes a better match\n",
ecompX0->cell1->name, name1, file1);
flattenInstancesOf(name1, file1,
ecompX0->cell1->name);
ecompX0->num1 = 0;
ecomp0X->num1 += ecompX0->num1;
modified1++;
if (flattenInstancesOf(name1, file1,
ecompX0->cell1->name) > 0) {
ecompX0->num1 = 0;
ecomp0X->num1 += ecompX0->num1;
modified1++;
}
}
else
{
@ -2331,11 +2345,12 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
Fprintf(stdout, "Flattening instances of %s in cell"
" %s (%d) makes a better match\n",
ecomp0X->cell2->name, name2, file2);
flattenInstancesOf(name2, file2,
ecomp0X->cell2->name);
ecomp0X->num2 = 0;
ecompX0->num2 += ecomp0X->num2;
modified2++;
if (flattenInstancesOf(name2, file2,
ecomp0X->cell2->name) > 0) {
ecomp0X->num2 = 0;
ecompX0->num2 += ecomp0X->num2;
modified2++;
}
}
else {
Fprintf(stdout, "Flattening instances of %s in "

View File

@ -137,32 +137,39 @@ static unsigned char uppercase[] = {
// horrible things can happen, as, for example, names AOI12 and OAI12
// have exactly the same hash result. Lousy for binning and even
// lousier for generating class magic numbers.
//
// Updated again 4/2/2026 to the FNV-1a hash, which is better than
// SDBM for this application, according to ChatGPT.
unsigned long hashnocase(char *s, int hashsize)
{
unsigned long hashval;
for (hashval = 0; *s != '\0'; )
hashval = uppercase[*s++]
+ (hashval << 6) + (hashval << 16) - hashval;
unsigned long hashval = 2166136261ul;
for (; *s != '\0'; s++) {
hashval ^= uppercase[*s];
hashval *= 16777619ul;
}
return (hashsize == 0) ? hashval : (hashval % hashsize);
}
unsigned long hashcase(char *s, int hashsize)
{
unsigned long hashval;
for (hashval = 0; *s != '\0'; )
hashval = (*s++) + (hashval << 6) + (hashval << 16) - hashval;
unsigned long hashval = 2166136261ul;
for (; *s != '\0'; s++) {
hashval ^= (unsigned char)(*s);
hashval *= 16777619ul;
}
return (hashsize == 0) ? hashval : (hashval % hashsize);
}
unsigned long genhash(char *s, int c, int hashsize)
{
unsigned long hashval;
for (hashval = (unsigned long)c; *s != '\0'; )
hashval = (*s++) + (hashval << 6) + (hashval << 16) - hashval;
unsigned long hashval = 2166136261ul;
hashval ^= (unsigned long)c;
hashval *= 16777619ul;
for (; *s != '\0'; s++) {
hashval ^= (unsigned char)(*s);
hashval *= 16777619ul;
}
return (hashsize == 0) ? hashval : (hashval % hashsize);
}

View File

@ -24,6 +24,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdarg.h>
#include <setjmp.h>
#include <signal.h>
#include <strings.h> /* for strncasecmp() */
#include <time.h> /* for time() as a seed for random number generator */
#include <limits.h>
#include <math.h> /* for fabs() */
@ -51,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
@ -1621,8 +1622,8 @@ void FormatIllegalElementClasses()
char *permcount;
int bytesleft;
permname = CALLOC(right_col_end + 2, sizeof(char));
permcount = CALLOC(right_col_end + 2, sizeof(char));
permname = CALLOC(right_col_end + 100, sizeof(char));
permcount = CALLOC(right_col_end + 100, sizeof(char));
ostr = output_string_init();
found = 0;
@ -3581,7 +3582,7 @@ int FlattenUnmatched(struct nlist *tc, char *parent, int stoplevel, int loclevel
tc->name, parent, tc->file);
changed = flattenInstancesOf(parent, tc->file, tc->name);
Fprintf(stdout, "(%d instance%s)\n", changed, ((changed == 1) ? "" : "s"));
return 1;
return (changed != 0);
}
if (tc->cell == NULL) return 0;
@ -7543,6 +7544,11 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata)
}
else {
lob = ob;
if (ob == NULL) {
Fprintf(stdout, "Error: Premature end of pin list on "
"instance %s.\n", firstpin->instance.name);
break;
}
ob->type = i++;
ob = ob->next;
}

View File

@ -685,6 +685,7 @@ void SpiceSkipNewLine(void)
ungetc(contline, infile);
}
#if 0 /* Commented with "#if 0" due to comment characters in the comment */
/*----------------------------------------------------------------------*/
/* Function similar to strtok() for token parsing. The difference is */
/* that it takes two sets of delimiters. The first is whitespace */
@ -705,6 +706,7 @@ void SpiceSkipNewLine(void)
/* the first character of the delimiter string in addition to marking */
/* the boundary between two-character and one-character delimiters. */
/*----------------------------------------------------------------------*/
#endif
char *strdtok0(char *pstring, char *delim1, char *delim2, char isverilog)
{

View File

@ -25,6 +25,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <stdlib.h> /* for strtof() */
#include <stdarg.h>
#include <string.h>
#include <strings.h>
#include <ctype.h> /* toupper() */
#ifdef IBMPC
#include <alloc.h>

View File

@ -449,6 +449,7 @@ int removeshorted(struct hashlist *p, int file)
ob = nob;
}
}
return 1;
}
/* Remove shorted instances of class "class" from the database */
@ -539,6 +540,7 @@ int deleteclass(struct hashlist *p, int file)
}
}
FREE(checknodes);
return 1;
}
/* Remove all instances of class "class" from the database */
@ -576,6 +578,7 @@ int renameinstances(struct hashlist *p, int file)
}
}
}
return 1;
}
void InstanceRename(char *from, char *to, int file)
@ -598,9 +601,10 @@ int freeprop(struct hashlist *p)
struct property *prop;
prop = (struct property *)(p->ptr);
if (prop->type == PROP_STRING)
if (prop->type == PROP_STRING) {
if (prop->pdefault.string != NULL)
FREE(prop->pdefault.string);
}
else if (prop->type == PROP_EXPRESSION) {
struct tokstack *stackptr, *nptr;
stackptr = prop->pdefault.stack;

View File

@ -319,7 +319,7 @@ void Fanout(char *cell, char *node, int filter)
while (ob != NULL) {
char *obname = ob->name;
if (*obname == '/') obname++;
if (ob->node == nodenum)
if (ob->node == nodenum) {
if (filter == ALLOBJECTS) {
Printf(" %s (", obname);
PrintObjectType(ob->type);
@ -331,6 +331,7 @@ void Fanout(char *cell, char *node, int filter)
else if (ob->type == filter) {
Printf(" %s\n", obname);
}
}
ob = ob->next;
}
}
@ -933,7 +934,7 @@ static int PrintLeavesInCellHash(struct hashlist *p)
struct nlist *ptr;
ptr = (struct nlist *)(p->ptr);
if ((ptr->class == CLASS_SUBCKT)) PrintLeavesInCell(ptr->name, ptr->file);
if (ptr->class == CLASS_SUBCKT) PrintLeavesInCell(ptr->name, ptr->file);
return(0);
}

View File

@ -21,6 +21,9 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#if 0
#include <stdarg.h> /* what about varargs, like in pdutils.c ??? */
#endif
@ -193,7 +196,7 @@ void SpiceSubCell(struct nlist *tp, int IsSubCell)
if (ob->type == PROPERTY) {
struct valuelist *vl;
int i;
for (i == 0;; i++) {
for (i = 0;; i++) {
vl = &(ob->instance.props[i]);
if (vl->type == PROP_ENDLIST) break;
else if (vl->type == PROP_VALUE) {
@ -213,7 +216,7 @@ void SpiceSubCell(struct nlist *tp, int IsSubCell)
if (ob->type == PROPERTY) {
struct valuelist *vl;
int i;
for (i == 0;; i++) {
for (i = 0;; i++) {
vl = &(ob->instance.props[i]);
if (vl->type == PROP_ENDLIST) break;
else if (vl->type == PROP_VALUE) {
@ -233,7 +236,7 @@ void SpiceSubCell(struct nlist *tp, int IsSubCell)
if (ob->type == PROPERTY) {
struct valuelist *vl;
int i;
for (i == 0;; i++) {
for (i = 0;; i++) {
vl = &(ob->instance.props[i]);
if (vl->type == PROP_ENDLIST) break;
else if (vl->type == PROP_VALUE) {
@ -396,7 +399,7 @@ int renamepins(struct hashlist *p, int file)
ptr = (struct nlist *)(p->ptr);
if (ptr->file != file)
return 1;
return 0;
for (ob = ptr->cell; ob != NULL; ob = ob->next) {
if (ob->type == FIRSTPIN) {
@ -423,6 +426,7 @@ int renamepins(struct hashlist *p, int file)
}
}
}
return 1;
}
/* If any pins are marked unconnected, see if there are */

View File

@ -76,7 +76,8 @@ struct hashdict verilogparams;
// Global storage for verilog definitions
struct hashdict verilogdefs;
// Record file pointer that is associated with the hash tables
int hashfile = -1;
int hashfilep = -1; /* for parameters */
int hashfiled = -1; /* for definitions */
// Global storage for wire buses
struct hashdict buses;
@ -156,7 +157,8 @@ struct expr_stack {
//-------------------------------------------------------------------------
// Evaluate an expression for an array bound. This is much like
// ReduceOneExpression() in netgen.c, but only handles basic integer
// arithmetic (+,-,*,/) and grouping by parentheses.
// arithmetic (+,-,*,/), grouping by parentheses, bit shifts, and
// if-else operators.
//
// Returns 1 if successful, 0 on error.
// Evaluated result is placed in the integer pointed to by "valptr".
@ -220,6 +222,39 @@ int EvalExpr(struct expr_stack **stackptr, int *valptr)
}
}
/* Reduce (a << b) and (a >> b) */
for (texp = start; texp; texp = texp->next) {
if ((texp->last != NULL) && (texp->next != NULL) && (texp->oper != '\0')) {
if ((texp->last->oper == '\0') && (texp->next->oper == '\0')) {
if (texp->oper == '<') {
/* Left shift */
texp->last->value <<= texp->next->value;
/* Remove two items from the stack */
tmp = texp;
texp = texp->last;
texp->next = tmp->next->next;
if (tmp->next->next) tmp->next->next->last = texp;
FREE(tmp->next);
FREE(tmp);
modified = TRUE;
}
if (texp->oper == '>') {
/* Right shift */
texp->last->value >>= texp->next->value;
/* Remove two items from the stack */
tmp = texp;
texp = texp->last;
texp->next = tmp->next->next;
if (tmp->next->next) tmp->next->next->last = texp;
FREE(tmp->next);
FREE(tmp);
modified = TRUE;
}
}
}
}
/* Reduce (a * b) and (a / b) */
for (texp = start; texp; texp = texp->next) {
@ -295,6 +330,39 @@ int EvalExpr(struct expr_stack **stackptr, int *valptr)
}
}
/* Reduce (a ? b : c) */
for (texp = start; texp; texp = texp->next) {
/* There must be at least five objects on the stack */
if ((texp->last != NULL) && (texp->next != NULL) && (texp->oper != '\0')
&& (texp->next->next != NULL)
&& (texp->next->next->next != NULL)) {
if ((texp->last->oper == '\0') && (texp->next->oper == '\0')
&& (texp->next->next->next->oper == '\0')) {
if ((texp->oper == '?') && (texp->next->next->oper == ':')) {
/* If-Else conditional */
if (texp->last->value)
texp->last->value = texp->next->value;
else
texp->last->value = texp->next->next->next->value;
/* Remove four items from the stack */
tmp = texp;
texp = texp->last;
texp->next = tmp->next->next->next->next;
if (tmp->next->next->next->next)
tmp->next->next->next->next->last = texp;
FREE(tmp->next->next->next);
FREE(tmp->next->next);
FREE(tmp->next);
FREE(tmp);
modified = TRUE;
}
}
}
}
/* Reduce (a) */
for (texp = start; texp; texp = texp->next) {
@ -373,8 +441,15 @@ int ParseIntegerExpression(char *expr, int *iptr)
if (match(sptr, "+") || match(sptr, "-")
|| match(sptr, "*") || match(sptr, "/")
|| match(sptr, "(") || match(sptr, ")")) {
|| match(sptr, "(") || match(sptr, ")")
|| match(sptr, "<<") || match(sptr, ">>")
|| match(sptr, "?") || match(sptr, ":")) {
newexp = (struct expr_stack *)MALLOC(sizeof(struct expr_stack));
/* Note that "oper" is one character and that "<<" and ">>"
* become '<' and '>', respectively. The less-than and greater-
* than operators are not (yet) handled but will need to be
* recast to some other character in "oper".
*/
newexp->oper = *sptr;
newexp->value = 0;
newexp->next = NULL;
@ -389,7 +464,7 @@ int ParseIntegerExpression(char *expr, int *iptr)
if ((result = sscanf(sptr, "%d", &value)) != 1) {
// Is name in the parameter list?
kl = (struct property *)HashLookup(nexttok, &verilogparams);
kl = (struct property *)HashLookup(sptr, &verilogparams);
if (kl == NULL) {
Printf("Value %s in expression is not a number or a parameter.\n",
sptr);
@ -402,27 +477,29 @@ int ParseIntegerExpression(char *expr, int *iptr)
if (result != 1) {
Printf("Parameter %s has value %s that cannot be parsed"
" as an integer.\n",
nexttok, kl->pdefault.string);
sptr, kl->pdefault.string);
value = 0;
break;
}
}
else if (kl->type == PROP_INTEGER) {
value = kl->pdefault.ival;
result = 1; // Assert valid result
}
else if (kl->type == PROP_DOUBLE) {
value = (int)kl->pdefault.dval;
if ((double)value != kl->pdefault.dval) {
Printf("Parameter %s has value %g that cannot be parsed"
" as an integer.\n",
nexttok, kl->pdefault.dval);
sptr, kl->pdefault.dval);
value = 0;
break;
}
result = 1; // Assert valid result
}
else {
Printf("Parameter %s has unknown type; don't know how"
" to parse.\n", nexttok);
" to parse.\n", sptr);
value = 0;
break;
}
@ -516,7 +593,8 @@ int GetBusTok(struct bus *wb)
}
else if (match(nexttok, "+") || match(nexttok, "-")
|| match(nexttok, "*") || match(nexttok, "/")
|| match(nexttok, "(") || match(nexttok, ")")) {
|| match(nexttok, "(") || match(nexttok, ")")
|| match(nexttok, "<<") || match(nexttok, ">>")) {
newexp = (struct expr_stack *)MALLOC(sizeof(struct expr_stack));
newexp->oper = *nexttok;
newexp->value = 0;
@ -1879,7 +1957,8 @@ skip_endmodule:
// 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.
// "assign" using if-else constructs or bit shifts.
// ("assign" using any other boolean arithmetic is not structural verilog.)
// "assign a = {x{b}}" creates a bus by repeating a component.
if (nexttok && match(nexttok, "=")) {
@ -2140,6 +2219,19 @@ nextinst:
}
SkipTokComments(VLOG_DELIMITERS);
}
else if (loop.loopvar != NULL) {
/* Instances created within a generate block for loop have an
* implicit array
*/
int loopval;
struct property *klr;
klr = (struct property *)HashLookup(loop.loopvar, &verilogparams);
loopval = klr->pdefault.ival;
arraystart = arrayend = loopval;
sprintf(instancename + strlen(instancename), "[%d]", loopval);
}
if (match(nexttok, "(")) {
char savetok = (char)0;
@ -2202,7 +2294,8 @@ nextinst:
strcat(new_wire_bundle, nexttok);
FREE(wire_bundle);
wire_bundle = new_wire_bundle;
if (!strcmp(nexttok, "}")) break;
if (!strcmp(nexttok, "}"))
break;
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
}
if (!nexttok) {
@ -2578,6 +2671,7 @@ nextinst:
char *brackptr;
int j;
char locinst[MAX_STR_LEN];
int arraypos = (arraystart > arrayend) ? arraymax - i : i;
if (i != -1)
sprintf(locinst, "%s[%d]", instancename, i);
@ -2627,7 +2721,14 @@ nextinst:
else if (GetBus(scan->net, &wb) == 0) {
char *bptr2;
char *scanroot;
scanroot = strsave(scan->net);
int isbundle = FALSE;
/* Skip over a bundle delimiter */
if (*scan->net == '{') {
scanroot = strsave(scan->net + 1);
isbundle = TRUE;
}
else
scanroot = strsave(scan->net);
brackptr = strvchr(scanroot, '[');
if (brackptr) *brackptr = '\0';
@ -2660,6 +2761,7 @@ nextinst:
else {
// Instance must be an array
char netname[MAX_STR_LEN];
char *spos = scanroot;
int slice, portlen, siglen;
/* Get the array size of the port for bit slicing */
@ -2671,27 +2773,49 @@ nextinst:
if (siglen < 0) siglen = -siglen;
siglen++;
// If signal array is smaller than the portlength *
// length of instance array, then the signal wraps.
// If this is a bundle, then count out to the current
// slice and read off the index. NOTE: Need to
// handle multiple bits per bundle entry!
if (isbundle) {
int j;
if (brackptr) *brackptr = '[';
for (j = 0; j < arraypos * portlen; j++) {
spos = strvchr(spos, ',');
if (spos == NULL) break;
spos++;
}
if (spos != NULL) {
brackptr = strvchr(spos, '[');
*brackptr = '\0';
sscanf(brackptr + 1, "%d", &slice);
}
else spos = scanroot; /* should emit an error here */
}
else { /* not a bundle */
if (wb2.start >= wb2.end && arraystart >= arrayend) {
slice = wb.start - (arraystart - i) * portlen;
while (slice < wb2.end) slice += siglen;
}
else if (wb2.start < wb2.end && arraystart > arrayend) {
slice = wb.start + (arraystart - i) * portlen;
while (slice > wb2.end) slice -= siglen;
}
else if (wb2.start > wb2.end && arraystart < arrayend) {
slice = wb.start - (arraystart + i) * portlen;
while (slice < wb2.end) slice += siglen;
}
else { // (wb2.start < wb2.end && arraystart < arrayend)
slice = wb.start + (arraystart + i) * portlen;
while (slice > wb2.end) slice -= siglen;
// If signal array is smaller than the portlength *
// length of instance array, then the signal wraps.
if (wb2.start >= wb2.end && arraystart >= arrayend) {
slice = wb.start - (arraystart - i) * portlen;
while (slice < wb2.end) slice += siglen;
}
else if (wb2.start < wb2.end && arraystart > arrayend) {
slice = wb.start + (arraystart - i) * portlen;
while (slice > wb2.end) slice -= siglen;
}
else if (wb2.start > wb2.end && arraystart < arrayend) {
slice = wb.start - (arraystart + i) * portlen;
while (slice < wb2.end) slice += siglen;
}
else { // (wb2.start < wb2.end && arraystart < arrayend)
slice = wb.start + (arraystart + i) * portlen;
while (slice > wb2.end) slice -= siglen;
}
spos = scanroot;
}
sprintf(netname, "%s[%d]", scanroot, slice);
sprintf(netname, "%s[%d]", spos, slice);
if (LookupObject(netname, CurrentCell) == NULL) Node(netname);
join(netname, obptr->name);
}
@ -2876,18 +3000,25 @@ char *ReadVerilogTop(char *fname, int *fnum, int blackbox)
hashfunc = hashcase;
}
if ((hashfile != -1) && (hashfile != *fnum)) {
/* Started a new file, so remove all the parameters and definitions */
if ((hashfilep != -1) && (hashfilep != *fnum)) {
/* Started a new file, so remove all the parameters */
RecurseHashTable(&verilogparams, freeprop);
HashKill(&verilogparams);
hashfilep = -1;
}
if ((hashfiled != -1) && (hashfiled != *fnum)) {
/* Started a new file, so remove all the definitions */
RecurseHashTable(&verilogdefs, freeprop);
HashKill(&verilogdefs);
hashfile = -1;
hashfiled = -1;
}
if (hashfile == -1) {
if (hashfilep == -1) {
InitializeHashTable(&verilogparams, OBJHASHSIZE);
hashfilep = filenum;
}
if (hashfiled == -1) {
InitializeHashTable(&verilogdefs, OBJHASHSIZE);
hashfile = *fnum;
hashfiled = filenum;
}
definitions = &verilogdefs;

View File

@ -68,6 +68,7 @@ LIB_SPECS = @LIB_SPECS@
LIB_SPECS_NOSTUB = @LIB_SPECS_NOSTUB@
WISH_EXE = @WISH_EXE@
TCL_LIB_DIR = @TCL_LIB_DIR@
EXTRA_CFLAGS =
CC = @CC@
CPP = @CPP@
@ -76,7 +77,7 @@ CXX = @CXX@
CPPFLAGS = -I. -I${NETGENDIR} @CPPFLAGS@
DFLAGS = @extra_defs@ @stub_defs@ @DEFS@ -DSHDLIB_EXT=\"@SHDLIB_EXT@\" -DNDEBUG
DFLAGS_NOSTUB = @extra_defs@ @DEFS@ -DSHDLIB_EXT=\"@SHDLIB_EXT@\" -DNDEBUG
CFLAGS = @CFLAGS@ @SHLIB_CFLAGS@ @INC_SPECS@
CFLAGS = @CFLAGS@ @SHLIB_CFLAGS@ @INC_SPECS@ ${EXTRA_CFLAGS}
DEPEND_FILE = Depend
DEPEND_FLAG = @DEPEND_FLAG@

View File

@ -429,7 +429,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
set file1 $name1
set cell1 $name1
}
puts stdout "Reading netlist file $file1"
puts stdout "Reading netlist file $file1 for $name1"
set fnum1 [netgen::readnet $file1]
} else {
set cell1 [lindex $flist1 0]
@ -446,7 +446,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
set file2 $name2
set cell2 $name2
}
puts stdout "Reading netlist file $file2"
puts stdout "Reading netlist file $file2 for $name2"
set fnum2 [netgen::readnet $file2]
} else {
set cell2 [lindex $flist2 0]
@ -461,7 +461,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
}
set clist1 [cells list $fnum1]
set cidx [lsearch -regexp $clist1 ^$cell1$]
set cidx [lsearch -exact $clist1 $cell1]
if {$cidx < 0} {
puts stderr "Cannot find cell $cell1 in file $file1"
return
@ -469,7 +469,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
set cell1 [lindex $clist1 $cidx]
}
set clist2 [cells list $fnum2]
set cidx [lsearch -regexp $clist2 ^$cell2$]
set cidx [lsearch -exact $clist2 $cell2]
if {$cidx < 0} {
puts stderr "Cannot find cell $cell2 in file $file2"
return
@ -516,6 +516,14 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
}
}
close $fsetup
if {$command != {}} {
# Incomplete command. Evaluate it to get a meaningful error message
if {[catch {uplevel 1 [list namespace eval netgen $command]} msg]} {
set msg [string trimright $msg "\n"]
puts stderr "Error $setupfile:$sline (ignoring), $msg"
incr perrors
}
}
} else {
puts stdout "Error: Cannot read the setup file $setupfile"
}

View File

@ -21,6 +21,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <stdlib.h> /* for getenv */
#include <string.h>
#include <strings.h>
#include <stdarg.h> /* for va_list */
#include <tcl.h>
@ -43,6 +45,10 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#define FALSE 0
#endif
#if TCL_MAJOR_VERSION < 9
typedef int Tcl_Size;
#endif
/*-----------------------*/
/* Tcl 8.4 compatibility */
/*-----------------------*/
@ -283,7 +289,7 @@ GetTopCell(int fnum)
int
CommonGetFilenameOrFile(Tcl_Interp *interp, Tcl_Obj *fobj, int *fnumptr)
{
int result, llen;
int result;
int fnum, ftest;
char *filename;
struct nlist *tp;
@ -366,7 +372,8 @@ CommonParseCell(Tcl_Interp *interp, Tcl_Obj *objv,
struct nlist **tpr, int *fnumptr)
{
Tcl_Obj *tobj, *fobj;
int result, llen;
int result;
Tcl_Size llen;
int fnum, ftest, index;
char *filename, *cellname;
struct nlist *tp, *tp2;
@ -1016,7 +1023,7 @@ _netgen_flatten(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
char *repstr, *file;
int result, llen, filenum;
int result, filenum;
struct nlist *tp, *tp2, *tptop;
if ((objc < 2) || (objc > 4)) {
@ -2114,7 +2121,7 @@ _netcmp_compare(ClientData clientData,
int fnum1, fnum2, dolist = 0;
int dohierarchy = FALSE;
int assignonly = FALSE;
int argstart = 1, qresult, llen, result;
int argstart = 1, qresult, result;
int hascontents1, hascontents2;
struct Correspond *nextcomp;
struct nlist *tp1 = NULL, *tp2 = NULL;
@ -2828,7 +2835,7 @@ _netcmp_global(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
char *filename, *cellname, *pattern;
int numchanged = 0, p, fnum, llen, result;
int numchanged = 0, p, fnum, result;
struct nlist *tp;
if (objc < 2) {
@ -2925,7 +2932,8 @@ _netcmp_equate(ClientData clientData,
struct ElementClass *saveEclass = NULL;
struct NodeClass *saveNclass = NULL;
int file1, file2;
int i, l1, l2, ltest, lent, dolist = 0, doforce = 0, dounique = 0;
int i, dolist = 0, doforce = 0, dounique = 0;
Tcl_Size l1, l2, lent, ltest;
Tcl_Obj *tobj1, *tobj2, *tobj3;
while (objc > 1) {
@ -3426,10 +3434,11 @@ int
_netcmp_property(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
int fnum, i, llen;
int fnum, i;
struct nlist *tp;
struct property *kl, *kllast, *klnext;
Tcl_Obj *tobj1, *tobj2, *tobj3;
Tcl_Size llen;
double dval;
int ival, argstart;
@ -4485,14 +4494,14 @@ void tcl_vprintf(FILE *f, const char *fmt, va_list args_in)
void tcl_stdflush(FILE *f)
{
Tcl_SavedResult state;
Tcl_InterpState state;
static char stdstr[] = "::flush stdxxx";
char *stdptr = stdstr + 11;
Tcl_SaveResult(netgeninterp, &state);
state = Tcl_SaveInterpState(netgeninterp, TCL_OK);
strcpy(stdptr, (f == stderr) ? "err" : "out");
Tcl_Eval(netgeninterp, stdstr);
Tcl_RestoreResult(netgeninterp, &state);
Tcl_RestoreInterpState(netgeninterp, state);
}
/*------------------------------------------------------*/
@ -4561,7 +4570,7 @@ int Tclnetgen_Init(Tcl_Interp *interp)
/* Remember the interpreter */
netgeninterp = interp;
if (Tcl_InitStubs(interp, "8.5", 0) == NULL) return TCL_ERROR;
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) return TCL_ERROR;
for (n = 0; netgen_cmds[n].name != NULL; n++) {
sprintf(keyword, "netgen::%s", netgen_cmds[n].name);