Compare commits
144 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
e1528a797c | |
|
|
2c94087510 | |
|
|
3eadc8b0dc | |
|
|
9630670071 | |
|
|
f29452e550 | |
|
|
8a2bbe0723 | |
|
|
a0c49a026a | |
|
|
665203bba1 | |
|
|
0192558d4b | |
|
|
21d329b22d | |
|
|
37b1a2a07d | |
|
|
777f7ef095 | |
|
|
9b4185fe62 | |
|
|
ddd95c4fe6 | |
|
|
c0c9993980 | |
|
|
8a20b90074 | |
|
|
3392159243 | |
|
|
24c6eb4cb9 | |
|
|
9048191486 | |
|
|
72d7d55bbe | |
|
|
04163aedcc | |
|
|
f7d35f9cca | |
|
|
601277e539 | |
|
|
73344329f8 | |
|
|
08485d28a7 | |
|
|
2ee286efb4 | |
|
|
dae6919d4f | |
|
|
017bdc6e48 | |
|
|
b371af9235 | |
|
|
b5432d139b | |
|
|
0e958bd45c | |
|
|
b59196fa81 | |
|
|
6e6e9fb73f | |
|
|
e84700a607 | |
|
|
0bee21ccc8 | |
|
|
c269f1de89 | |
|
|
4443826f9e | |
|
|
a60dac6124 | |
|
|
bbe645f0ab | |
|
|
4f315d33d6 | |
|
|
4457248ecd | |
|
|
021dfa6e8a | |
|
|
1d286f9973 | |
|
|
6d2ef396ef | |
|
|
2483b7440f | |
|
|
49c0de0433 | |
|
|
3b9dca0cf2 | |
|
|
7d910b616c | |
|
|
b1032f846b | |
|
|
4c546d1472 | |
|
|
e1aa231db1 | |
|
|
df8fa29b2f | |
|
|
d14bf70f1c | |
|
|
5c21000a8b | |
|
|
05872ca918 | |
|
|
e821381900 | |
|
|
8022e1370f | |
|
|
2b88d79adc | |
|
|
bf4112db07 | |
|
|
fcee934580 | |
|
|
2d427aef3c | |
|
|
fd0c8c87ea | |
|
|
3d180f778d | |
|
|
035fef5c72 | |
|
|
202ea0431f | |
|
|
94754dbc4e | |
|
|
bf67d3c275 | |
|
|
62feed812e | |
|
|
d1c2848e4b | |
|
|
6b0bd4d97b | |
|
|
d69fbc23bb | |
|
|
c7fa0324d9 | |
|
|
eb27a18ae3 | |
|
|
1817f4dd6a | |
|
|
a7e859fcde | |
|
|
6d23844483 | |
|
|
cc84364263 | |
|
|
00b906c109 | |
|
|
25a0e12428 | |
|
|
eabb898578 | |
|
|
ec0e097fcf | |
|
|
f59c9ebcb7 | |
|
|
ce097d5d76 | |
|
|
619409556c | |
|
|
b1374e2bc8 | |
|
|
cff954f36a | |
|
|
c27d933adc | |
|
|
615c55cbe2 | |
|
|
87d8759a69 | |
|
|
1efa054ac1 | |
|
|
609d1de250 | |
|
|
47c3b34612 | |
|
|
66317c9848 | |
|
|
eeb3c0e5c6 | |
|
|
490f9f7dbc | |
|
|
40cf82c2cb | |
|
|
1ac2b592fb | |
|
|
e12883037c | |
|
|
2d63fd63c1 | |
|
|
e557e61a02 | |
|
|
67da250615 | |
|
|
cd013621a7 | |
|
|
45712a04f1 | |
|
|
28a2950439 | |
|
|
013fff9f37 | |
|
|
2292ab813b | |
|
|
7e8508db53 | |
|
|
c9f7b24e0f | |
|
|
95605ebbd4 | |
|
|
98e6a4bd8f | |
|
|
c73d9ec4ff | |
|
|
a5375177c5 | |
|
|
27b095754e | |
|
|
db457c562b | |
|
|
06386bee1b | |
|
|
7cd8d82964 | |
|
|
3aeea9d164 | |
|
|
12e1ff295f | |
|
|
2f9e898ec6 | |
|
|
9663579dd0 | |
|
|
f02e2b1ee0 | |
|
|
cc5f6d929f | |
|
|
4fa4d046c8 | |
|
|
9297090dc1 | |
|
|
79e193e0c9 | |
|
|
2056b37c95 | |
|
|
7550ef9258 | |
|
|
a795981eff | |
|
|
1b6e4e2b36 | |
|
|
edbe5d6e86 | |
|
|
f8ed4e42e2 | |
|
|
89ef83c597 | |
|
|
4e96c84ec6 | |
|
|
592c16706e | |
|
|
bfb01e032f | |
|
|
d0ec17e442 | |
|
|
6195745b45 | |
|
|
68ec2b2a7c | |
|
|
ca49a90ed6 | |
|
|
e07a5b416a | |
|
|
8094740048 | |
|
|
a026d37f11 | |
|
|
ab614b63f7 | |
|
|
83dce151d8 |
|
|
@ -7,6 +7,7 @@ config.log
|
|||
scripts/config.log
|
||||
config.status
|
||||
scripts/config.status
|
||||
python/lvs_manager.py
|
||||
*.o
|
||||
*.so
|
||||
*~
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <strings.h>
|
||||
#include <ctype.h>
|
||||
#ifdef IBMPC
|
||||
#include <stdlib.h> /* for strtol on PC */
|
||||
|
|
@ -90,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)
|
||||
|
|
@ -101,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]);
|
||||
|
|
@ -131,7 +132,7 @@ if format = 1, use the actel .pin file format
|
|||
struct nlist *tp;
|
||||
struct objlist *ob, *ob2;
|
||||
char *ptr;
|
||||
char physicalpin[200];
|
||||
char physicalpin[MAX_STR_LEN];
|
||||
|
||||
tp = LookupCell(name);
|
||||
if (tp == NULL) return;
|
||||
|
|
|
|||
|
|
@ -176,4 +176,6 @@ extern int open(char *path, int oflag, ...); /* HPUX has it in <sys/fcntl.h> */
|
|||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define MAX_STR_LEN 256
|
||||
|
||||
#endif /* _CONFIG_H */
|
||||
|
|
|
|||
|
|
@ -629,7 +629,7 @@ struct embed *FlattenEmbeddingTree(struct embed *E)
|
|||
int LenEmbed(char *prefix, struct nlist *np, struct embed *E, int flatten)
|
||||
/* return the number of characters required to print element E */
|
||||
{
|
||||
char longstr[200];
|
||||
char longstr[MAX_STR_LEN];
|
||||
|
||||
if (E == NULL) return(0);
|
||||
if (E->left == NULL && E->right == NULL) {
|
||||
|
|
@ -668,7 +668,7 @@ void PrintEmb(FILE *outfile, char *prefix, struct nlist *np,
|
|||
struct objlist *ob;
|
||||
char *instancename;
|
||||
struct nlist *np2;
|
||||
char name[200];
|
||||
char name[MAX_STR_LEN];
|
||||
|
||||
ob = InstanceNumber(np,E->instancenumber);
|
||||
instancename = ob->instance.name;
|
||||
|
|
@ -706,7 +706,7 @@ void PrintEmbed(FILE *outfile, char *prefix, struct nlist *np,
|
|||
struct objlist *ob;
|
||||
char *instancename;
|
||||
struct nlist *np2;
|
||||
char name[200];
|
||||
char name[MAX_STR_LEN];
|
||||
|
||||
ob = InstanceNumber(np,E->instancenumber);
|
||||
instancename = ob->instance.name;
|
||||
|
|
|
|||
351
base/ext.c
351
base/ext.c
|
|
@ -31,6 +31,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
#include "print.h"
|
||||
#include "hash.h"
|
||||
|
||||
static int invlambda = 100; /* Used in sim and prm files */
|
||||
|
||||
void extCell(char *name, int filenum)
|
||||
{
|
||||
struct nlist *tp, *tp2;
|
||||
|
|
@ -167,7 +169,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
|||
int filenum;
|
||||
|
||||
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
|
||||
char name[100];
|
||||
char name[MAX_STR_LEN];
|
||||
|
||||
SetExtension(name, fname, EXT_EXTENSION);
|
||||
if ((filenum = OpenParseFile(name, *fnum)) < 0) {
|
||||
|
|
@ -208,7 +210,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
|||
else if (match(nexttok, "style")) SkipNewLine(NULL);
|
||||
else if (match(nexttok, "resistclasses")) SkipNewLine(NULL);
|
||||
else if (match(nexttok, "node")) {
|
||||
char name[200];
|
||||
char name[MAX_STR_LEN];
|
||||
|
||||
/* No cell is generated until at least one valid "node" or "use" */
|
||||
/* has been read in the file. */
|
||||
|
|
@ -223,8 +225,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
|||
SkipNewLine(NULL);
|
||||
}
|
||||
else if (match(nexttok, "equiv")) {
|
||||
char name[200];
|
||||
char name2[200];
|
||||
char name[MAX_STR_LEN];
|
||||
char name2[MAX_STR_LEN];
|
||||
SkipTok(NULL);
|
||||
GetExtName(name, nexttok);
|
||||
if (LookupObject(name,CurrentCell) == NULL) Node(name);
|
||||
|
|
@ -235,8 +237,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
|||
SkipNewLine(NULL);
|
||||
}
|
||||
else if (match(nexttok, "device")) {
|
||||
char dev_name[100], dev_class[100];
|
||||
char gate[200], drain[200], source[200], subs[200];
|
||||
char dev_name[MAX_STR_LEN], dev_class[MAX_STR_LEN];
|
||||
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN], subs[MAX_STR_LEN];
|
||||
char inststr[64];
|
||||
SkipTok(NULL);
|
||||
strcpy(dev_class, nexttok);
|
||||
|
|
@ -306,8 +308,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
|||
SkipNewLine(NULL);
|
||||
}
|
||||
else if (match(nexttok, "fet")) { /* old-style FET record */
|
||||
char fet_class[100];
|
||||
char gate[200], drain[200], source[200], subs[200];
|
||||
char fet_class[MAX_STR_LEN];
|
||||
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN], subs[MAX_STR_LEN];
|
||||
char inststr[64];
|
||||
SkipTok(NULL);
|
||||
strcpy(fet_class, nexttok);
|
||||
|
|
@ -365,7 +367,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
|||
SkipNewLine(NULL);
|
||||
}
|
||||
else {
|
||||
char ctop[200], cbot[200], cdummy[200];
|
||||
char ctop[MAX_STR_LEN], cbot[MAX_STR_LEN], cdummy[MAX_STR_LEN];
|
||||
SkipTok(NULL);
|
||||
GetExtName(ctop, nexttok);
|
||||
SkipTok(NULL);
|
||||
|
|
@ -375,8 +377,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
|||
}
|
||||
}
|
||||
else if (match(nexttok, "use")) {
|
||||
char name[200];
|
||||
char instancename[200];
|
||||
char name[MAX_STR_LEN];
|
||||
char instancename[MAX_STR_LEN];
|
||||
char *basename;
|
||||
|
||||
/* No cell is generated until at least one valid "node" or "use" */
|
||||
|
|
@ -390,7 +392,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
|||
SkipTok(NULL);
|
||||
GetExtName(name, nexttok);
|
||||
if ((basename = strrchr(name,'/')) != NULL) {
|
||||
char tmp[200];
|
||||
char tmp[MAX_STR_LEN];
|
||||
strcpy(tmp, basename+1);
|
||||
strcpy(name, tmp);
|
||||
}
|
||||
|
|
@ -405,8 +407,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
|||
SkipNewLine(NULL);
|
||||
}
|
||||
else if (match(nexttok, "merge")) {
|
||||
char name[200];
|
||||
char name2[200];
|
||||
char name[MAX_STR_LEN];
|
||||
char name2[MAX_STR_LEN];
|
||||
SkipTok(NULL);
|
||||
GetExtName(name, nexttok);
|
||||
SkipTok(NULL);
|
||||
|
|
@ -450,7 +452,8 @@ void simCell(char *name, int filenum)
|
|||
struct nlist *tp, *tp2;
|
||||
struct objlist *ob, *ob2;
|
||||
char FileName[500], simclass;
|
||||
short i;
|
||||
char writeLine[1024], paramString[128];
|
||||
short i, p, mult;
|
||||
double l, w, v;
|
||||
|
||||
tp = LookupCellFile(name, filenum);
|
||||
|
|
@ -478,9 +481,9 @@ void simCell(char *name, int filenum)
|
|||
}
|
||||
|
||||
/* print out header list */
|
||||
/* distance units are multiplied by 100 (distances are in um) */
|
||||
/* distance units are multiplied by invlambda */
|
||||
|
||||
FlushString("| units: 100 tech: scmos\n");
|
||||
FlushString("| units: %d tech: scmos\n", 100 * invlambda);
|
||||
|
||||
/* now run through cell's contents, print instances */
|
||||
for (ob = tp->cell; ob != NULL; ob = ob->next) {
|
||||
|
|
@ -516,13 +519,17 @@ void simCell(char *name, int filenum)
|
|||
case CLASS_NPN:
|
||||
simclass = 'b';
|
||||
break;
|
||||
default:
|
||||
case CLASS_SUBCKT:
|
||||
case CLASS_MODULE:
|
||||
simclass = 'x';
|
||||
break;
|
||||
default:
|
||||
simclass = '|';
|
||||
break;
|
||||
}
|
||||
|
||||
if (simclass != 'x')
|
||||
FlushString("%c", simclass);
|
||||
FlushString("%c", simclass);
|
||||
|
||||
switch (tp2->class) {
|
||||
case CLASS_NMOS: case CLASS_NMOS4:
|
||||
|
|
@ -590,6 +597,115 @@ void simCell(char *name, int filenum)
|
|||
FlushString(" %g\n", v);
|
||||
break;
|
||||
|
||||
case CLASS_MODULE:
|
||||
*writeLine = 'x';
|
||||
*(writeLine + 1) = '\0';
|
||||
mult = 1;
|
||||
|
||||
/* Important---Need to look up the cell definition; if
|
||||
* the first pin is "drain" then it is a FET, and pins
|
||||
* get swapped from D-G-S-B to G-S-D-B. Source and drain
|
||||
* are treated here as equivalent because the .sim format
|
||||
* has no concept of an asymmetric source and drain.
|
||||
*/
|
||||
ob2 = tp2->cell;
|
||||
if ((*matchfunc)(ob2->next->name, "gate"))
|
||||
{
|
||||
strcat(writeLine, " ");
|
||||
strcat(writeLine, NodeAlias(tp, ob->next));
|
||||
strcat(writeLine, " ");
|
||||
strcat(writeLine, NodeAlias(tp, ob));
|
||||
ob2 = ob->next->next;
|
||||
}
|
||||
else
|
||||
ob2 = ob;
|
||||
|
||||
while (ob2 != NULL) {
|
||||
strcat(writeLine, " ");
|
||||
strcat(writeLine, NodeAlias(tp, ob2));
|
||||
ob2 = ob2->next;
|
||||
if ((ob2 == NULL) || (ob2->type <= FIRSTPIN)) break;
|
||||
}
|
||||
|
||||
if (ob2 && ob2->type == PROPERTY) {
|
||||
struct valuelist *vl;
|
||||
/* Only known parameters are L, W, X, and Y */
|
||||
for (p = 0;; p++) {
|
||||
vl = (struct valuelist *)(&(ob2->instance.props[p]));
|
||||
if (vl->type == PROP_ENDLIST) {
|
||||
strcat(writeLine, " l=1");
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(vl->key, "L")) {
|
||||
v = vl->value.dval;
|
||||
sprintf(paramString, " l=%d", (int)(0.5 + (v * invlambda)));
|
||||
strcat(writeLine, paramString);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (p = 0;; p++) {
|
||||
vl = (struct valuelist *)(&(ob2->instance.props[p]));
|
||||
if (vl->type == PROP_ENDLIST) {
|
||||
strcat(writeLine, " w=1");
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(vl->key, "W")) {
|
||||
v = vl->value.dval;
|
||||
sprintf(paramString, " w=%d", (int)(0.5 + (v * invlambda)));
|
||||
strcat(writeLine, paramString);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (p = 0;; p++) {
|
||||
vl = (struct valuelist *)(&(ob2->instance.props[p]));
|
||||
if (vl->type == PROP_ENDLIST) {
|
||||
strcat(writeLine, " x=0");
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(vl->key, "X")) {
|
||||
i = vl->value.ival;
|
||||
sprintf(paramString, " x=%d", i);
|
||||
strcat(writeLine, paramString);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (p = 0;; p++) {
|
||||
vl = (struct valuelist *)(&(ob2->instance.props[p]));
|
||||
if (vl->type == PROP_ENDLIST) {
|
||||
strcat(writeLine, " y=0");
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(vl->key, "Y")) {
|
||||
i = vl->value.ival;
|
||||
sprintf(paramString, " y=%d", i);
|
||||
strcat(writeLine, paramString);
|
||||
}
|
||||
}
|
||||
for (p = 0;; p++) {
|
||||
vl = (struct valuelist *)(&(ob2->instance.props[p]));
|
||||
if (vl->type == PROP_ENDLIST) {
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(vl->key, "M")) {
|
||||
if (vl->type == PROP_INTEGER)
|
||||
mult = vl->value.ival;
|
||||
else
|
||||
mult = vl->value.dval;
|
||||
}
|
||||
}
|
||||
}
|
||||
strcat(writeLine, " ");
|
||||
strcat(writeLine, tp2->name);
|
||||
strcat(writeLine, "\n");
|
||||
|
||||
/* Multiple instances (M != 1) are written multiple times.
|
||||
* NF is ignored in favor of having a single device with
|
||||
* the total width.
|
||||
*/
|
||||
for (i = 0; i < mult; i++)
|
||||
FlushString(writeLine);
|
||||
break;
|
||||
|
||||
default:
|
||||
FlushString("| unhandled component %s\n", tp2->name);
|
||||
break;
|
||||
|
|
@ -626,6 +742,181 @@ int StrIsInt(char *s)
|
|||
return (1);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Read a .prm format file. This is specifically to */
|
||||
/* get the "device" lines that indicate how a SPICE */
|
||||
/* subcircuit model or a .sim "x" record needs to be */
|
||||
/* translated into a specific component type like a */
|
||||
/* FET, diode, resistor, etc. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
char *ReadPrm(char *fname, int *fnum)
|
||||
{
|
||||
int filenum;
|
||||
struct keyvalue *kvlist = NULL;
|
||||
struct nlist *tp;
|
||||
|
||||
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
|
||||
char name[MAX_STR_LEN];
|
||||
|
||||
SetExtension(name, fname, PRM_EXTENSION);
|
||||
if (OpenParseFile(name, *fnum) < 0) {
|
||||
Printf("Error in prm file read: No file %s\n",name);
|
||||
*fnum = filenum;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure all .prm file reading is case INsensitive */
|
||||
/* This is because the only reason to read a PRM file */
|
||||
/* is to find all the subcircuit device types so that */
|
||||
/* a SPICE file can be read and a SIM file written. */
|
||||
|
||||
matchfunc = matchnocase;
|
||||
matchintfunc = matchfile;
|
||||
hashfunc = hashnocase;
|
||||
|
||||
CellDef(fname, filenum);
|
||||
|
||||
while (!EndParseFile()) {
|
||||
char devicename[MAX_STR_LEN];
|
||||
SkipTok(NULL);
|
||||
|
||||
if (EndParseFile()) break;
|
||||
if (nexttok[0] == ';') continue; /* Comment line */
|
||||
else if (nexttok[0] == '\0') continue; /* Blank line */
|
||||
else if (match(nexttok, "lambda")) {
|
||||
SkipTok(NULL);
|
||||
invlambda = (int)(0.5 + (1.0 / atof(nexttok)));
|
||||
SkipNewLine(NULL); /* skip any attributes */
|
||||
}
|
||||
else if (match(nexttok, "device")) {
|
||||
SkipTok(NULL);
|
||||
if (match(nexttok, "nfet")) {
|
||||
SkipTok(NULL);
|
||||
strcpy(devicename, nexttok);
|
||||
/* Create 4-terminal nfet subcircuit device record */
|
||||
if (LookupCellFile(devicename, filenum) == NULL) {
|
||||
CellDef(devicename, filenum);
|
||||
Port("drain");
|
||||
Port("gate");
|
||||
Port("source");
|
||||
Port("bulk");
|
||||
PropertyDouble(devicename, filenum, "l", 0.01, 0.0);
|
||||
PropertyDouble(devicename, filenum, "w", 0.01, 0.0);
|
||||
PropertyInteger(devicename, filenum, "nf", 0, 1);
|
||||
PropertyInteger(devicename, filenum, "m", 0, 1);
|
||||
SetClass(CLASS_MODULE);
|
||||
EndCell();
|
||||
ReopenCellDef(fname, filenum);
|
||||
}
|
||||
LinkProperties(devicename, kvlist);
|
||||
SkipNewLine(NULL); /* skip any attributes */
|
||||
}
|
||||
else if (match(nexttok, "pfet")) {
|
||||
SkipTok(NULL);
|
||||
strcpy(devicename, nexttok);
|
||||
/* Create 4-terminal pfet subcircuit device record */
|
||||
if (LookupCellFile(devicename, filenum) == NULL) {
|
||||
CellDef(devicename, filenum);
|
||||
Port("drain");
|
||||
Port("gate");
|
||||
Port("source");
|
||||
Port("well");
|
||||
PropertyDouble(devicename, filenum, "l", 0.01, 0.0);
|
||||
PropertyDouble(devicename, filenum, "w", 0.01, 0.0);
|
||||
PropertyInteger(devicename, filenum, "nf", 0, 1);
|
||||
PropertyInteger(devicename, filenum, "m", 0, 1);
|
||||
SetClass(CLASS_MODULE);
|
||||
EndCell();
|
||||
ReopenCellDef(fname, filenum);
|
||||
}
|
||||
LinkProperties(devicename, kvlist);
|
||||
SkipNewLine(NULL); /* skip various attributes */
|
||||
}
|
||||
else if (match(nexttok, "resistor")) {
|
||||
SkipTok(NULL);
|
||||
strcpy(devicename, nexttok);
|
||||
/* Resistor device has additional record for the value */
|
||||
/* (Need to do something with this. . . ?) */
|
||||
SkipTok(NULL);
|
||||
/* Create resistor subcircuit device record */
|
||||
if (LookupCellFile(devicename, filenum) == NULL) {
|
||||
CellDef(devicename, filenum);
|
||||
Port("end_a");
|
||||
Port("end_b");
|
||||
PropertyDouble(devicename, filenum, "value", 0.01, 0.0);
|
||||
PropertyDouble(devicename, filenum, "l", 0.01, 0.0);
|
||||
PropertyDouble(devicename, filenum, "w", 0.01, 0.0);
|
||||
PropertyInteger(devicename, filenum, "m", 0, 1);
|
||||
SetClass(CLASS_MODULE);
|
||||
EndCell();
|
||||
ReopenCellDef(fname, filenum);
|
||||
}
|
||||
LinkProperties(devicename, kvlist);
|
||||
SkipNewLine(NULL); /* skip various attributes */
|
||||
}
|
||||
else if (match(nexttok, "capacitor")) {
|
||||
SkipTok(NULL);
|
||||
strcpy(devicename, nexttok);
|
||||
/* Capacitor device has additional record for the value */
|
||||
/* (Need to do something with this. . . ?) */
|
||||
SkipTok(NULL);
|
||||
/* Create capacitor subcircuit device record */
|
||||
if (LookupCellFile(devicename, filenum) == NULL) {
|
||||
CellDef(devicename, filenum);
|
||||
Port("top");
|
||||
Port("bottom");
|
||||
PropertyDouble(devicename, filenum, "value", 0.01, 0.0);
|
||||
PropertyDouble(devicename, filenum, "l", 0.01, 0.0);
|
||||
PropertyDouble(devicename, filenum, "w", 0.01, 0.0);
|
||||
PropertyInteger(devicename, filenum, "m", 0, 1);
|
||||
SetClass(CLASS_MODULE);
|
||||
EndCell();
|
||||
ReopenCellDef(fname, filenum); /* Reopen */
|
||||
}
|
||||
LinkProperties(devicename, kvlist);
|
||||
SkipNewLine(NULL);
|
||||
}
|
||||
else if (match(nexttok, "diode")) {
|
||||
SkipTok(NULL);
|
||||
strcpy(devicename, nexttok);
|
||||
/* Create diode subcircuit device record */
|
||||
if (LookupCellFile(devicename, filenum) == NULL) {
|
||||
CellDef(devicename, filenum);
|
||||
Port("anode");
|
||||
Port("cathode");
|
||||
PropertyInteger(devicename, filenum, "m", 0, 1);
|
||||
SetClass(CLASS_MODULE);
|
||||
EndCell();
|
||||
ReopenCellDef(fname, filenum); /* Reopen */
|
||||
}
|
||||
LinkProperties(devicename, kvlist);
|
||||
SkipNewLine(NULL);
|
||||
}
|
||||
else {
|
||||
Printf("Unknown device type in .prm: '%s'\n", nexttok);
|
||||
InputParseError(stderr);
|
||||
SkipNewLine(NULL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Could spell out all the keywords used in .prm files */
|
||||
/* but probably not worth the effort. */
|
||||
SkipNewLine(NULL);
|
||||
}
|
||||
DeleteProperties(&kvlist);
|
||||
}
|
||||
EndCell();
|
||||
CloseParseFile();
|
||||
|
||||
tp = LookupCellFile(fname, filenum);
|
||||
if (tp) tp->flags |= CELL_TOP;
|
||||
|
||||
*fnum = filenum;
|
||||
return fname;
|
||||
}
|
||||
|
||||
/*-------------------------*/
|
||||
/* Read a .sim format file */
|
||||
/*-------------------------*/
|
||||
|
|
@ -640,11 +931,11 @@ char *ReadSim(char *fname, int *fnum)
|
|||
double simscale = 1.0;
|
||||
|
||||
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
|
||||
char name[100];
|
||||
char name[MAX_STR_LEN];
|
||||
|
||||
SetExtension(name, fname, SIM_EXTENSION);
|
||||
if (OpenParseFile(name, *fnum) < 0) {
|
||||
Printf("Error in ext file read: No file %s\n",name);
|
||||
Printf("Error in sim file read: No file %s\n",name);
|
||||
*fnum = filenum;
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -670,7 +961,7 @@ char *ReadSim(char *fname, int *fnum)
|
|||
SkipNewLine(NULL);
|
||||
}
|
||||
else if (match(nexttok, "n")) {
|
||||
char gate[200], drain[200], source[200];
|
||||
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN];
|
||||
char inststr[25], *instptr = NULL;
|
||||
|
||||
SkipTok(NULL);
|
||||
|
|
@ -714,7 +1005,7 @@ char *ReadSim(char *fname, int *fnum)
|
|||
LinkProperties("n", kvlist);
|
||||
}
|
||||
else if (match(nexttok, "p")) {
|
||||
char gate[200], drain[200], source[200];
|
||||
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN];
|
||||
char inststr[25], *instptr = NULL;
|
||||
SkipTok(NULL);
|
||||
GetExtName(gate, nexttok);
|
||||
|
|
@ -754,7 +1045,7 @@ char *ReadSim(char *fname, int *fnum)
|
|||
LinkProperties("p", kvlist);
|
||||
}
|
||||
else if (match(nexttok, "e")) { /* 3-port capacitors (poly/poly2) */
|
||||
char gate[200], drain[200], source[200];
|
||||
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN];
|
||||
char inststr[25], *instptr = NULL;
|
||||
SkipTok(NULL);
|
||||
GetExtName(gate, nexttok);
|
||||
|
|
@ -788,7 +1079,7 @@ char *ReadSim(char *fname, int *fnum)
|
|||
E(fname, instptr, gate, drain, source);
|
||||
}
|
||||
else if (match(nexttok, "b")) { /* bipolars added by Tim 7/16/96 */
|
||||
char base[200], emitter[200], collector[200];
|
||||
char base[MAX_STR_LEN], emitter[MAX_STR_LEN], collector[MAX_STR_LEN];
|
||||
char inststr[25], *instptr = NULL;
|
||||
SkipTok(NULL);
|
||||
GetExtName(base, nexttok);
|
||||
|
|
@ -826,7 +1117,7 @@ char *ReadSim(char *fname, int *fnum)
|
|||
SkipNewLine(NULL);
|
||||
}
|
||||
else {
|
||||
char ctop[200], cbot[200], cdummy[200];
|
||||
char ctop[MAX_STR_LEN], cbot[MAX_STR_LEN], cdummy[MAX_STR_LEN];
|
||||
SkipTok(NULL);
|
||||
GetExtName(ctop, nexttok);
|
||||
if (LookupObject(ctop, CurrentCell) == NULL)
|
||||
|
|
@ -847,11 +1138,11 @@ char *ReadSim(char *fname, int *fnum)
|
|||
}
|
||||
else if (match(nexttok, "r")) { /* 2-port resistors */
|
||||
if (IgnoreRC) {
|
||||
/* ignore all capacitances */
|
||||
/* ignore all resistances */
|
||||
SkipNewLine(NULL);
|
||||
}
|
||||
else {
|
||||
char rtop[200], rbot[200];
|
||||
char rtop[MAX_STR_LEN], rbot[MAX_STR_LEN];
|
||||
SkipTok(NULL);
|
||||
GetExtName(rtop, nexttok);
|
||||
if (LookupObject(rtop, CurrentCell) == NULL)
|
||||
|
|
@ -875,7 +1166,7 @@ char *ReadSim(char *fname, int *fnum)
|
|||
SkipNewLine(NULL);
|
||||
}
|
||||
else {
|
||||
char rtop[200], rbot[200], rdummy[200];
|
||||
char rtop[MAX_STR_LEN], rbot[MAX_STR_LEN], rdummy[MAX_STR_LEN];
|
||||
char inststr[25], *instptr = NULL;
|
||||
SkipTok(NULL);
|
||||
GetExtName(rdummy, nexttok);
|
||||
|
|
@ -917,7 +1208,7 @@ char *ReadSim(char *fname, int *fnum)
|
|||
SkipNewLine(NULL);
|
||||
}
|
||||
else if (match(nexttok, "=")) {
|
||||
char node1[200], node2[200];
|
||||
char node1[MAX_STR_LEN], node2[MAX_STR_LEN];
|
||||
SkipTok(NULL);
|
||||
GetExtName(node1, nexttok);
|
||||
SkipTok(NULL);
|
||||
|
|
|
|||
512
base/flatten.c
512
base/flatten.c
|
|
@ -53,7 +53,7 @@ void flattenCell(char *name, int file)
|
|||
struct nlist *ChildCell;
|
||||
struct objlist *tmp, *ob2, *ob3;
|
||||
int notdone, rnodenum;
|
||||
char tmpstr[200];
|
||||
char tmpstr[MAX_STR_LEN];
|
||||
int nextnode, oldmax;
|
||||
#if !OLDPREFIX
|
||||
int prefixlength;
|
||||
|
|
@ -66,9 +66,13 @@ void flattenCell(char *name, int file)
|
|||
else
|
||||
ThisCell = LookupCellFile(name, file);
|
||||
if (ThisCell == NULL) {
|
||||
Printf("No cell %s found.\n", name);
|
||||
Printf("No cell %s (%d) found.\n", name, file);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Placeholder cells must not be flattened */
|
||||
if (ThisCell->flags & CELL_PLACEHOLDER) return;
|
||||
|
||||
FreeNodeNames(ThisCell);
|
||||
|
||||
ParentParams = ThisCell->cell;
|
||||
|
|
@ -132,17 +136,16 @@ void flattenCell(char *name, int file)
|
|||
ob2 = ob2->next;
|
||||
}
|
||||
|
||||
|
||||
/* delete all port elements from child */
|
||||
while (IsPort(ChildObjList)) {
|
||||
/* delete all ports at beginning of list */
|
||||
if (Debug) Printf("deleting leading port from child\n");
|
||||
tmp = ChildObjList->next;
|
||||
FreeObjectAndHash(ChildObjList, ChildCell);
|
||||
ChildObjList = tmp;
|
||||
if ((ChildObjList = tmp) == NULL) break;
|
||||
}
|
||||
tmp = ChildObjList;
|
||||
while (tmp->next != NULL) {
|
||||
while (tmp && (tmp->next != NULL)) {
|
||||
if (IsPort(tmp->next)) {
|
||||
ob2 = (tmp->next)->next;
|
||||
if (Debug) Printf("deleting a port from child\n");
|
||||
|
|
@ -239,6 +242,13 @@ void flattenCell(char *name, int file)
|
|||
ThisCell->dumped = 1; /* indicate cell has been flattened */
|
||||
}
|
||||
|
||||
/* Structure used to keep track of nodes needing checking */
|
||||
|
||||
struct linkednode {
|
||||
int node;
|
||||
struct linkednode *next;
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* flattenInstancesOf -- */
|
||||
/* */
|
||||
|
|
@ -261,6 +271,7 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
|||
struct nlist *ThisCell;
|
||||
struct nlist *ChildCell;
|
||||
struct objlist *tmp, *ob2, *ob3;
|
||||
struct linkednode *checknodes = NULL, *newlnode, *chknode;
|
||||
int notdone, rnodenum;
|
||||
char tmpstr[1024];
|
||||
int nextnode, oldmax, numflat = 0;
|
||||
|
|
@ -278,16 +289,18 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
|||
}
|
||||
else {
|
||||
if (Debug)
|
||||
Printf("Flattening instances of %s within cell: %s\n", instance, name);
|
||||
Printf("Flattening instances of %s within cell: %s (%d)\n", instance,
|
||||
name, fnum);
|
||||
if (fnum == -1)
|
||||
ThisCell = LookupCell(name);
|
||||
else
|
||||
ThisCell = LookupCellFile(name, fnum);
|
||||
if (ThisCell == NULL) {
|
||||
Printf("No cell %s found.\n", name);
|
||||
Printf("No cell %s (%d) found.\n", name, fnum);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
FreeNodeNames(ThisCell);
|
||||
|
||||
ParentParams = ThisCell->cell;
|
||||
|
|
@ -324,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
|
||||
|
|
@ -372,22 +389,16 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
|||
|
||||
/* update node numbers in child to unique numbers */
|
||||
oldmax = 0;
|
||||
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next)
|
||||
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) {
|
||||
if (tmp->node > oldmax) oldmax = tmp->node;
|
||||
if (nextnode <= oldmax) nextnode = oldmax + 1;
|
||||
|
||||
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next)
|
||||
if (tmp->node <= oldmax && tmp->node > 0) {
|
||||
if (Debug) Printf("Update node %d --> %d\n", tmp->node, nextnode);
|
||||
UpdateNodeNumbers(ChildStart, tmp->node, nextnode);
|
||||
nextnode++;
|
||||
}
|
||||
if (tmp->node > 0) tmp->node += (nextnode - 1);
|
||||
}
|
||||
nextnode += oldmax;
|
||||
|
||||
/* copy nodenumbers of ports from parent */
|
||||
ob2 = ParentParams;
|
||||
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) {
|
||||
if (IsPort(tmp)) {
|
||||
if (tmp->node > 0) {
|
||||
for (tmp = ChildStart; tmp && IsPort(tmp); tmp = tmp->next) {
|
||||
if (tmp->node > 0) {
|
||||
if (ob2->node == -1) {
|
||||
|
||||
// Before commiting to attaching to a unconnected node, see
|
||||
|
|
@ -413,17 +424,26 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
|||
Printf("Update node %d --> %d\n", tmp->node, ob2->node);
|
||||
}
|
||||
UpdateNodeNumbers(ChildStart, tmp->node, ob2->node);
|
||||
}
|
||||
}
|
||||
else if (tmp->node == -1) {
|
||||
/* Opposite case: If child port is an unconnected node, then */
|
||||
/* removing the instance may make the parent node become */
|
||||
/* unconnected. For now, just record the node number. At the */
|
||||
/* end we'll check if these nodes are actually disconnected. */
|
||||
newlnode = (struct linkednode *)MALLOC(sizeof(struct linkednode));
|
||||
newlnode->node = ob2->node;
|
||||
newlnode->next = checknodes;
|
||||
checknodes = newlnode;
|
||||
}
|
||||
|
||||
/* in pathological cases, the lengths of the port lists may
|
||||
* change. This is an error, but that is no reason to allow
|
||||
* the code to core dump. We avoid this by placing a
|
||||
* superfluous check on ob2->type
|
||||
*/
|
||||
if (ob2 != NULL) ob2 = ob2->next;
|
||||
/* in pathological cases, the lengths of the port lists may
|
||||
* change. This is an error, but that is no reason to allow
|
||||
* the code to core dump. We avoid this by placing a
|
||||
* superfluous check on ob2->type
|
||||
*/
|
||||
if (ob2 != NULL) ob2 = ob2->next;
|
||||
|
||||
if (ob2 == NULL) break;
|
||||
}
|
||||
if (ob2 == NULL) break;
|
||||
}
|
||||
|
||||
/* Using name == NULL to indicate that a .ext file is being */
|
||||
|
|
@ -517,11 +537,10 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
|||
|
||||
/* Do property inheritance */
|
||||
|
||||
/* NOTE: Need to do: Check properties for M > 1 and decrement
|
||||
* and repeat without moving CurrentProp
|
||||
*/
|
||||
|
||||
if (CurrentProp) {
|
||||
int i, mval;
|
||||
struct valuelist *kv;
|
||||
|
||||
for (ob2 = ChildStart; ob2 != NULL; ob2=ob2->next) {
|
||||
|
||||
/* If the parent cell has properties to declare, then */
|
||||
|
|
@ -529,10 +548,49 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
|||
/* spiceparams dictionary is active (during file */
|
||||
/* reading only). */
|
||||
|
||||
if (ob2->type == PROPERTY)
|
||||
if (ob2->type == PROPERTY) {
|
||||
ReduceExpressions(ob2, CurrentProp, ChildCell,
|
||||
(spiceparams.hashtab == NULL) ? 0 : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for property M. If it exists and is greater than */
|
||||
/* one, reduce it and repeat; i.e., generate multiple */
|
||||
/* child instances to match the M value. Probably this */
|
||||
/* could be done quicker by just creating a new property */
|
||||
/* M for a single child. */
|
||||
|
||||
mval = 0;
|
||||
for (i = 0; ; i++) {
|
||||
kv = &(CurrentProp->instance.props[i]);
|
||||
if (kv->type == PROP_ENDLIST) break;
|
||||
if ((*matchfunc)(kv->key, "M")) {
|
||||
if (kv->type == PROP_INTEGER) {
|
||||
mval = kv->value.ival;
|
||||
kv->value.ival = mval - 1;
|
||||
break;
|
||||
}
|
||||
else if (kv->type == PROP_DOUBLE) {
|
||||
mval = (int)kv->value.dval;
|
||||
kv->value.dval = (double)mval - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mval > 1) {
|
||||
/* Put the child cell at the start of ChildObjList */
|
||||
if (ChildEnd) {
|
||||
ChildEnd->next = ChildObjList;
|
||||
ChildObjList = ChildStart;
|
||||
|
||||
/* Continue without moving CurrentProp */
|
||||
/* Note that if ChildEnd is NULL then the child cell
|
||||
* is optimized out and there is no need to do it
|
||||
* M times.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Repeat for each property record, as each property represents a
|
||||
* unique instance that must be flattened individually.
|
||||
|
|
@ -544,8 +602,10 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
|||
else break;
|
||||
|
||||
/* Put the child cell at the start of ChildObjList */
|
||||
ChildEnd->next = ChildObjList;
|
||||
ChildObjList = ChildStart;
|
||||
if (ChildEnd) {
|
||||
ChildEnd->next = ChildObjList;
|
||||
ChildObjList = ChildStart;
|
||||
}
|
||||
}
|
||||
|
||||
/* Put the child cell at the start of ChildObjList */
|
||||
|
|
@ -597,6 +657,29 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
|||
NextObj = ParentParams;
|
||||
} /* repeat until no more instances found */
|
||||
}
|
||||
|
||||
/* Check nodes that may have become disconnected after child flattening */
|
||||
while (checknodes != NULL) {
|
||||
struct objlist *portnode = NULL;
|
||||
|
||||
chknode = checknodes;
|
||||
checknodes = checknodes->next;
|
||||
|
||||
for (ob3 = ThisCell->cell; ob3; ob3 = ob3->next) {
|
||||
if ((ob3->type != PORT) && (portnode == NULL))
|
||||
break;
|
||||
else if ((ob3->type == PORT) && (ob3->node == chknode->node))
|
||||
portnode = ob3;
|
||||
else if ((ob3->type >= FIRSTPIN) && (ob3->node == chknode->node))
|
||||
break;
|
||||
}
|
||||
if ((ob3 == NULL) && (portnode != NULL)) {
|
||||
/* Port became disconnected when child was flattened */
|
||||
portnode->node = -1;
|
||||
}
|
||||
FREE(chknode);
|
||||
}
|
||||
|
||||
CacheNodeNames(ThisCell);
|
||||
ThisCell->dumped = 1; /* indicate cell has been flattened */
|
||||
return numflat;
|
||||
|
|
@ -688,7 +771,7 @@ void convertGlobalsOf(char *name, int fnum, char *instance)
|
|||
else
|
||||
ThisCell = LookupCellFile(name, fnum);
|
||||
if (ThisCell == NULL) {
|
||||
Printf("No cell %s found.\n", name);
|
||||
Printf("No cell %s (%d) found.\n", name, fnum);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1118,7 +1201,7 @@ int UniquePins(char *name, int filenum)
|
|||
ThisCell = LookupCellFile(name, filenum);
|
||||
|
||||
if (ThisCell == NULL) {
|
||||
Printf("No cell %s found.\n", name);
|
||||
Printf("No cell %s (%d) found.\n", name, filenum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1140,7 +1223,27 @@ int UniquePins(char *name, int filenum)
|
|||
if (ob->node > 0) {
|
||||
nodecount[ob->node]++;
|
||||
if (nodecount[ob->node] == 2) {
|
||||
Printf("Duplicate pin %s in cell %s\n", ob->name, ThisCell->name);
|
||||
if (!(*matchfunc)(firstport[ob->node]->name, ob->name)) {
|
||||
Printf("Pins %s and %s are shorted in cell %s (%d)\n", ob->name,
|
||||
firstport[ob->node]->name, ThisCell->name, ThisCell->file);
|
||||
/* Do not count this as a duplicate pin. */
|
||||
nodecount[ob->node]--;
|
||||
/* Note: Previously there was code here to move the shorted port
|
||||
* next to the pin it is shorted to. This causes the cell def pins
|
||||
* to become scrambled with respect to the pin order of its instances.
|
||||
* Removed the code 9/1/2023. But---Not sure if any code depends
|
||||
* on shorted pins being adjacent.
|
||||
*/
|
||||
/* When two pins are shorted, they are by definition permutable */
|
||||
PermuteSetup(ThisCell->name, ThisCell->file, ob->name,
|
||||
firstport[ob->node]->name);
|
||||
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
Printf("Duplicate pin %s in cell %s (%d)\n", ob->name,
|
||||
ThisCell->name, filenum);
|
||||
}
|
||||
}
|
||||
if (nodecount[ob->node] > 1) {
|
||||
/* Remove this node; prep for removal by marking with UNKNOWN */
|
||||
|
|
@ -1205,6 +1308,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 */
|
||||
|
|
@ -1217,6 +1328,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;
|
||||
|
||||
|
|
@ -1272,6 +1384,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 {
|
||||
|
|
@ -1315,6 +1436,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 */
|
||||
}
|
||||
|
|
@ -1339,7 +1482,7 @@ int CleanupPins(char *name, int filenum)
|
|||
ThisCell = LookupCellFile(name, filenum);
|
||||
|
||||
if (ThisCell == NULL) {
|
||||
Printf("No cell %s found.\n", name);
|
||||
Printf("No cell %s (%d) found.\n", name, filenum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1421,11 +1564,27 @@ typedef struct ecomplist {
|
|||
ECompListPtr next;
|
||||
} ECompList;
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Determine if a cell contains at least one device or subcircuit */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
HasContents(struct nlist *tc)
|
||||
{
|
||||
struct objlist *ob;
|
||||
|
||||
for (ob = tc->cell; ob; ob = ob->next)
|
||||
if (ob->type == FIRSTPIN)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Survey the contents of a cell and sort into a hash */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
int
|
||||
void
|
||||
SurveyCell(struct nlist *tc, struct hashdict *compdict, int file1, int file2, int which)
|
||||
{
|
||||
struct objlist *ob;
|
||||
|
|
@ -1433,12 +1592,10 @@ SurveyCell(struct nlist *tc, struct hashdict *compdict, int file1, int file2, in
|
|||
ECompare *ecomp, *qcomp, *ncomp;
|
||||
int file = (which == 0) ? file1 : file2;
|
||||
int ofile = (which == 0) ? file2 : file1;
|
||||
int retval = FALSE;
|
||||
char *dstr;
|
||||
|
||||
for (ob = tc->cell; ob; ob = ob->next) {
|
||||
if (ob->type == FIRSTPIN) {
|
||||
retval = TRUE; /* Cell has at least one device or subcircuit */
|
||||
tsub = LookupCellFile(ob->model.class, file);
|
||||
if (tsub->flags & CELL_DUPLICATE) {
|
||||
// Always register a duplicate under the original name
|
||||
|
|
@ -1492,7 +1649,6 @@ SurveyCell(struct nlist *tc, struct hashdict *compdict, int file1, int file2, in
|
|||
if (dstr) *dstr = '[';
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
|
|
@ -1522,7 +1678,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
ECompare *ecomp, *ncomp;
|
||||
ECompList *list0X, *listX0;
|
||||
int hascontents1, hascontents2;
|
||||
int match, modified = 0;
|
||||
int match, modified1 = 0, modified2 = 0;
|
||||
int not_top;
|
||||
|
||||
if (file1 == -1)
|
||||
tc1 = LookupCell(name1);
|
||||
|
|
@ -1540,28 +1697,10 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
listX0 = list0X = NULL;
|
||||
|
||||
// Gather information about instances of cell "name1"
|
||||
hascontents1 = SurveyCell(tc1, &compdict, file1, file2, 0);
|
||||
SurveyCell(tc1, &compdict, file1, file2, 0);
|
||||
|
||||
// Gather information about instances of cell "name2"
|
||||
hascontents2 = SurveyCell(tc2, &compdict, file1, file2, 1);
|
||||
|
||||
// If one cell has no contents, then flattening the other
|
||||
// isn't going to improve anything, so stop here.
|
||||
|
||||
if (!hascontents1 && !hascontents2 && (tc1->flags & CELL_PLACEHOLDER)
|
||||
&& (tc2->flags & CELL_PLACEHOLDER)) {
|
||||
goto done;
|
||||
}
|
||||
else if (hascontents1 && !hascontents2 && (tc2->flags & CELL_PLACEHOLDER)) {
|
||||
Fprintf(stdout, "Circuit 2 cell %s is a black box; will not flatten "
|
||||
"Circuit 1\n", name2);
|
||||
goto done;
|
||||
}
|
||||
else if (hascontents2 && !hascontents1 && (tc1->flags & CELL_PLACEHOLDER)) {
|
||||
Fprintf(stdout, "Circuit 1 cell %s is a black box; will not flatten "
|
||||
"Circuit 2\n", name1);
|
||||
goto done;
|
||||
}
|
||||
SurveyCell(tc2, &compdict, file1, file2, 1);
|
||||
|
||||
// Find all instances of one cell that have fewer in
|
||||
// the compared circuit. Check whether subcircuits
|
||||
|
|
@ -1611,19 +1750,32 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
}
|
||||
}
|
||||
if (match) {
|
||||
if (ecomp->cell1 && (ecomp->num1 > 0)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
if (ecomp->cell1 && (ecomp->num1 > 0) &&
|
||||
(!(ecomp->cell1->flags & CELL_PLACEHOLDER))) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" makes a better match\n", ecomp->cell1->name,
|
||||
name1);
|
||||
flattenInstancesOf(name1, file1, ecomp->cell1->name);
|
||||
name1, file1);
|
||||
if (flattenInstancesOf(name1, file1, ecomp->cell1->name) > 0)
|
||||
modified1++;
|
||||
}
|
||||
if (ecomp->cell2 && (ecomp->num2 > 0)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
else if (ecomp->cell1 && (ecomp->num1 > 0)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" would make a better match but is prohibited.\n",
|
||||
ecomp->cell1->name, name1, file1);
|
||||
}
|
||||
if (ecomp->cell2 && (ecomp->num2 > 0) &&
|
||||
(!(ecomp->cell2->flags & CELL_PLACEHOLDER))) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" makes a better match\n", ecomp->cell2->name,
|
||||
name2);
|
||||
flattenInstancesOf(name2, file2, ecomp->cell2->name);
|
||||
name2, file2);
|
||||
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)"
|
||||
" would make a better match but is prohibited.\n",
|
||||
ecomp->cell2->name, name2, file2);
|
||||
}
|
||||
modified++;
|
||||
}
|
||||
|
||||
/* Reset or apply the count adjustments */
|
||||
|
|
@ -1700,13 +1852,26 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
}
|
||||
}
|
||||
if (match) {
|
||||
if (ecomp->cell2) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
|
||||
/* Don't flatten if cell1 is a black box, because it */
|
||||
/* can't also be flattened. */
|
||||
|
||||
if ((ecomp->num1 == 0) || (ecomp->cell1->class !=
|
||||
CLASS_MODULE)) {
|
||||
|
||||
if (ecomp->cell2 && !(ecomp->cell2->flags & CELL_PLACEHOLDER)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" makes a better match\n", ecomp->cell2->name,
|
||||
name2);
|
||||
flattenInstancesOf(name2, file2, ecomp->cell2->name);
|
||||
name2, file2);
|
||||
if (flattenInstancesOf(name2, file2, ecomp->cell2->name) > 0)
|
||||
modified2++;
|
||||
}
|
||||
else if (ecomp->cell2) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" would make a better match but is prohibited.\n",
|
||||
ecomp->cell2->name, name2, file2);
|
||||
}
|
||||
}
|
||||
modified++;
|
||||
}
|
||||
|
||||
/* Reset or apply the count adjustments */
|
||||
|
|
@ -1730,7 +1895,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
}
|
||||
|
||||
/* Case 3: Cell1 class is a subcircuit, and flattening */
|
||||
/* it (without regard to cell1) improves the matching. */
|
||||
/* it (without regard to cell2) improves the matching. */
|
||||
|
||||
else if ((ecomp->num1 != ecomp->num2) && (ecomp->cell1 != NULL) &&
|
||||
(ecomp->num1 != 0) && (ecomp->cell1->class == CLASS_SUBCKT)) {
|
||||
|
|
@ -1758,13 +1923,26 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
}
|
||||
}
|
||||
if (match) {
|
||||
if (ecomp->cell1) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
|
||||
/* Don't flatten if cell2 is a black box, because it */
|
||||
/* can't also be flattened. */
|
||||
|
||||
if ((ecomp->num2 == 0) || (ecomp->cell2->class !=
|
||||
CLASS_MODULE)) {
|
||||
|
||||
if (ecomp->cell1 && !(ecomp->cell1->flags & CELL_PLACEHOLDER)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" makes a better match\n", ecomp->cell1->name,
|
||||
name1);
|
||||
flattenInstancesOf(name1, file1, ecomp->cell1->name);
|
||||
name1, file1);
|
||||
if (flattenInstancesOf(name1, file1, ecomp->cell1->name) > 0)
|
||||
modified1++;
|
||||
}
|
||||
else if (ecomp->cell1) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" would make a better match but is prohibited.\n",
|
||||
ecomp->cell1->name, name1, file1);
|
||||
}
|
||||
}
|
||||
modified++;
|
||||
}
|
||||
|
||||
/* Reset or apply the count adjustments */
|
||||
|
|
@ -1792,6 +1970,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
// Remove non-matching zero-value devices. This can
|
||||
// be done on a per-instance basis.
|
||||
|
||||
not_top = (PeekCompareQueueTop(NULL, NULL, NULL, NULL) == -1) ? FALSE : TRUE;
|
||||
|
||||
ecomp = (ECompare *)HashFirst(&compdict);
|
||||
while (ecomp != NULL) {
|
||||
if ((ecomp->num1 != ecomp->num2) && (ecomp->cell1 != NULL) &&
|
||||
|
|
@ -1840,17 +2020,65 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
}
|
||||
if (found) break;
|
||||
}
|
||||
|
||||
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 */
|
||||
/* cells to be declared mismatched. */
|
||||
/* 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)) {
|
||||
int found1 = FALSE;
|
||||
int found2 = FALSE;
|
||||
for (ob2 = tc1->cell; ob2; ob2 = ob2->next) {
|
||||
if (!IsPort(ob2)) break;
|
||||
else if (ob2->node == node1)
|
||||
found1 = TRUE;
|
||||
else if (ob2->node == node2)
|
||||
found2 = TRUE;
|
||||
if (found1 && found2) {
|
||||
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) {
|
||||
Fprintf(stdout, "Removing zero-valued device "
|
||||
"%s from cell %s makes a better match\n",
|
||||
tsub1->name,
|
||||
tc1->name);
|
||||
"%s from cell %s (%d) makes a better "
|
||||
"match\n",
|
||||
tsub1->name, tc1->name, tc1->file);
|
||||
|
||||
/* A current source is an open, while a */
|
||||
/* resistor or voltage source is a short. */
|
||||
|
||||
if (ecomp->cell1->class != CLASS_ISOURCE) {
|
||||
/* merge node of endpoints */
|
||||
/* Prefer a port node over a non-port node */
|
||||
for (ob2 = tc1->cell; ob2; ob2 = ob2->next) {
|
||||
if (!IsPort(ob2)) break;
|
||||
else if (ob2->node == node1) break;
|
||||
else if (ob2->node == node2) {
|
||||
int ntemp = node1;
|
||||
node1 = node2;
|
||||
node2 = ntemp;
|
||||
}
|
||||
}
|
||||
for (ob2 = tc1->cell; ob2; ob2 = ob2->next) {
|
||||
if (ob2->node == node2)
|
||||
ob2->node = node1;
|
||||
|
|
@ -1877,7 +2105,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
|
||||
/* Remove from list */
|
||||
ecomp->num1--;
|
||||
modified++;
|
||||
modified1++;
|
||||
|
||||
ob1 = lob;
|
||||
}
|
||||
|
|
@ -1949,16 +2177,47 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* (See comments above about removing shorts */
|
||||
/* between two ports.) */
|
||||
|
||||
if ((not_top == TRUE) &&
|
||||
(ecomp->cell2->class != CLASS_ISOURCE)) {
|
||||
int found1 = FALSE;
|
||||
int found2 = FALSE;
|
||||
for (ob1 = tc2->cell; ob1; ob1 = ob1->next) {
|
||||
if (!IsPort(ob1)) break;
|
||||
else if (ob1->node == node1)
|
||||
found1 = TRUE;
|
||||
else if (ob1->node == node2)
|
||||
found2 = TRUE;
|
||||
if (found1 && found2) {
|
||||
found = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found) break;
|
||||
}
|
||||
if (found) {
|
||||
Fprintf(stdout, "Removing zero-valued device "
|
||||
"%s from cell %s makes a better match\n",
|
||||
tsub2->name,
|
||||
tc2->name);
|
||||
"%s from cell %s (%d) makes a better "
|
||||
"match\n",
|
||||
tsub2->name, tc2->name, tc2->file);
|
||||
|
||||
/* merge node of endpoints */
|
||||
if (ecomp->cell2->class != CLASS_ISOURCE) {
|
||||
/* Prefer a port node over a non-port node */
|
||||
for (ob1 = tc2->cell; ob1; ob1 = ob1->next) {
|
||||
if (!IsPort(ob1)) break;
|
||||
else if (ob1->node == node1) break;
|
||||
else if (ob1->node == node2) {
|
||||
int ntemp = node1;
|
||||
node1 = node2;
|
||||
node2 = ntemp;
|
||||
}
|
||||
}
|
||||
for (ob1 = tc2->cell; ob1; ob1 = ob1->next) {
|
||||
if (ob1->node == node2)
|
||||
ob1->node = node1;
|
||||
|
|
@ -1984,8 +2243,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
}
|
||||
|
||||
/* Remove from list */
|
||||
ecomp->num1--;
|
||||
modified++;
|
||||
ecomp->num2--;
|
||||
modified2++;
|
||||
|
||||
ob2 = lob;
|
||||
}
|
||||
|
|
@ -2019,7 +2278,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
// are no other modifications, as this rule is relaxed compared to other
|
||||
// rules, and the other rules should be exhaustively applied first.
|
||||
|
||||
if ((listX0 != NULL) && (list0X != NULL) && (modified == 0)) {
|
||||
if ((listX0 != NULL) && (list0X != NULL) && ((modified1 + modified2) == 0)) {
|
||||
ECompare *ecomp0X, *ecompX0;
|
||||
ECompList *elist0X, *elistX0;
|
||||
for (elistX0 = listX0; elistX0; elistX0 = elistX0->next) {
|
||||
|
|
@ -2045,13 +2304,24 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
ecompX0->cell1->file, &compdict);
|
||||
if (dstr) *dstr = '[';
|
||||
if ((ncomp == ecomp0X) && (ecomp0X->num2 <= ecompX0->num1)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
" makes a better match\n", ecompX0->cell1->name,
|
||||
name1);
|
||||
flattenInstancesOf(name1, file1, ecompX0->cell1->name);
|
||||
ecompX0->num1 = 0;
|
||||
ecomp0X->num1 += ecompX0->num1;
|
||||
modified++;
|
||||
if (!(ecompX0->cell1->flags & CELL_PLACEHOLDER)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell"
|
||||
" %s (%d) makes a better match\n",
|
||||
ecompX0->cell1->name, name1, file1);
|
||||
if (flattenInstancesOf(name1, file1,
|
||||
ecompX0->cell1->name) > 0) {
|
||||
ecompX0->num1 = 0;
|
||||
ecomp0X->num1 += ecompX0->num1;
|
||||
modified1++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Fprintf(stdout, "Flattening instances of %s in "
|
||||
"cell %s (%d) would make a better "
|
||||
"match but is prohibited.\n",
|
||||
ecompX0->cell1->name, name1, file1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -2071,13 +2341,23 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
ecomp0X->cell2->file, &compdict);
|
||||
if (dstr) *dstr = '[';
|
||||
if ((ncomp == ecompX0) && (ecompX0->num1 <= ecomp0X->num2)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
" makes a better match\n", ecomp0X->cell2->name,
|
||||
name2);
|
||||
flattenInstancesOf(name2, file2, ecomp0X->cell2->name);
|
||||
ecomp0X->num2 = 0;
|
||||
ecompX0->num2 += ecomp0X->num2;
|
||||
modified++;
|
||||
if (!(ecomp0X->cell2->flags & CELL_PLACEHOLDER)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell"
|
||||
" %s (%d) makes a better match\n",
|
||||
ecomp0X->cell2->name, name2, file2);
|
||||
if (flattenInstancesOf(name2, file2,
|
||||
ecomp0X->cell2->name) > 0) {
|
||||
ecomp0X->num2 = 0;
|
||||
ecompX0->num2 += ecomp0X->num2;
|
||||
modified2++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Fprintf(stdout, "Flattening instances of %s in "
|
||||
"cell %s (%d) would make a better "
|
||||
"match but is prohibited.\n",
|
||||
ecompX0->cell2->name, name2, file2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -2108,5 +2388,17 @@ done:
|
|||
FREE(list0X);
|
||||
list0X = nextptr;
|
||||
}
|
||||
return modified;
|
||||
|
||||
// If either netlist was modified, rebuild its node cache
|
||||
|
||||
if (modified1 > 0) {
|
||||
FreeNodeNames(tc1);
|
||||
CacheNodeNames(tc1);
|
||||
}
|
||||
if (modified2 > 0) {
|
||||
FreeNodeNames(tc2);
|
||||
CacheNodeNames(tc2);
|
||||
}
|
||||
|
||||
return modified1 + modified2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,5 +3,6 @@
|
|||
|
||||
extern int UniquePins(char *name, int filenum);
|
||||
extern void flattenCell(char *name, int file);
|
||||
extern int HasContents(struct nlist *);
|
||||
|
||||
#endif /* _FLATTEN_H */
|
||||
|
|
|
|||
33
base/hash.c
33
base/hash.c
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ along with this program; see the file copying. If not, write to
|
|||
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* inetcomp.c -- a simple wrapper to the NETCOMP() function */
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "netgen.h"
|
||||
|
|
@ -33,7 +34,7 @@ void STRCPY(char *dest, char *source)
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char cell1[200], cell2[200];
|
||||
char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
|
||||
|
||||
Debug = 0;
|
||||
if (argc != 1) {
|
||||
|
|
|
|||
1826
base/netcmp.c
1826
base/netcmp.c
File diff suppressed because it is too large
Load Diff
|
|
@ -7,6 +7,7 @@ extern struct nlist *Circuit1;
|
|||
extern struct nlist *Circuit2;
|
||||
|
||||
extern int ExhaustiveSubdivision;
|
||||
extern int ExactTopology;
|
||||
|
||||
extern int left_col_end;
|
||||
extern int right_col_end;
|
||||
|
|
@ -26,6 +27,7 @@ extern void PrintCoreStats(void);
|
|||
extern void ResetState(void);
|
||||
extern void CreateTwoLists(char *name1, int file1, char *name2, int file2,
|
||||
int dolist);
|
||||
extern void DescribeContents(char *name1, int file1, char *name2, int file2);
|
||||
extern int Iterate(void);
|
||||
extern int VerifyMatching(void);
|
||||
extern void PrintAutomorphisms(void);
|
||||
|
|
@ -36,7 +38,8 @@ extern int PermuteSetup(char *model, int filenum, char *pin1, char *pin2);
|
|||
extern int PermuteForget(char *model, int filenum, char *pin1, char *pin2);
|
||||
extern int EquivalenceElements(char *name1, int file1, char *name2, int file2);
|
||||
extern int EquivalenceNodes(char *name1, int file1, char *name2, int file2);
|
||||
extern int EquivalenceClasses(char *name1, int file1, char *name2, int file2);
|
||||
extern int EquivalenceClasses(char *name1, int file1, char *name2, int file2,
|
||||
int dounique);
|
||||
extern int IgnoreClass(char *name, int file, unsigned char type);
|
||||
extern int MatchPins(struct nlist *tp1, struct nlist *tp2, int dolist);
|
||||
extern int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run,
|
||||
|
|
@ -46,6 +49,7 @@ extern int CreateCompareQueue(char *, int, char *, int);
|
|||
extern int GetCompareQueueTop(char **, int *, char **, int *);
|
||||
extern int PeekCompareQueueTop(char **, int *, char **, int *);
|
||||
extern void RemoveCompareQueue();
|
||||
extern int FlattenUnmatched(struct nlist *, char *, int, int);
|
||||
|
||||
extern void PrintIllegalClasses();
|
||||
extern void PrintIllegalNodeClasses();
|
||||
|
|
@ -58,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);
|
||||
|
||||
|
|
@ -66,6 +70,8 @@ extern int remove_group_tags(struct objlist *ob);
|
|||
#ifdef TCL_NETGEN
|
||||
extern int EquivalentNode();
|
||||
extern int EquivalentElement();
|
||||
extern void DeriveAreaProperty();
|
||||
extern void DerivePerimeterProperty();
|
||||
|
||||
extern void enable_interrupt();
|
||||
extern void disable_interrupt();
|
||||
|
|
|
|||
231
base/netfile.c
231
base/netfile.c
|
|
@ -183,7 +183,6 @@ void CloseFile(char *filename)
|
|||
fclose(outfile);
|
||||
}
|
||||
|
||||
|
||||
/* STUFF TO READ INPUT FILES */
|
||||
|
||||
static char *line = NULL; /* actual line read in */
|
||||
|
|
@ -207,6 +206,21 @@ struct hashdict *definitions = (struct hashdict *)NULL;
|
|||
|
||||
#define WHITESPACE_DELIMITER " \t\n\r"
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Seek and Tell on infile stream, for use with handling generate */
|
||||
/* loops in verilog. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void SeekFile(long offset)
|
||||
{
|
||||
fseek(infile, offset, SEEK_SET);
|
||||
}
|
||||
|
||||
long TellFile()
|
||||
{
|
||||
return ftell(infile);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* TrimQuoted() --- */
|
||||
/* Remove spaces from inside single- or double-quoted strings. */
|
||||
|
|
@ -288,7 +302,7 @@ int GetNextLineNoNewline(char *delimiter)
|
|||
{
|
||||
char *newbuf;
|
||||
int testc;
|
||||
int nested = 0;
|
||||
static int nested = 0;
|
||||
int llen;
|
||||
|
||||
if (feof(infile)) return -1;
|
||||
|
|
@ -315,6 +329,11 @@ int GetNextLineNoNewline(char *delimiter)
|
|||
llen = strlen(line);
|
||||
}
|
||||
while (llen == linesize - 1) {
|
||||
/* Note that in the rare case where a newline is in the last buffer
|
||||
* position, we're done.
|
||||
*/
|
||||
if (*(line + llen - 1) == '\n') break;
|
||||
|
||||
newbuf = (char *)MALLOC(linesize + 501);
|
||||
strcpy(newbuf, line);
|
||||
FREE(line);
|
||||
|
|
@ -331,77 +350,87 @@ int GetNextLineNoNewline(char *delimiter)
|
|||
linetok = (char *)MALLOC(linesize + 1);
|
||||
}
|
||||
|
||||
/* Check for substitutions (verilog only). Make sure linetok is */
|
||||
/* large enough to hold the entire line after substitutions. */
|
||||
|
||||
if (definitions != NULL) {
|
||||
char *s, *w, e;
|
||||
struct property *kl;
|
||||
int len, dlen, vlen, addin = 0;
|
||||
unsigned char found = FALSE;
|
||||
|
||||
for (s = line; *s != '\0'; s++) {
|
||||
if (*s == '`') {
|
||||
w = s + 1;
|
||||
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
|
||||
e = *w;
|
||||
*w = '\0';
|
||||
kl = (struct property *)HashLookup(s + 1, definitions);
|
||||
if (kl != NULL) {
|
||||
dlen = strlen(s);
|
||||
if (kl->type == PROP_STRING) {
|
||||
vlen = strlen(kl->pdefault.string);
|
||||
}
|
||||
else vlen = 12; /* Leave room for numeric conversion */
|
||||
addin += vlen - dlen + 1;
|
||||
found = TRUE;
|
||||
}
|
||||
*w = e;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
len = strlen(line);
|
||||
if (len + addin > linesize) {
|
||||
while (len + addin > linesize) linesize += 500;
|
||||
FREE(linetok);
|
||||
linetok = (char *)MALLOC(linesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Make definition substitutions (verilog only) */
|
||||
|
||||
if (definitions != NULL) {
|
||||
if (definitions == NULL)
|
||||
strcpy(linetok, line);
|
||||
else {
|
||||
char *s, *t, *w, e;
|
||||
struct property *kl;
|
||||
int len, dlen, vlen, addin = 0;
|
||||
int oldlinesize = linesize;
|
||||
unsigned char found = TRUE;
|
||||
|
||||
t = linetok;
|
||||
for (s = line; *s != '\0'; s++) {
|
||||
if (*s == '`') {
|
||||
w = s + 1;
|
||||
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
|
||||
e = *w;
|
||||
*w = '\0';
|
||||
kl = (struct property *)HashLookup(s + 1, definitions);
|
||||
if (kl != NULL) {
|
||||
if (kl->type == PROP_STRING)
|
||||
strcpy(t, kl->pdefault.string);
|
||||
else if (kl->type == PROP_INTEGER)
|
||||
sprintf(t, "%d", kl->pdefault.ival);
|
||||
else if (kl->type == PROP_DOUBLE)
|
||||
sprintf(t, "%g", kl->pdefault.dval);
|
||||
t += strlen(t);
|
||||
s = w - 1;
|
||||
/* Check for substitutions (verilog only). Make sure linetok is */
|
||||
/* large enough to hold the entire line after substitutions. */
|
||||
|
||||
while (found) { /* Do this recursively, for nested definitions */
|
||||
found = FALSE;
|
||||
|
||||
for (s = line; *s != '\0'; s++) {
|
||||
if (*s == '`') {
|
||||
w = s + 1;
|
||||
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
|
||||
e = *w;
|
||||
*w = '\0';
|
||||
kl = (struct property *)HashLookup(s + 1, definitions);
|
||||
if (kl != NULL) {
|
||||
dlen = strlen(s);
|
||||
if (kl->type == PROP_STRING) {
|
||||
vlen = strlen(kl->pdefault.string);
|
||||
}
|
||||
else vlen = 12; /* Leave room for numeric conversion */
|
||||
addin += vlen - dlen + 1;
|
||||
found = TRUE;
|
||||
}
|
||||
*w = e;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
len = strlen(line);
|
||||
if (len + addin > linesize) {
|
||||
while (len + addin > linesize) linesize += 500;
|
||||
FREE(linetok);
|
||||
linetok = (char *)MALLOC(linesize);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make definition substitutions (verilog only) */
|
||||
|
||||
t = linetok;
|
||||
for (s = line; *s != '\0'; s++) {
|
||||
if (*s == '`') {
|
||||
w = s + 1;
|
||||
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
|
||||
e = *w;
|
||||
*w = '\0';
|
||||
kl = (struct property *)HashLookup(s + 1, definitions);
|
||||
if (kl != NULL) {
|
||||
if (kl->type == PROP_STRING)
|
||||
strcpy(t, kl->pdefault.string);
|
||||
else if (kl->type == PROP_INTEGER)
|
||||
sprintf(t, "%d", kl->pdefault.ival);
|
||||
else if (kl->type == PROP_DOUBLE)
|
||||
sprintf(t, "%g", kl->pdefault.dval);
|
||||
t += strlen(t);
|
||||
s = w - 1;
|
||||
}
|
||||
else *t++ = *s;
|
||||
*w = e;
|
||||
}
|
||||
else *t++ = *s;
|
||||
*w = e;
|
||||
}
|
||||
*t = '\0';
|
||||
|
||||
/* Copy substituted linetok back to line and repeat until */
|
||||
/* there are no more substitutions to be made. */
|
||||
|
||||
if (oldlinesize != linesize) {
|
||||
FREE(line);
|
||||
line = (char *)MALLOC(linesize + 501);
|
||||
oldlinesize = linesize;
|
||||
}
|
||||
else *t++ = *s;
|
||||
strcpy(line, linetok);
|
||||
}
|
||||
*t = '\0';
|
||||
}
|
||||
else
|
||||
strcpy(linetok, line);
|
||||
|
||||
TrimQuoted(linetok);
|
||||
linenum++;
|
||||
|
|
@ -563,19 +592,31 @@ void SkipTokNoNewline(char *delimiter)
|
|||
/* */
|
||||
/* Modified 3/30/2015 to include the condition where a comment line is */
|
||||
/* in the middle of a series of continuation lines. */
|
||||
/* */
|
||||
/* Modified 1/3/2024 to avoid skipping two lines if a line has only the */
|
||||
/* comment character '*' followed by a newline. It seems that '\n' is */
|
||||
/* being ignored in WHITESPACE_DELIMITER, but it's easier to write the */
|
||||
/* code to find the exception rather than track down the problem in */
|
||||
/* GetNextLine(). */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void SpiceTokNoNewline(void)
|
||||
{
|
||||
int contline;
|
||||
|
||||
if ((nexttok = strdtok(NULL, WHITESPACE_DELIMITER, NULL)) != NULL) return;
|
||||
if ((nexttok = strdtok0(NULL, WHITESPACE_DELIMITER, NULL, FALSE)) != NULL) return;
|
||||
|
||||
while (nexttok == NULL) {
|
||||
contline = getc(infile);
|
||||
if (contline == '*') {
|
||||
GetNextLine(WHITESPACE_DELIMITER);
|
||||
SkipNewLine(NULL);
|
||||
char testline = ' ';
|
||||
while ((testline == ' ') || (testline == '\t'))
|
||||
testline = getc(infile);
|
||||
if (testline != '\n') {
|
||||
ungetc(testline, infile);
|
||||
GetNextLine(WHITESPACE_DELIMITER);
|
||||
SkipNewLine(NULL);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (contline != '+') {
|
||||
|
|
@ -587,7 +628,8 @@ void SpiceTokNoNewline(void)
|
|||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Skip to the next token, ignoring any C-style comments. */
|
||||
/* Skip to the next token, ignoring any C-style comments and verilog */
|
||||
/* "(* ... *)"-style comments. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void SkipTokComments(char *delimiter)
|
||||
|
|
@ -603,6 +645,11 @@ void SkipTokComments(char *delimiter)
|
|||
SkipTok(delimiter);
|
||||
if (nexttok) SkipTok(delimiter);
|
||||
}
|
||||
else if (match(nexttok, "(*")) {
|
||||
while (nexttok && !match(nexttok, "*)"))
|
||||
SkipTok(delimiter);
|
||||
if (nexttok) SkipTok(delimiter);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
|
@ -638,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 */
|
||||
|
|
@ -658,8 +706,9 @@ 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 *strdtok(char *pstring, char *delim1, char *delim2)
|
||||
char *strdtok0(char *pstring, char *delim1, char *delim2, char isverilog)
|
||||
{
|
||||
static char *stoken = NULL;
|
||||
static char *sstring = NULL;
|
||||
|
|
@ -704,10 +753,10 @@ char *strdtok(char *pstring, char *delim1, char *delim2)
|
|||
/* should know whether it is parsing SPICE or verilog and handle the syntax */
|
||||
/* accordingly (needs to be done). */
|
||||
|
||||
if (*s == '\\') {
|
||||
if (isverilog && (*s == '\\')) {
|
||||
s++;
|
||||
while (*s != '\0') {
|
||||
if ((*s == ' ') || (*s == '\\')) {
|
||||
if ((*s == ' ') || ((*s == '\\') && (*(s + 1) == '\0'))) {
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
|
|
@ -775,6 +824,17 @@ char *strdtok(char *pstring, char *delim1, char *delim2)
|
|||
return sstring;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* strdtok() is the original string tokenizer. It calls strdtok0() */
|
||||
/* with isverilog=TRUE, so that tokens are parsed as (potentially) */
|
||||
/* verilog names, which includes verilog backslash notation. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
char *strdtok(char *pstring, char *delim1, char *delim2)
|
||||
{
|
||||
return strdtok0(pstring, delim1, delim2, TRUE);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void InputParseError(FILE *f)
|
||||
|
|
@ -856,7 +916,7 @@ char *ReadNetlist(char *fname, int *fnum)
|
|||
};
|
||||
|
||||
#ifdef mips
|
||||
struct filetype formats[7];
|
||||
struct filetype formats[8];
|
||||
|
||||
formats[0].extension = NTK_EXTENSION;
|
||||
formats[0].proc = ReadNtk;
|
||||
|
|
@ -864,14 +924,16 @@ char *ReadNetlist(char *fname, int *fnum)
|
|||
formats[1].proc = ReadExtHier;
|
||||
formats[2].extension = SIM_EXTENSION;
|
||||
formats[2].proc = ReadSim;
|
||||
formats[3].extension = SPICE_EXTENSION;
|
||||
formats[3].proc = ReadSpice;
|
||||
formats[4].extension = NETGEN_EXTENSION;
|
||||
formats[4].proc = ReadNetgenFile;
|
||||
formats[5].extension = VERILOG_EXTENSION;
|
||||
formats[5].proc = ReadVerilogFile;
|
||||
formats[6].extension = NULL;
|
||||
formats[6].proc = NULL;
|
||||
formats[3].extension = PRM_EXTENSION;
|
||||
formats[3].proc = ReadPrm;
|
||||
formats[4].extension = SPICE_EXTENSION;
|
||||
formats[4].proc = ReadSpice;
|
||||
formats[5].extension = NETGEN_EXTENSION;
|
||||
formats[5].proc = ReadNetgenFile;
|
||||
formats[6].extension = VERILOG_EXTENSION;
|
||||
formats[6].proc = ReadVerilogFile;
|
||||
formats[7].extension = NULL;
|
||||
formats[7].proc = NULL;
|
||||
|
||||
#else /* not mips (i.e. compiler with reasonable initializers) */
|
||||
|
||||
|
|
@ -880,6 +942,7 @@ char *ReadNetlist(char *fname, int *fnum)
|
|||
{NTK_EXTENSION, ReadNtk},
|
||||
{EXT_EXTENSION, ReadExtHier},
|
||||
{SIM_EXTENSION, ReadSim},
|
||||
{PRM_EXTENSION, ReadPrm},
|
||||
{SPICE_EXTENSION, ReadSpice},
|
||||
{SPICE_EXT2, ReadSpice},
|
||||
{SPICE_EXT3, ReadSpice},
|
||||
|
|
@ -904,7 +967,7 @@ char *ReadNetlist(char *fname, int *fnum)
|
|||
}
|
||||
/* try appending extensions in sequence, and testing for file existance */
|
||||
for (index = 0; formats[index].extension != NULL; index++) {
|
||||
char testname[200];
|
||||
char testname[MAX_STR_LEN];
|
||||
strcpy(testname, fname);
|
||||
strcat(testname, formats[index].extension);
|
||||
if (OpenParseFile(testname, *fnum) >= 0) {
|
||||
|
|
@ -1009,7 +1072,7 @@ void WriteNetgenFile(char *name, char *filename)
|
|||
|
||||
char *ReadNetgenFile (char *fname, int *fnum)
|
||||
{
|
||||
char name[100];
|
||||
char name[MAX_STR_LEN];
|
||||
char *LastCellRead = NULL;
|
||||
int filenum;
|
||||
|
||||
|
|
@ -1245,7 +1308,7 @@ int READ(void *buf, int bytes)
|
|||
|
||||
char *ReadNetgenFile (char *fname, int *fnum)
|
||||
{
|
||||
char name[100];
|
||||
char name[MAX_STR_LEN];
|
||||
int len, chars;
|
||||
char *LastCellRead = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#define WOMBAT_EXTENSION ".wom"
|
||||
#define EXT_EXTENSION ".ext"
|
||||
#define SIM_EXTENSION ".sim"
|
||||
#define PRM_EXTENSION ".prm"
|
||||
#define SPICE_EXTENSION ".spice"
|
||||
#define SPICE_EXT2 ".spc"
|
||||
#define SPICE_EXT3 ".sp"
|
||||
|
|
@ -35,6 +36,7 @@ extern struct hashdict *definitions;
|
|||
|
||||
extern char *nexttok;
|
||||
#define SKIPTO(a) do {SkipTok(NULL);} while (!match(nexttok,a))
|
||||
extern char *strdtok0(char *pstring, char *delim1, char *delim2, char isverilog);
|
||||
extern char *strdtok(char *pstring, char *delim1, char *delim2);
|
||||
extern char *GetLineAtTok();
|
||||
extern void SkipTok(char *delimiter);
|
||||
|
|
@ -47,5 +49,7 @@ extern void InputParseError(FILE *f);
|
|||
extern int OpenParseFile(char *name, int fnum);
|
||||
extern int EndParseFile(void);
|
||||
extern int CloseParseFile(void);
|
||||
extern void SeekFile(long offset); /* handles verilog 'for' loops */
|
||||
extern long TellFile(); /* handles verilog 'for' loops */
|
||||
|
||||
#endif /* _NETFILE_H */
|
||||
|
|
|
|||
116
base/netgen.c
116
base/netgen.c
|
|
@ -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>
|
||||
|
|
@ -57,7 +59,7 @@ int AddToExistingDefinition = 0; /* default: overwrite cell when reopened */
|
|||
extern int errno; /* Defined in stdlib.h */
|
||||
|
||||
#define MAX_STATIC_STRINGS 5
|
||||
static char staticstrings[MAX_STATIC_STRINGS][200];
|
||||
static char staticstrings[MAX_STATIC_STRINGS][MAX_STR_LEN];
|
||||
static int laststring;
|
||||
|
||||
extern struct hashdict spiceparams; /* From spice.c */
|
||||
|
|
@ -300,7 +302,9 @@ int ReduceOneExpression(struct valuelist *kv, struct objlist *parprops,
|
|||
tstr = sstr - 1;
|
||||
numlast = 1;
|
||||
}
|
||||
break;
|
||||
/* But might not be. . . */
|
||||
if ((dval != 0) || (sstr > estr))
|
||||
break;
|
||||
}
|
||||
/* Not a number, so must be arithmetic */
|
||||
*tstr = '\0';
|
||||
|
|
@ -320,7 +324,9 @@ int ReduceOneExpression(struct valuelist *kv, struct objlist *parprops,
|
|||
tstr = sstr - 1;
|
||||
numlast = 1;
|
||||
}
|
||||
break;
|
||||
/* But might not be. . . */
|
||||
if ((dval != 0) || (sstr > estr))
|
||||
break;
|
||||
}
|
||||
/* Not a number, so must be arithmetic */
|
||||
*tstr = '\0';
|
||||
|
|
@ -984,6 +990,51 @@ PropertyDelete(char *name, int fnum, char *key)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Associate a property with a specific pin */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
PropertyAssociatePin(char *name, int fnum, char *key, char *pin)
|
||||
{
|
||||
struct property *kl = NULL;
|
||||
struct nlist *tc;
|
||||
struct objlist *ob;
|
||||
int result;
|
||||
|
||||
if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
|
||||
result = PropertyAssociatePin(name, Circuit1->file, key, pin);
|
||||
result = PropertyAssociatePin(name, Circuit2->file, key, pin);
|
||||
return result;
|
||||
}
|
||||
|
||||
tc = LookupCellFile(name, fnum);
|
||||
if (tc == NULL) {
|
||||
Printf("No device %s found for PropertyAssociatePin()\n", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
kl = (struct property *)HashLookup(key, &(tc->propdict));
|
||||
if (kl == NULL) {
|
||||
Printf("No property %s found for device %s\n", key, name);
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
for (ob = tc->cell; ob != NULL; ob = ob->next) {
|
||||
if (ob->type != PORT) break;
|
||||
else if ((*matchfunc)(ob->name, pin)) {
|
||||
kl->pin = ob->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ob == NULL) {
|
||||
Printf("No pin %s found for device %s\n", pin, name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Set the tolerance of a property in the master cell record. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
|
@ -2199,7 +2250,10 @@ int PromoteProperty(struct property *prop, struct valuelist *vl,
|
|||
if (prop == NULL || vl == NULL) return -1;
|
||||
if (prop->type == vl->type) return 1; /* Nothing to do */
|
||||
result = 0;
|
||||
if (prop->type == PROP_EXPRESSION) {
|
||||
/* If vl is an expression but prop is not, then try to reduce
|
||||
* the expression in vl.
|
||||
*/
|
||||
if (vl->type == PROP_EXPRESSION) {
|
||||
ReduceOneExpression(vl, ob, tc, FALSE);
|
||||
}
|
||||
switch (prop->type) {
|
||||
|
|
@ -3045,7 +3099,7 @@ void add_balancing_close(struct objlist *ob1, struct objlist *ob2)
|
|||
for (nob = ob1->next; nob && nob->type != FIRSTPIN; nob = nob->next)
|
||||
if (nob->type == PROPERTY)
|
||||
break;
|
||||
if (nob->type != PROPERTY) return; // shouldn't happen
|
||||
if (nob == NULL || nob->type != PROPERTY) return; // shouldn't happen
|
||||
|
||||
opentags = 0;
|
||||
for (; nob->next && nob->next->type == PROPERTY; nob = nob->next) {
|
||||
|
|
@ -3337,16 +3391,13 @@ int CombineParallel(char *model, int file)
|
|||
/* "sob" to it. If "ob" does not have properties, then */
|
||||
/* create a property record and set property "M" to 1. */
|
||||
|
||||
/* Find last non-property record of sob ( = pob) */
|
||||
/* Find first property record of sob ( = spropfirst) */
|
||||
/* Find last property record of sob ( = sproplast) */
|
||||
/* Find last non-property record of sob ( = pob) */
|
||||
/* Find first property record of sob ( = spropfirst) */
|
||||
|
||||
spropfirst = sproplast = NULL;
|
||||
spropfirst = NULL;
|
||||
for (ob2 = sob; ob2->type > FIRSTPIN || ob2 == sob; ob2 = ob2->next)
|
||||
pob = ob2;
|
||||
if (ob2->type == PROPERTY) spropfirst = ob2;
|
||||
for (; ob2->type == PROPERTY; ob2 = ob2->next)
|
||||
sproplast = ob2;
|
||||
|
||||
if (spropfirst == NULL) {
|
||||
/* Create new property instance record if one doesn't exist */
|
||||
|
|
@ -3372,8 +3423,9 @@ int CombineParallel(char *model, int file)
|
|||
nob->next = pob->next;
|
||||
pob->next = nob;
|
||||
|
||||
/* Handle case of contiguous entries */
|
||||
if (lob == pob) lob = nob;
|
||||
spropfirst = sproplast = nob;
|
||||
spropfirst = nob;
|
||||
}
|
||||
if (propfirst == NULL) {
|
||||
/* Create new property instance record if one doesn't exist */
|
||||
|
|
@ -3396,27 +3448,26 @@ int CombineParallel(char *model, int file)
|
|||
kv->type = PROP_ENDLIST;
|
||||
kv->value.ival = 0;
|
||||
|
||||
/* Append to sob's property list */
|
||||
nob->next = sproplast->next;
|
||||
sproplast->next = nob;
|
||||
if (lob == sproplast) lob = nob;
|
||||
/* Prepend to sob's property list */
|
||||
nob->next = pob->next;
|
||||
pob->next = nob;
|
||||
/* Handle case of contiguous entries */
|
||||
if (lob == pob) lob = nob;
|
||||
}
|
||||
|
||||
if (propfirst != NULL) {
|
||||
else {
|
||||
|
||||
// Series/Parallel logic:
|
||||
// If propfirst has _tag in properties,
|
||||
// then add an "open" tag at propfirst
|
||||
add_prop_tag(propfirst, '(');
|
||||
// If spropfirst has _tag in properties,
|
||||
// then add an "open" tag at spropfirst
|
||||
add_prop_tag(spropfirst, '(');
|
||||
|
||||
// if spropfirst has _tag in properties then add an "open" tag
|
||||
// to spropfirst and a "close" tag to propfirst
|
||||
if (add_prop_tag(spropfirst, '(')) add_prop_tag(propfirst, ')');
|
||||
// if propfirst has _tag in properties then add an "open" tag
|
||||
// to propfirst and a "close" tag to spropfirst
|
||||
if (add_prop_tag(propfirst, '(')) add_prop_tag(spropfirst, ')');
|
||||
|
||||
/* Append ob's property list to sob */
|
||||
proplast->next = sproplast->next;
|
||||
sproplast->next = propfirst;
|
||||
if (lob == sproplast) lob = proplast;
|
||||
/* Prepend ob's property list to sob */
|
||||
proplast->next = pob->next;
|
||||
pob->next = propfirst;
|
||||
}
|
||||
|
||||
/* Link up around object to be removed */
|
||||
|
|
@ -3429,7 +3480,6 @@ int CombineParallel(char *model, int file)
|
|||
obr = nob;
|
||||
}
|
||||
dcnt++;
|
||||
|
||||
}
|
||||
FREE((char *)pstr);
|
||||
}
|
||||
|
|
@ -3441,7 +3491,8 @@ int CombineParallel(char *model, int file)
|
|||
}
|
||||
HashKill(&devdict);
|
||||
if (dcnt > 0) {
|
||||
Fprintf(stdout, "Class %s(%d): Merged %d parallel devices.\n", model, file, dcnt);
|
||||
Fprintf(stdout, "Class %s (%d): Merged %d parallel devices.\n",
|
||||
model, file, dcnt);
|
||||
}
|
||||
FREE(nodecount);
|
||||
return dcnt;
|
||||
|
|
@ -3598,7 +3649,7 @@ int CombineSeries(char *model, int file)
|
|||
nob->type = PROPERTY;
|
||||
nob->name = strsave("properties");
|
||||
nob->node = -2; /* Don't report as disconnected node */
|
||||
nob->model.class = (obp->model.class == NULL) ? NULL :
|
||||
nob->model.class = (obp == NULL || obp->model.class == NULL) ? NULL :
|
||||
strsave(obp->model.class);
|
||||
nob->instance.props = NewPropValue(2);
|
||||
|
||||
|
|
@ -3739,7 +3790,8 @@ int CombineSeries(char *model, int file)
|
|||
}
|
||||
FREE(instlist);
|
||||
if (scnt > 0) {
|
||||
Fprintf(stdout, "Class %s(%d): Merged %d series devices.\n", model, file, scnt);
|
||||
Fprintf(stdout, "Class %s (%d): Merged %d series devices.\n",
|
||||
model, file, scnt);
|
||||
}
|
||||
return scnt;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ extern void SetParallelCombine(int value);
|
|||
extern void SetSeriesCombine(int value);
|
||||
extern int PropertyTolerance(char *name, int fnum, char *key, int ival,
|
||||
double dval);
|
||||
extern int PropertyAssociatePin(char *name, int fnum, char *key, char *pin);
|
||||
extern int PropertyMerge(char *name, int fnum, char *key, int merge_type,
|
||||
int merge_mask);
|
||||
extern void ResolveProperties(char *name1, int file1, char *name2, int file2);
|
||||
|
|
@ -190,6 +191,7 @@ extern char *ReadNtk (char *fname, int *fnum);
|
|||
extern char *ReadExtHier(char *fname, int *fnum);
|
||||
extern char *ReadExtFlat(char *fname, int *fnum);
|
||||
extern char *ReadSim(char *fname, int *fnum);
|
||||
extern char *ReadPrm(char *fname, int *fnum);
|
||||
extern char *ReadSpice(char *fname, int *fnum);
|
||||
extern char *ReadSpiceLib(char *fname, int *fnum);
|
||||
extern char *ReadNetgenFile (char *fname, int *fnum);
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ void Ntk(char *name, char *filename)
|
|||
|
||||
char *ReadNtk (char *fname, int *fnum)
|
||||
{
|
||||
char model[100], instancename[100], name[100];
|
||||
char model[MAX_STR_LEN], instancename[MAX_STR_LEN], name[MAX_STR_LEN];
|
||||
struct objlist *ob;
|
||||
int CellDefInProgress = 0;
|
||||
int filenum;
|
||||
|
|
@ -218,7 +218,7 @@ char *ReadNtk (char *fname, int *fnum)
|
|||
}
|
||||
}
|
||||
else if (match(nexttok, "s")) {
|
||||
char last[100];
|
||||
char last[MAX_STR_LEN];
|
||||
*last = '\0';
|
||||
if (!CellDefInProgress) {
|
||||
/* fake cell declaration for top-level call */
|
||||
|
|
|
|||
237
base/objlist.c
237
base/objlist.c
|
|
@ -130,6 +130,7 @@ struct property *NewProperty(void)
|
|||
|
||||
kl = (struct property *)CALLOC(1,sizeof(struct property));
|
||||
if (kl == NULL) Fprintf(stderr,"NewProperty: Core allocation error\n");
|
||||
kl->pin = (char *)NULL;
|
||||
return (kl);
|
||||
}
|
||||
|
||||
|
|
@ -222,12 +223,35 @@ 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.
|
||||
* *Both* values null will also be treated as a mismatch (debatable
|
||||
* behavior).
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
|
@ -258,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)
|
||||
{
|
||||
|
|
@ -425,6 +476,7 @@ int removeshorted(struct hashlist *p, int file)
|
|||
ob = nob;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Remove shorted instances of class "class" from the database */
|
||||
|
|
@ -440,15 +492,32 @@ void RemoveShorted(char *class, int file)
|
|||
RecurseCellFileHashTable(removeshorted, file);
|
||||
}
|
||||
|
||||
/* Remove instances of a deleted class from the database. */
|
||||
/* NOTE: This treats deleted classes as not existing, so it */
|
||||
/* needs to take care of disconnected ports in the same manner */
|
||||
/* as flattenInstancesOf() in disconnecting the port of a */
|
||||
/* parent cell if it connected to nothing other than the */
|
||||
/* deleted instance. */
|
||||
|
||||
int deleteclass(struct hashlist *p, int file)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
struct objlist *ob, *lob, *nob;
|
||||
struct objlist *ob, *lob, *nob, *portnode;
|
||||
unsigned char *checknodes;
|
||||
int i;
|
||||
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
|
||||
if ((file != -1) && (ptr->file != file)) return 0;
|
||||
|
||||
/* Note: This could be made faster by enumerating all times each
|
||||
* node is used during the full pass, then subtracting each time
|
||||
* the node is deleted in a child, then disconnecting all nodes
|
||||
* that ended up with a zero count.
|
||||
*/
|
||||
checknodes = (unsigned char *)CALLOC(ptr->nodename_cache_maxnodenum + 1,
|
||||
sizeof(unsigned char));
|
||||
|
||||
lob = NULL;
|
||||
for (ob = ptr->cell; ob != NULL;) {
|
||||
nob = ob->next;
|
||||
|
|
@ -456,6 +525,8 @@ int deleteclass(struct hashlist *p, int file)
|
|||
if ((*matchfunc)(ob->model.class, OldCell->name)) {
|
||||
HashDelete(ob->instance.name, &(ptr->instdict));
|
||||
while (1) {
|
||||
if (ob->type >= FIRSTPIN)
|
||||
checknodes[ob->node] = (unsigned char)1;
|
||||
FreeObjectAndHash(ob, ptr);
|
||||
ob = nob;
|
||||
if (ob == NULL) break;
|
||||
|
|
@ -477,6 +548,26 @@ int deleteclass(struct hashlist *p, int file)
|
|||
ob = nob;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i <= ptr->nodename_cache_maxnodenum; i++) {
|
||||
if (checknodes[i] != 0) {
|
||||
portnode = NULL;
|
||||
for (ob = ptr->cell; ob != NULL; ob = ob->next) {
|
||||
if ((ob->type != PORT) && (portnode == NULL))
|
||||
break;
|
||||
else if ((ob->type == PORT) && (ob->node == i))
|
||||
portnode = ob;
|
||||
else if ((ob->type >= FIRSTPIN) && (ob->node == i))
|
||||
break;
|
||||
}
|
||||
if ((ob == NULL) && (portnode != NULL)) {
|
||||
/* Port became disconnected when child was deleted */
|
||||
portnode->node = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
FREE(checknodes);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Remove all instances of class "class" from the database */
|
||||
|
|
@ -514,6 +605,7 @@ int renameinstances(struct hashlist *p, int file)
|
|||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void InstanceRename(char *from, char *to, int file)
|
||||
|
|
@ -536,9 +628,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;
|
||||
|
|
@ -557,65 +650,65 @@ int freeprop(struct hashlist *p)
|
|||
|
||||
void CellDelete(char *name, int fnum)
|
||||
{
|
||||
/* delete all the contents of cell 'name', and remove 'name' from
|
||||
the cell hash table. NOTE: this procedure does not care or check
|
||||
if 'name' has been instanced anywhere. It is assumed that if this
|
||||
is the case, the user will (quickly) define a new cell of that name.
|
||||
*/
|
||||
struct objlist *ob, *obnext;
|
||||
struct nlist *tp;
|
||||
/* delete all the contents of cell 'name', and remove 'name' from
|
||||
the cell hash table. NOTE: this procedure does not care or check
|
||||
if 'name' has been instanced anywhere. It is assumed that if this
|
||||
is the case, the user will (quickly) define a new cell of that name.
|
||||
*/
|
||||
struct objlist *ob, *obnext;
|
||||
struct nlist *tp;
|
||||
|
||||
tp = LookupCellFile(name, fnum);
|
||||
if (tp == NULL) {
|
||||
Printf ("No cell '%s' found.\n", name);
|
||||
return;
|
||||
}
|
||||
tp = LookupCellFile(name, fnum);
|
||||
if (tp == NULL) {
|
||||
Printf ("No cell '%s' found.\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
HashIntDelete(name, fnum, &cell_dict);
|
||||
/* now make sure that we free all the fields of the nlist struct */
|
||||
if (tp->name != NULL) FREE(tp->name);
|
||||
HashKill(&(tp->objdict));
|
||||
HashKill(&(tp->instdict));
|
||||
RecurseHashTable(&(tp->propdict), freeprop);
|
||||
HashKill(&(tp->propdict));
|
||||
FreeNodeNames(tp);
|
||||
ob = tp->cell;
|
||||
while (ob != NULL) {
|
||||
obnext = ob->next;
|
||||
FreeObject (ob);
|
||||
ob = obnext;
|
||||
}
|
||||
HashIntDelete(name, fnum, &cell_dict);
|
||||
/* now make sure that we free all the fields of the nlist struct */
|
||||
if (tp->name != NULL) FREE(tp->name);
|
||||
HashKill(&(tp->objdict));
|
||||
HashKill(&(tp->instdict));
|
||||
RecurseHashTable(&(tp->propdict), freeprop);
|
||||
HashKill(&(tp->propdict));
|
||||
FreeNodeNames(tp);
|
||||
ob = tp->cell;
|
||||
while (ob != NULL) {
|
||||
obnext = ob->next;
|
||||
FreeObject (ob);
|
||||
ob = obnext;
|
||||
}
|
||||
}
|
||||
|
||||
static int PrintCellHashTableElement(struct hashlist *p)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
struct nlist *ptr;
|
||||
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
if ((TopFile >= 0) && (ptr->file != TopFile)) return 1;
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
if ((TopFile >= 0) && (ptr->file != TopFile)) return 1;
|
||||
|
||||
if (ptr->class != CLASS_SUBCKT) {
|
||||
/* only print primitive cells if Debug is enabled */
|
||||
if (Debug == 1) Printf("Cell: %s (instanced %d times); Primitive\n",
|
||||
if ((ptr->class != CLASS_SUBCKT) && (ptr->class != CLASS_MODULE)) {
|
||||
/* only print primitive cells if Debug is enabled */
|
||||
if (Debug == 1) Printf("Cell: %s (instanced %d times); Primitive\n",
|
||||
ptr->name, ptr->number);
|
||||
else if (Debug == 3) { /* list */
|
||||
else if (Debug == 3) { /* list */
|
||||
#ifdef TCL_NETGEN
|
||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||
#else
|
||||
Printf("%s ", ptr->name);
|
||||
Printf("%s ", ptr->name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if ((Debug == 2) || (Debug == 3)) { /* list only */
|
||||
}
|
||||
}
|
||||
else if ((Debug == 2) || (Debug == 3)) { /* list only */
|
||||
#ifdef TCL_NETGEN
|
||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||
#else
|
||||
Printf("%s ", ptr->name);
|
||||
Printf("%s ", ptr->name);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
Printf("Cell: %s (instanced %d times)\n",ptr->name,ptr->number);
|
||||
return(1);
|
||||
}
|
||||
else
|
||||
Printf("Cell: %s (instanced %d times)\n", ptr->name, ptr->number);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* Print the contents of the cell hash table. */
|
||||
|
|
@ -624,65 +717,65 @@ static int PrintCellHashTableElement(struct hashlist *p)
|
|||
|
||||
void PrintCellHashTable(int full, int filenum)
|
||||
{
|
||||
int total, bins;
|
||||
int OldDebug;
|
||||
int total, bins;
|
||||
int OldDebug;
|
||||
|
||||
if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
|
||||
if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
|
||||
PrintCellHashTable(full, Circuit1->file);
|
||||
PrintCellHashTable(full, Circuit2->file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TopFile = filenum;
|
||||
TopFile = filenum;
|
||||
|
||||
bins = RecurseHashTable(&cell_dict, CountHashTableBinsUsed);
|
||||
total = RecurseHashTable(&cell_dict, CountHashTableEntries);
|
||||
if (full < 2)
|
||||
Printf("Hash table: %d of %d bins used; %d cells total (%.2f per bin)\n",
|
||||
bins = RecurseHashTable(&cell_dict, CountHashTableBinsUsed);
|
||||
total = RecurseHashTable(&cell_dict, CountHashTableEntries);
|
||||
if (full < 2)
|
||||
Printf("Hash table: %d of %d bins used; %d cells total (%.2f per bin)\n",
|
||||
bins, CELLHASHSIZE, total, (bins == 0) ? 0 :
|
||||
(float)((float)total / (float)bins));
|
||||
|
||||
OldDebug = Debug;
|
||||
Debug = full;
|
||||
RecurseHashTable(&cell_dict, PrintCellHashTableElement);
|
||||
Debug = OldDebug;
|
||||
OldDebug = Debug;
|
||||
Debug = full;
|
||||
RecurseHashTable(&cell_dict, PrintCellHashTableElement);
|
||||
Debug = OldDebug;
|
||||
#ifndef TCL_NETGEN
|
||||
if (full >= 2) Printf("\n");
|
||||
if (full >= 2) Printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
struct nlist *FirstCell(void)
|
||||
{
|
||||
return((struct nlist *)HashFirst(&cell_dict));
|
||||
return((struct nlist *)HashFirst(&cell_dict));
|
||||
}
|
||||
|
||||
struct nlist *NextCell(void)
|
||||
{
|
||||
return((struct nlist *)HashNext(&cell_dict));
|
||||
return((struct nlist *)HashNext(&cell_dict));
|
||||
}
|
||||
|
||||
static int ClearDumpedElement(struct hashlist *np)
|
||||
{
|
||||
struct nlist *p;
|
||||
struct nlist *p;
|
||||
|
||||
p = (struct nlist *)(np->ptr);
|
||||
p->dumped = 0;
|
||||
return(1);
|
||||
p = (struct nlist *)(np->ptr);
|
||||
p->dumped = 0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
void ClearDumpedList(void)
|
||||
{
|
||||
RecurseHashTable(&cell_dict, ClearDumpedElement);
|
||||
RecurseHashTable(&cell_dict, ClearDumpedElement);
|
||||
}
|
||||
|
||||
int RecurseCellHashTable(int (*foo)(struct hashlist *np))
|
||||
{
|
||||
return RecurseHashTable(&cell_dict, foo);
|
||||
return RecurseHashTable(&cell_dict, foo);
|
||||
}
|
||||
|
||||
int RecurseCellFileHashTable(int (*foo)(struct hashlist *, int), int value)
|
||||
{
|
||||
return RecurseHashTableValue(&cell_dict, foo, value);
|
||||
return RecurseHashTableValue(&cell_dict, foo, value);
|
||||
}
|
||||
|
||||
/* Yet another version, passing one parameter that is a pointer */
|
||||
|
|
@ -690,14 +783,14 @@ int RecurseCellFileHashTable(int (*foo)(struct hashlist *, int), int value)
|
|||
struct nlist *RecurseCellHashTable2(struct nlist *(*foo)(struct hashlist *,
|
||||
void *), void *pointer)
|
||||
{
|
||||
return RecurseHashTablePointer(&cell_dict, foo, pointer);
|
||||
return RecurseHashTablePointer(&cell_dict, foo, pointer);
|
||||
}
|
||||
|
||||
/************************** WILD-CARD STUFF *******************************/
|
||||
|
||||
char *FixTemplate(char *t)
|
||||
{
|
||||
char buffer[200];
|
||||
char buffer[MAX_STR_LEN];
|
||||
char *rstr;
|
||||
int i,j;
|
||||
int InsideBrace;
|
||||
|
|
@ -1208,7 +1301,7 @@ static char *OldNodeName(struct nlist *tp, int node)
|
|||
struct objlist *firstuniqueglobal;
|
||||
struct objlist *firstglobal;
|
||||
struct objlist *firstpin;
|
||||
static char StrBuffer[100];
|
||||
static char StrBuffer[MAX_STR_LEN];
|
||||
|
||||
#if 0
|
||||
/* make second pass, looking for ports */
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ struct property {
|
|||
unsigned char idx; /* index into valuelist */
|
||||
unsigned char type; /* string, integer, double, value, expression */
|
||||
unsigned char merge; /* how property changes when devices are merged */
|
||||
char *pin; /* associated pin (or NULL if not associated) */
|
||||
union {
|
||||
char *string;
|
||||
double dval;
|
||||
|
|
@ -206,7 +207,7 @@ struct nlist {
|
|||
char *name;
|
||||
int number; /* number of instances defined */
|
||||
int dumped; /* instance count, and general-purpose marker */
|
||||
unsigned char flags;
|
||||
unsigned short flags;
|
||||
unsigned char class;
|
||||
unsigned long classhash; /* randomized hash value for cell class */
|
||||
struct Permutation *permutes; /* list of permuting pins */
|
||||
|
|
@ -222,17 +223,18 @@ struct nlist {
|
|||
|
||||
/* Defined nlist structure flags */
|
||||
|
||||
#define CELL_MATCHED 0x01 /* cell matched to another */
|
||||
#define CELL_NOCASE 0x02 /* cell is case-insensitive (e.g., SPICE) */
|
||||
#define CELL_TOP 0x04 /* cell is a top-level cell */
|
||||
#define CELL_PLACEHOLDER 0x08 /* cell is a placeholder cell */
|
||||
#define CELL_PROPSMATCHED 0x10 /* properties matched to matching cell */
|
||||
#define CELL_DUPLICATE 0x20 /* cell has a duplicate */
|
||||
#define CELL_MATCHED 0x001 /* cell matched to another */
|
||||
#define CELL_NOCASE 0x002 /* cell is case-insensitive (e.g., SPICE) */
|
||||
#define CELL_TOP 0x004 /* cell is a top-level cell */
|
||||
#define CELL_PLACEHOLDER 0x008 /* cell is a placeholder cell */
|
||||
#define CELL_PROPSMATCHED 0x010 /* properties matched to matching cell */
|
||||
#define CELL_DUPLICATE 0x020 /* cell has a duplicate */
|
||||
#define CELL_VERILOG 0x040 /* cell is verilog module */
|
||||
|
||||
/* Flags for combination allowances and prohibitions */
|
||||
|
||||
#define COMB_SERIES 0x40
|
||||
#define COMB_NO_PARALLEL 0x80
|
||||
#define COMB_SERIES 0x100
|
||||
#define COMB_NO_PARALLEL 0x200
|
||||
|
||||
extern struct nlist *CurrentCell;
|
||||
extern struct objlist *CurrentTail;
|
||||
|
|
@ -307,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);
|
||||
|
|
|
|||
18
base/place.c
18
base/place.c
|
|
@ -511,8 +511,8 @@ int OpenEmbeddingFile(char *cellname, char *filename)
|
|||
/* returns 1 if OK */
|
||||
{
|
||||
struct nlist *tp;
|
||||
char outfilename[200];
|
||||
char logfilename[200];
|
||||
char outfilename[MAX_STR_LEN];
|
||||
char logfilename[MAX_STR_LEN];
|
||||
|
||||
tp = LookupCell(cellname);
|
||||
if (tp == NULL) {
|
||||
|
|
@ -783,7 +783,7 @@ void SetupArray(char *prompt1, char *prompt2, char *prompt3, int *data,
|
|||
void (*proc)(void))
|
||||
{
|
||||
int i, oldfanout;
|
||||
char name[100];
|
||||
char name[MAX_STR_LEN];
|
||||
|
||||
Printf(prompt1);
|
||||
for (i = 1; i <= MAX_TREE_DEPTH; i++)
|
||||
|
|
@ -792,7 +792,7 @@ void SetupArray(char *prompt1, char *prompt2, char *prompt3, int *data,
|
|||
|
||||
oldfanout = 1;
|
||||
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
|
||||
char prompt[100];
|
||||
char prompt[MAX_STR_LEN];
|
||||
int newfanout;
|
||||
sprintf(prompt, prompt2, i);
|
||||
promptstring(prompt, name);
|
||||
|
|
@ -822,7 +822,7 @@ void SetupArrayFromString(char *prompt1, char *prompt3, int *data,
|
|||
void (*proc)(void), char *text)
|
||||
{
|
||||
int i, oldfanout, newfanout;
|
||||
char string[100];
|
||||
char string[MAX_STR_LEN];
|
||||
char *ch;
|
||||
char *endch;
|
||||
|
||||
|
|
@ -962,7 +962,7 @@ void ProtoPrintParameters(void)
|
|||
void PROTOCHIP(void)
|
||||
/* a simple command interpreter to manage embedding/routing */
|
||||
{
|
||||
char name[100];
|
||||
char name[MAX_STR_LEN];
|
||||
char ch;
|
||||
|
||||
InitializeFanout();
|
||||
|
|
@ -1136,7 +1136,7 @@ void PROTOCHIP(void)
|
|||
|
||||
oldfanout = 1;
|
||||
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
|
||||
char prompt[100];
|
||||
char prompt[MAX_STR_LEN];
|
||||
int newfanout;
|
||||
sprintf(prompt,"Fanout for level %d (0 to quit): ",i);
|
||||
promptstring(prompt, name);
|
||||
|
|
@ -1168,7 +1168,7 @@ void PROTOCHIP(void)
|
|||
|
||||
oldfanout = 1;
|
||||
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
|
||||
char prompt[100];
|
||||
char prompt[MAX_STR_LEN];
|
||||
int newfanout;
|
||||
sprintf(prompt,"Common nodes for level %d (0 to quit): ",i);
|
||||
promptstring(prompt, name);
|
||||
|
|
@ -1200,7 +1200,7 @@ void PROTOCHIP(void)
|
|||
|
||||
oldfanout = 1;
|
||||
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
|
||||
char prompt[100];
|
||||
char prompt[MAX_STR_LEN];
|
||||
int newfanout;
|
||||
sprintf(prompt,"Used leaves for level %d (0 to quit): ",i);
|
||||
promptstring(prompt, name);
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ extern int ColumnBase;
|
|||
|
||||
struct filestr {
|
||||
FILE *f;
|
||||
char buffer[200];
|
||||
char buffer[MAX_STR_LEN];
|
||||
int wrap; /* column to wrap around in, or 0 if no wrap */
|
||||
} file_buffers[MAXFILES];
|
||||
|
||||
|
|
@ -107,7 +107,7 @@ void Fprintf(FILE *f, char *format, ...)
|
|||
{
|
||||
va_list ap;
|
||||
int FileIndex;
|
||||
char tmpstr[200];
|
||||
char tmpstr[MAX_STR_LEN];
|
||||
int bufferlongenough;
|
||||
int linewrapexceeded;
|
||||
|
||||
|
|
@ -203,7 +203,7 @@ void Printf(char *format, ...)
|
|||
void Printf(char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char tmpstr[200];
|
||||
char tmpstr[MAX_STR_LEN];
|
||||
|
||||
va_start(ap, format);
|
||||
vsprintf(tmpstr, format, ap);
|
||||
|
|
|
|||
24
base/query.c
24
base/query.c
|
|
@ -52,7 +52,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
/*************************************************************************/
|
||||
|
||||
static int SuppressPrompts = 0;
|
||||
static char InputLine[200];
|
||||
static char InputLine[MAX_STR_LEN];
|
||||
|
||||
void typeahead(char *str)
|
||||
{
|
||||
|
|
@ -73,7 +73,7 @@ but reads from 'promptstring_infile' if nec. */
|
|||
/* If interactive, puts out 'prompt' */
|
||||
{
|
||||
char *nexttok;
|
||||
char tmpstr[200];
|
||||
char tmpstr[MAX_STR_LEN];
|
||||
int echo;
|
||||
|
||||
if (promptstring_infile == NULL)
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -805,11 +806,14 @@ void DescribeInstance(char *name, int file)
|
|||
/* All black-box modules and placeholders by definition have all */
|
||||
/* disconnected pins, so don't report those. */
|
||||
|
||||
if (!(tp->flags & CELL_PLACEHOLDER) && (tp->class != CLASS_MODULE))
|
||||
{
|
||||
//if (disconnectednodes == 0) Fprintf(stderr, "\n");
|
||||
if ((!(tp->flags & CELL_PLACEHOLDER)) && (tp->class != CLASS_MODULE)) {
|
||||
// if (disconnectednodes == 0) Fprintf(stderr, "\n");
|
||||
disconnectednodes++;
|
||||
Fprintf(stderr, "Cell %s(%d) disconnected node: %s\n", tp->name, tp->file, ob->name);
|
||||
/* Don't report on ports marked "port_match_error", which is just confusing. */
|
||||
if (strcmp(ob->name, "port_match_error")) {
|
||||
Fprintf(stderr, "Cell %s (%d) disconnected node: %s\n",
|
||||
tp->name, tp->file, ob->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -930,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);
|
||||
}
|
||||
|
||||
|
|
@ -956,8 +960,8 @@ void Query(void)
|
|||
{
|
||||
/* little interactive debugger */
|
||||
char reply;
|
||||
char repstr[100];
|
||||
char repstr2[100];
|
||||
char repstr[MAX_STR_LEN];
|
||||
char repstr2[MAX_STR_LEN];
|
||||
float StartTime; /* for elapsed CPU times */
|
||||
int Timing; /* if true, print times of each command */
|
||||
int filenum = -1;
|
||||
|
|
|
|||
360
base/spice.c
360
base/spice.c
|
|
@ -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
|
||||
|
|
@ -43,6 +46,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
#include "print.h"
|
||||
#include "query.h"
|
||||
#include "objlist.h"
|
||||
#include "netcmp.h"
|
||||
|
||||
// Global storage for parameters from .PARAM
|
||||
struct hashdict spiceparams;
|
||||
|
|
@ -192,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) {
|
||||
|
|
@ -212,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) {
|
||||
|
|
@ -232,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) {
|
||||
|
|
@ -395,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) {
|
||||
|
|
@ -422,6 +426,7 @@ int renamepins(struct hashlist *p, int file)
|
|||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If any pins are marked unconnected, see if there are */
|
||||
|
|
@ -518,21 +523,27 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
|||
int warnings = 0, update = 0, hasports = 0;
|
||||
char *eqptr, devtype, in_subckt;
|
||||
struct keyvalue *kvlist = NULL;
|
||||
char inst[256], model[256], instname[256];
|
||||
struct nlist *tp;
|
||||
char inst[MAX_STR_LEN], model[MAX_STR_LEN], instname[MAX_STR_LEN];
|
||||
struct nlist *tp, *tpsave;
|
||||
struct objlist *parent, *sobj, *nobj, *lobj, *pobj;
|
||||
|
||||
inst[255] = '\0';
|
||||
model[255] = '\0';
|
||||
instname[255] = '\0';
|
||||
inst[MAX_STR_LEN-1] = '\0';
|
||||
model[MAX_STR_LEN-1] = '\0';
|
||||
instname[MAX_STR_LEN-1] = '\0';
|
||||
in_subckt = (char)0;
|
||||
|
||||
while (!EndParseFile()) {
|
||||
|
||||
SkipTok(NULL); /* get the next token */
|
||||
if ((EndParseFile()) && (nexttok == NULL)) break;
|
||||
if (nexttok == NULL) break;
|
||||
|
||||
if (nexttok[0] == '*') SkipNewLine(NULL);
|
||||
/* Handle comment lines. Note that some variants of CDL format
|
||||
* use "*." for information that is transparent to SPICE simulators.
|
||||
* Handle "*.GLOBAL" entries. All others are ignored.
|
||||
*/
|
||||
if ((nexttok[0] == '*') && (!matchnocase(nexttok, "*.GLOBAL")))
|
||||
SkipNewLine(NULL);
|
||||
|
||||
else if (matchnocase(nexttok, ".SUBCKT")) {
|
||||
SpiceTokNoNewline();
|
||||
|
|
@ -555,8 +566,9 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
|||
|
||||
/* Check for existence of the cell. We may need to rename it. */
|
||||
|
||||
snprintf(model, 99, "%s", nexttok);
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
||||
tp = LookupCellFile(nexttok, filenum);
|
||||
tpsave = NULL;
|
||||
|
||||
/* Check for name conflict with duplicate cell names */
|
||||
/* This may mean that the cell was used before it was */
|
||||
|
|
@ -595,11 +607,46 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
|||
tp = LookupCellFile(nexttok, filenum);
|
||||
}
|
||||
else if (tp != NULL) { /* Make a new definition for an empty cell */
|
||||
FreePorts(nexttok);
|
||||
CellDelete(nexttok, filenum); /* This removes any PLACEHOLDER flag */
|
||||
CellDef(model, filenum);
|
||||
tp = LookupCellFile(model, filenum);
|
||||
update = 1; /* Will need to update existing instances */
|
||||
/* Handle issue with SPICE read after verilog, where a placeholder
|
||||
* was created from the verilog. (1) If the pin names are "1", "2",
|
||||
* "3", then this is a SPICE placeholder, and just remove the CellDef
|
||||
* and re-create it. Otherwise, create new cell "_PLACEHOLDER_".
|
||||
* (2) After encountering .ends, run MatchPins between the two cells.
|
||||
* (3) delete the original cell and rename the new cell.
|
||||
*/
|
||||
int i = 1;
|
||||
char pname[10];
|
||||
for (pobj = tp->cell; pobj && pobj->type == PORT; pobj = pobj->next) {
|
||||
sprintf(pname, "%d", i);
|
||||
if (!matchnocase(pobj->name, pname)) break;
|
||||
i++;
|
||||
}
|
||||
if ((pobj == NULL) || (pobj->type != PORT)) {
|
||||
/* This is a SPICE placeholder created because the cell was instanced
|
||||
* before it was defined. However, the pins can be assumed to be in
|
||||
* the correct order, and pin reordering does not need to be done.
|
||||
*/
|
||||
FreePorts(nexttok);
|
||||
CellDelete(nexttok, filenum); /* This removes any PLACEHOLDER flag */
|
||||
CellDef(model, filenum);
|
||||
tp = LookupCellFile(model, filenum);
|
||||
update = 1; /* Will need to update existing instances */
|
||||
}
|
||||
else {
|
||||
/* This is (probably) a verilog placeholder created because the
|
||||
* verilog was read before the (SPICE) definitions. The verilog
|
||||
* netlist should have named the pins of the parent cell. However,
|
||||
* there is no guarantee the order of pins is correct. The MatchPins()
|
||||
* routine from netcmp.c can be used here to match the cell against
|
||||
* the placeholder, and reorder the pins in all instances to match.
|
||||
* Note that we cannot just reorder the SPICE pins to match the
|
||||
* verilog order, because there may be other SPICE netlists which
|
||||
* instance the cell with the correct SPICE port order.
|
||||
*/
|
||||
tpsave = tp;
|
||||
CellDef("_PLACEHOLDER_", filenum);
|
||||
tp = LookupCellFile("_PLACEHOLDER_", filenum);
|
||||
}
|
||||
}
|
||||
else if (tp == NULL) { /* Completely new cell, no name conflict */
|
||||
CellDef(model, filenum);
|
||||
|
|
@ -691,6 +738,38 @@ skip_ends:
|
|||
if (*CellStackPtr) PopStack(CellStackPtr);
|
||||
if (*CellStackPtr) ReopenCellDef((*CellStackPtr)->cellname, filenum);
|
||||
SkipNewLine(NULL);
|
||||
|
||||
if (tpsave != NULL) {
|
||||
struct nlist *tpplace;
|
||||
char *savename;
|
||||
|
||||
/* Handle a placeholder from a verilog file that has been replaced
|
||||
* by a netlist with pins in a different order. The pins need to
|
||||
* be matched, corrected in the original cell and all instances,
|
||||
* and the new cell deleted.
|
||||
*/
|
||||
|
||||
Printf("Verilog placeholder %s replaced by SPICE definition\n",
|
||||
tpsave->name);
|
||||
tpplace = LookupCellFile("_PLACEHOLDER_", filenum);
|
||||
/* MatchPins is part of netcmp and normally Circuit2 is the
|
||||
* circuit being matched, so set Circuit2 to the original
|
||||
* verilog black-box cell, and MatchPins() will force its
|
||||
* pins to be rearranged to match the SPICE definition just
|
||||
* read.
|
||||
*/
|
||||
Circuit2 = tpsave;
|
||||
MatchPins(tpplace, tpsave, 0);
|
||||
savename = strsave(tpsave->name);
|
||||
/* Now the original verilog black-box cell can be removed */
|
||||
FreePorts(savename);
|
||||
CellDelete(savename, filenum);
|
||||
/* And _PLACEHOLDER_ is renamed to the original name of the cell. */
|
||||
CellRehash("_PLACEHOLDER_", savename, filenum);
|
||||
tpsave = NULL;
|
||||
Circuit2 = NULL;
|
||||
FREE(savename);
|
||||
}
|
||||
}
|
||||
else if (matchnocase(nexttok, ".MODEL")) {
|
||||
unsigned char class = CLASS_SUBCKT;
|
||||
|
|
@ -703,7 +782,7 @@ skip_ends:
|
|||
|
||||
SpiceTokNoNewline();
|
||||
if (nexttok == NULL) continue; /* Ignore if no model name */
|
||||
snprintf(model, 99, "%s", nexttok);
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
||||
SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
|
||||
|
|
@ -752,7 +831,10 @@ skip_ends:
|
|||
|
||||
// Handle some commonly-used cards
|
||||
|
||||
else if (matchnocase(nexttok, ".GLOBAL")) {
|
||||
/* .GLOBAL and *.GLOBAL. Note that *.GLOBAL is excepted from comment-line
|
||||
* handling, above, so any line starting with '*' is "*.GLOBAL".
|
||||
*/
|
||||
else if (matchnocase(nexttok, ".GLOBAL") || (nexttok[0] == '*')) {
|
||||
while (nexttok != NULL) {
|
||||
int numnodes = 0;
|
||||
SpiceTokNoNewline();
|
||||
|
|
@ -887,29 +969,29 @@ skip_ends:
|
|||
}
|
||||
|
||||
else if (toupper(nexttok[0]) == 'Q') {
|
||||
char emitter[100], base[100], collector[100];
|
||||
emitter[99] = '\0';
|
||||
base[99] = '\0';
|
||||
collector[99] = '\0';
|
||||
char emitter[MAX_STR_LEN], base[MAX_STR_LEN], collector[MAX_STR_LEN];
|
||||
emitter[MAX_STR_LEN-1] = '\0';
|
||||
base[MAX_STR_LEN-1] = '\0';
|
||||
collector[MAX_STR_LEN-1] = '\0';
|
||||
|
||||
if (!(*CellStackPtr)) {
|
||||
CellDef(fname, filenum);
|
||||
PushStack(fname, CellStackPtr);
|
||||
}
|
||||
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(collector, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(collector, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(base, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(base, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(emitter, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(emitter, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
/* make sure all the nodes exist */
|
||||
if (LookupObject(collector, CurrentCell) == NULL) Node(collector);
|
||||
if (LookupObject(base, CurrentCell) == NULL) Node(base);
|
||||
if (LookupObject(emitter, CurrentCell) == NULL) Node(emitter);
|
||||
|
||||
/* Read the device model */
|
||||
snprintf(model, 99, "%s", nexttok);
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
||||
|
||||
while (nexttok != NULL)
|
||||
{
|
||||
|
|
@ -940,30 +1022,30 @@ skip_ends:
|
|||
goto baddevice;
|
||||
}
|
||||
|
||||
snprintf(instname, 255, "%s%s", model, inst);
|
||||
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
|
||||
Cell(instname, model, collector, base, emitter);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
DeleteProperties(&kvlist);
|
||||
}
|
||||
else if (toupper(nexttok[0]) == 'M') {
|
||||
char drain[100], gate[100], source[100], bulk[100];
|
||||
drain[99] = '\0';
|
||||
gate[99] = '\0';
|
||||
source[99] = '\0';
|
||||
bulk[99] = '\0';
|
||||
char drain[MAX_STR_LEN], gate[MAX_STR_LEN], source[MAX_STR_LEN], bulk[MAX_STR_LEN];
|
||||
drain[MAX_STR_LEN-1] = '\0';
|
||||
gate[MAX_STR_LEN-1] = '\0';
|
||||
source[MAX_STR_LEN-1] = '\0';
|
||||
bulk[MAX_STR_LEN-1] = '\0';
|
||||
|
||||
if (!(*CellStackPtr)) {
|
||||
CellDef(fname, filenum);
|
||||
PushStack(fname, CellStackPtr);
|
||||
}
|
||||
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(drain, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(drain, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(gate, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(gate, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(source, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(source, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
/* make sure all the nodes exist */
|
||||
if (LookupObject(drain, CurrentCell) == NULL) Node(drain);
|
||||
|
|
@ -971,11 +1053,11 @@ skip_ends:
|
|||
if (LookupObject(source, CurrentCell) == NULL) Node(source);
|
||||
|
||||
/* handle the substrate node */
|
||||
strncpy(bulk, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(bulk, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (LookupObject(bulk, CurrentCell) == NULL) Node(bulk);
|
||||
|
||||
/* Read the device model */
|
||||
snprintf(model, 99, "%s", nexttok);
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
||||
|
||||
while (nexttok != NULL)
|
||||
{
|
||||
|
|
@ -1013,7 +1095,7 @@ skip_ends:
|
|||
goto baddevice;
|
||||
}
|
||||
|
||||
snprintf(instname, 255, "%s%s", model, inst);
|
||||
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
|
||||
Cell(instname, model, drain, gate, source, bulk);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
|
|
@ -1027,19 +1109,19 @@ skip_ends:
|
|||
SpiceSkipNewLine();
|
||||
}
|
||||
else {
|
||||
char ctop[100], cbot[100];
|
||||
ctop[99] = '\0';
|
||||
cbot[99] = '\0';
|
||||
char ctop[MAX_STR_LEN], cbot[MAX_STR_LEN];
|
||||
ctop[MAX_STR_LEN-1] = '\0';
|
||||
cbot[MAX_STR_LEN-1] = '\0';
|
||||
|
||||
if (!(*CellStackPtr)) {
|
||||
CellDef(fname, filenum);
|
||||
PushStack(fname, CellStackPtr);
|
||||
}
|
||||
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(ctop, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(ctop, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(cbot, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(cbot, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
|
||||
/* make sure all the nodes exist */
|
||||
if (LookupObject(ctop, CurrentCell) == NULL) Node(ctop);
|
||||
|
|
@ -1058,7 +1140,7 @@ skip_ends:
|
|||
|
||||
model[0] = '\0';
|
||||
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
|
||||
snprintf(model, 99, "%s", nexttok);
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
||||
|
||||
/* Any other device properties? */
|
||||
while (nexttok != NULL)
|
||||
|
|
@ -1071,7 +1153,7 @@ skip_ends:
|
|||
}
|
||||
else if (!strncmp(nexttok, "$[", 2)) {
|
||||
// Support for CDL modeled capacitor format
|
||||
snprintf(model, 99, "%s", nexttok + 2);
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok + 2);
|
||||
if ((eqptr = strchr(model, ']')) != NULL)
|
||||
*eqptr = '\0';
|
||||
}
|
||||
|
|
@ -1104,7 +1186,7 @@ skip_ends:
|
|||
usemodel = 1;
|
||||
}
|
||||
|
||||
snprintf(instname, 255, "%s%s", model, inst);
|
||||
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
|
||||
if (usemodel)
|
||||
Cell(instname, model, ctop, cbot);
|
||||
else
|
||||
|
|
@ -1121,19 +1203,19 @@ skip_ends:
|
|||
SpiceSkipNewLine();
|
||||
}
|
||||
else {
|
||||
char rtop[100], rbot[100];
|
||||
rtop[99] = '\0';
|
||||
rbot[99] = '\0';
|
||||
char rtop[MAX_STR_LEN], rbot[MAX_STR_LEN];
|
||||
rtop[MAX_STR_LEN-1] = '\0';
|
||||
rbot[MAX_STR_LEN-1] = '\0';
|
||||
|
||||
if (!(*CellStackPtr)) {
|
||||
CellDef(fname, filenum);
|
||||
PushStack(fname, CellStackPtr);
|
||||
}
|
||||
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(rtop, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(rtop, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(rbot, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(rbot, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
/* make sure all the nodes exist */
|
||||
if (LookupObject(rtop, CurrentCell) == NULL) Node(rtop);
|
||||
if (LookupObject(rbot, CurrentCell) == NULL) Node(rbot);
|
||||
|
|
@ -1152,7 +1234,7 @@ skip_ends:
|
|||
|
||||
model[0] = '\0';
|
||||
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
|
||||
snprintf(model, 99, "%s", nexttok);
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
||||
|
||||
/* Any other device properties? */
|
||||
while (nexttok != NULL) {
|
||||
|
|
@ -1164,7 +1246,7 @@ skip_ends:
|
|||
}
|
||||
else if (!strncmp(nexttok, "$[", 2)) {
|
||||
// Support for CDL modeled resistor format
|
||||
snprintf(model, 99, "%s", nexttok + 2);
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok + 2);
|
||||
if ((eqptr = strchr(model, ']')) != NULL)
|
||||
*eqptr = '\0';
|
||||
}
|
||||
|
|
@ -1197,7 +1279,7 @@ skip_ends:
|
|||
else
|
||||
strcpy(model, "r"); /* Use default resistor model */
|
||||
|
||||
snprintf(instname, 255, "%s%s", model, inst);
|
||||
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
|
||||
if (usemodel)
|
||||
Cell(instname, model, rtop, rbot);
|
||||
else
|
||||
|
|
@ -1208,25 +1290,25 @@ skip_ends:
|
|||
}
|
||||
}
|
||||
else if (toupper(nexttok[0]) == 'D') { /* diode */
|
||||
char cathode[100], anode[100];
|
||||
cathode[99] = '\0';
|
||||
anode[99] = '\0';
|
||||
char cathode[MAX_STR_LEN], anode[MAX_STR_LEN];
|
||||
cathode[MAX_STR_LEN-1] = '\0';
|
||||
anode[MAX_STR_LEN-1] = '\0';
|
||||
|
||||
if (!(*CellStackPtr)) {
|
||||
CellDef(fname, filenum);
|
||||
PushStack(fname, CellStackPtr);
|
||||
}
|
||||
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(anode, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(anode, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(cathode, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(cathode, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
/* make sure all the nodes exist */
|
||||
if (LookupObject(anode, CurrentCell) == NULL) Node(anode);
|
||||
if (LookupObject(cathode, CurrentCell) == NULL) Node(cathode);
|
||||
|
||||
/* Read the device model */
|
||||
snprintf(model, 99, "%s", nexttok);
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
||||
|
||||
while (nexttok != NULL)
|
||||
{
|
||||
|
|
@ -1255,7 +1337,7 @@ skip_ends:
|
|||
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a diode.\n");
|
||||
goto baddevice;
|
||||
}
|
||||
snprintf(instname, 255, "%s%s", model, inst);
|
||||
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
|
||||
Cell(instname, model, anode, cathode);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
|
|
@ -1268,25 +1350,25 @@ skip_ends:
|
|||
SpiceSkipNewLine();
|
||||
}
|
||||
else {
|
||||
char node1[100], node2[100], node3[100], node4[100];
|
||||
node1[99] = '\0';
|
||||
node2[99] = '\0';
|
||||
node3[99] = '\0';
|
||||
node4[99] = '\0';
|
||||
char node1[MAX_STR_LEN], node2[MAX_STR_LEN], node3[MAX_STR_LEN], node4[MAX_STR_LEN];
|
||||
node1[MAX_STR_LEN-1] = '\0';
|
||||
node2[MAX_STR_LEN-1] = '\0';
|
||||
node3[MAX_STR_LEN-1] = '\0';
|
||||
node4[MAX_STR_LEN-1] = '\0';
|
||||
|
||||
if (!(*CellStackPtr)) {
|
||||
CellDef(fname, filenum);
|
||||
PushStack(fname, CellStackPtr);
|
||||
}
|
||||
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(node1, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(node1, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(node2, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(node2, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(node3, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(node3, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(node4, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(node4, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
/* make sure all the nodes exist */
|
||||
if (LookupObject(node1, CurrentCell) == NULL) Node(node1);
|
||||
if (LookupObject(node2, CurrentCell) == NULL) Node(node2);
|
||||
|
|
@ -1298,7 +1380,7 @@ skip_ends:
|
|||
|
||||
model[0] = '\0';
|
||||
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
|
||||
snprintf(model, 99, "%s", nexttok);
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
||||
|
||||
/* Any other device properties? */
|
||||
while (nexttok != NULL) {
|
||||
|
|
@ -1334,7 +1416,7 @@ skip_ends:
|
|||
else
|
||||
strcpy(model, "t"); /* Use default xline model */
|
||||
|
||||
snprintf(instname, 255, "%s%s", model, inst);
|
||||
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
|
||||
|
||||
if (usemodel)
|
||||
Cell(instname, model, node1, node2, node3, node4);
|
||||
|
|
@ -1347,20 +1429,20 @@ skip_ends:
|
|||
}
|
||||
}
|
||||
else if (toupper(nexttok[0]) == 'L') { /* inductor */
|
||||
char end_a[100], end_b[100];
|
||||
char end_a[MAX_STR_LEN], end_b[MAX_STR_LEN];
|
||||
int usemodel = 0;
|
||||
end_a[99] = '\0';
|
||||
end_b[99] = '\0';
|
||||
end_a[MAX_STR_LEN-1] = '\0';
|
||||
end_b[MAX_STR_LEN-1] = '\0';
|
||||
|
||||
if (!(*CellStackPtr)) {
|
||||
CellDef(fname, filenum);
|
||||
PushStack(fname, CellStackPtr);
|
||||
}
|
||||
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(end_a, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(end_a, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(end_b, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(end_b, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
/* make sure all the nodes exist */
|
||||
if (LookupObject(end_a, CurrentCell) == NULL) Node(end_a);
|
||||
if (LookupObject(end_b, CurrentCell) == NULL) Node(end_b);
|
||||
|
|
@ -1379,7 +1461,7 @@ skip_ends:
|
|||
|
||||
model[0] = '\0';
|
||||
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
|
||||
snprintf(model, 99, "%s", nexttok);
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
||||
|
||||
/* Any other device properties? */
|
||||
while (nexttok != NULL)
|
||||
|
|
@ -1417,7 +1499,7 @@ skip_ends:
|
|||
else
|
||||
strcpy(model, "l"); /* Use default inductor model */
|
||||
|
||||
snprintf(instname, 255, "%s%s", model, inst);
|
||||
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
|
||||
if (usemodel)
|
||||
Cell(instname, model, end_a, end_b);
|
||||
else
|
||||
|
|
@ -1431,25 +1513,38 @@ skip_ends:
|
|||
/* black-box subcircuits (class MODULE): V, I, E */
|
||||
|
||||
else if (toupper(nexttok[0]) == 'V') { /* voltage source */
|
||||
char pos[100], neg[100];
|
||||
pos[99] = '\0';
|
||||
neg[99] = '\0';
|
||||
char pos[MAX_STR_LEN], neg[MAX_STR_LEN];
|
||||
pos[MAX_STR_LEN-1] = '\0';
|
||||
neg[MAX_STR_LEN-1] = '\0';
|
||||
|
||||
if (!(*CellStackPtr)) {
|
||||
CellDef(fname, filenum);
|
||||
PushStack(fname, CellStackPtr);
|
||||
}
|
||||
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(pos, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(pos, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(neg, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(neg, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
/* make sure all the nodes exist */
|
||||
if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
|
||||
if (LookupObject(neg, CurrentCell) == NULL) Node(neg);
|
||||
|
||||
/* Any device properties? */
|
||||
/* Get voltage value (if present); save as property "value" */
|
||||
|
||||
if (nexttok != NULL) {
|
||||
if (matchnocase(nexttok, "DC")) {
|
||||
SpiceTokNoNewline();
|
||||
}
|
||||
}
|
||||
if (nexttok != NULL) {
|
||||
if (StringIsValueOrExpression(nexttok)) {
|
||||
AddProperty(&kvlist, "value", nexttok);
|
||||
}
|
||||
}
|
||||
|
||||
/* Any other device properties? */
|
||||
while (nexttok != NULL)
|
||||
{
|
||||
SpiceTokNoNewline();
|
||||
|
|
@ -1477,7 +1572,7 @@ skip_ends:
|
|||
else if (CountPorts(model, filenum) != 2) {
|
||||
/* Modeled device: Make sure it has the right number of ports */
|
||||
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a "
|
||||
"voltage source.\n");
|
||||
"voltage source.\n", inst);
|
||||
goto baddevice;
|
||||
}
|
||||
Cell(instname, model, pos, neg);
|
||||
|
|
@ -1486,19 +1581,19 @@ skip_ends:
|
|||
DeleteProperties(&kvlist);
|
||||
}
|
||||
else if (toupper(nexttok[0]) == 'I') { /* current source */
|
||||
char pos[100], neg[100];
|
||||
pos[99] = '\0';
|
||||
neg[99] = '\0';
|
||||
char pos[MAX_STR_LEN], neg[MAX_STR_LEN];
|
||||
pos[MAX_STR_LEN-1] = '\0';
|
||||
neg[MAX_STR_LEN-1] = '\0';
|
||||
|
||||
if (!(*CellStackPtr)) {
|
||||
CellDef(fname, filenum);
|
||||
PushStack(fname, CellStackPtr);
|
||||
}
|
||||
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(pos, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(pos, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(neg, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(neg, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
/* make sure all the nodes exist */
|
||||
if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
|
||||
if (LookupObject(neg, CurrentCell) == NULL) Node(neg);
|
||||
|
|
@ -1540,25 +1635,25 @@ skip_ends:
|
|||
DeleteProperties(&kvlist);
|
||||
}
|
||||
else if (toupper(nexttok[0]) == 'E') { /* controlled voltage source */
|
||||
char pos[100], neg[100], ctrlp[100], ctrln[100];
|
||||
pos[99] = '\0';
|
||||
neg[99] = '\0';
|
||||
ctrlp[99] = '\0';
|
||||
ctrln[99] = '\0';
|
||||
char pos[MAX_STR_LEN], neg[MAX_STR_LEN], ctrlp[MAX_STR_LEN], ctrln[MAX_STR_LEN];
|
||||
pos[MAX_STR_LEN-1] = '\0';
|
||||
neg[MAX_STR_LEN-1] = '\0';
|
||||
ctrlp[MAX_STR_LEN-1] = '\0';
|
||||
ctrln[MAX_STR_LEN-1] = '\0';
|
||||
|
||||
if (!(*CellStackPtr)) {
|
||||
CellDef(fname, filenum);
|
||||
PushStack(fname, CellStackPtr);
|
||||
}
|
||||
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(pos, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(pos, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(neg, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(neg, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(ctrlp, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(ctrlp, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
if (nexttok == NULL) goto baddevice;
|
||||
strncpy(ctrln, nexttok, 99); SpiceTokNoNewline();
|
||||
strncpy(ctrln, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
||||
|
||||
/* make sure all the nodes exist */
|
||||
if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
|
||||
|
|
@ -1606,11 +1701,11 @@ skip_ends:
|
|||
}
|
||||
|
||||
else if (toupper(nexttok[0]) == 'X') { /* subcircuit instances */
|
||||
char instancename[100], subcktname[100];
|
||||
char instancename[MAX_STR_LEN], subcktname[MAX_STR_LEN];
|
||||
int itype, in_props;
|
||||
|
||||
instancename[99] = '\0';
|
||||
subcktname[99] = '\0';
|
||||
instancename[MAX_STR_LEN-1] = '\0';
|
||||
subcktname[MAX_STR_LEN-1] = '\0';
|
||||
|
||||
struct portelement {
|
||||
char *name;
|
||||
|
|
@ -1620,8 +1715,8 @@ skip_ends:
|
|||
struct portelement *head, *tail, *scan, *scannext;
|
||||
struct objlist *obptr;
|
||||
|
||||
snprintf(instancename, 99, "%s", nexttok + 1);
|
||||
strncpy(instancename, nexttok + 1, 99);
|
||||
snprintf(instancename, MAX_STR_LEN-1, "%s", nexttok + 1);
|
||||
strncpy(instancename, nexttok + 1, MAX_STR_LEN-1);
|
||||
if (!(*CellStackPtr)) {
|
||||
CellDef(fname, filenum);
|
||||
PushStack(fname, CellStackPtr);
|
||||
|
|
@ -1688,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;
|
||||
}
|
||||
|
||||
|
|
@ -1706,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);
|
||||
|
|
@ -1729,14 +1833,14 @@ skip_ends:
|
|||
/* names. */
|
||||
|
||||
if (strncmp(instancename, scan->name, strlen(scan->name))) {
|
||||
snprintf(subcktname, 99, "%s%s", scan->name, instancename);
|
||||
snprintf(subcktname, MAX_STR_LEN-1, "%s:%s", scan->name, instancename);
|
||||
strcpy(instancename, subcktname);
|
||||
}
|
||||
else {
|
||||
snprintf(subcktname, 99, "/%s", instancename);
|
||||
snprintf(subcktname, MAX_STR_LEN-1, "/%s", instancename);
|
||||
strcpy(instancename, subcktname);
|
||||
}
|
||||
snprintf(subcktname, 99, "%s", scan->name);
|
||||
snprintf(subcktname, MAX_STR_LEN-1, "%s", scan->name);
|
||||
|
||||
if (scan == head) {
|
||||
head = NULL;
|
||||
|
|
@ -1770,6 +1874,18 @@ skip_ends:
|
|||
ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */
|
||||
update = 1;
|
||||
}
|
||||
else if (tp->flags & CELL_VERILOG) {
|
||||
if (tp->flags & CELL_PLACEHOLDER) {
|
||||
/* Flag this as an error. To do: Rearrange the verilog instance pins to */
|
||||
/* match the SPICE subcircuit pin order. */
|
||||
Fprintf(stderr, "Error: SPICE subcircuit %s should be read before verilog "
|
||||
"module using it, or pins may not match!\n", subcktname);
|
||||
}
|
||||
else {
|
||||
Fprintf(stderr, "Error: SPICE subcircuit %s redefines a verilog module!\n",
|
||||
subcktname);
|
||||
}
|
||||
}
|
||||
|
||||
/* nexttok is now NULL, scan->name points to class */
|
||||
|
||||
|
|
@ -1972,7 +2088,7 @@ void IncludeSpice(char *fname, int parent, struct cellstack **CellStackPtr,
|
|||
int blackbox)
|
||||
{
|
||||
int filenum = -1;
|
||||
char name[256];
|
||||
char name[MAX_STR_LEN];
|
||||
|
||||
/* If fname does not begin with "/", then assume that it is */
|
||||
/* in the same relative path as its parent. */
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
#include "print.h"
|
||||
#endif
|
||||
|
||||
extern void Finsert(FILE *f);
|
||||
|
||||
void test_entry(void)
|
||||
{
|
||||
|
||||
|
|
|
|||
1319
base/verilog.c
1319
base/verilog.c
File diff suppressed because it is too large
Load Diff
|
|
@ -65,10 +65,10 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
|
||||
Widget toplevel = NULL;
|
||||
|
||||
char GlobalFileName[100],
|
||||
GlobalCellName[100],
|
||||
GlobalOtherName[100],
|
||||
GlobalDataName[100];
|
||||
char GlobalFileName[MAX_STR_LEN],
|
||||
GlobalCellName[MAX_STR_LEN],
|
||||
GlobalOtherName[MAX_STR_LEN],
|
||||
GlobalDataName[MAX_STR_LEN];
|
||||
|
||||
/*********************************************************
|
||||
* Menu structure: attaches label string to a function,
|
||||
|
|
@ -1708,7 +1708,7 @@ void X_main_loop(int argc, char *argv[])
|
|||
|
||||
XmStringCharSet cs = "ISOLatin1";
|
||||
|
||||
static char prompt_response[100];
|
||||
static char prompt_response[MAX_STR_LEN];
|
||||
int prompt_done;
|
||||
int calling_editor; /* which string are we trying to get ? */
|
||||
#define FILE_NAME 1
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ along with this program; see the file copying. If not, write to
|
|||
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* inetcomp.c -- a simple wrapper to the NETCOMP() function */
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "netgen.h"
|
||||
|
|
@ -33,7 +34,7 @@ void STRCPY(char *dest, char *source)
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char cell1[200], cell2[200];
|
||||
char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
|
||||
|
||||
Debug = 0;
|
||||
if (argc != 1) {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ along with this program; see the file copying. If not, write to
|
|||
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* netcomp.c -- a simple wrapper to provide netlist comparison functionality */
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "netgen.h"
|
||||
|
|
@ -51,7 +52,7 @@ void STRCPY(char *dest, char *source)
|
|||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifndef HAVE_GETOPT
|
||||
char cell1[200], cell2[200];
|
||||
char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
|
||||
int filenum = -1;
|
||||
|
||||
Debug = 0;
|
||||
|
|
@ -67,7 +68,7 @@ int main(int argc, char *argv[])
|
|||
STRCPY(cell2, ReadNetlist(argv[2], &filenum));
|
||||
if (argc == 5) STRCPY(cell2, argv[4]); /* if explicit cell name specified */
|
||||
#else
|
||||
char cell1[200], cell2[200];
|
||||
char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
|
||||
int usage = 0;
|
||||
int args;
|
||||
int c;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
#include <stdlib.h> /* for getenv */
|
||||
#endif
|
||||
#include "netgen.h"
|
||||
#include "print.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,9 +20,11 @@ along with this program; see the file copying. If not, write to
|
|||
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* ntk2xnf.c -- a simple wrapper to translate .ntk to Xilinx XNF format */
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "netgen.h"
|
||||
#include "xilinx.h"
|
||||
|
||||
#ifdef HAVE_X11
|
||||
/* the following two X procedures are to permit linking
|
||||
|
|
@ -47,7 +49,7 @@ void STRCPY(char *dest, char *source)
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char cellname[200];
|
||||
char cellname[MAX_STR_LEN];
|
||||
int filenum = -1;
|
||||
|
||||
Debug = 0;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -668,7 +668,6 @@ XMKMF
|
|||
HAVE_PYTHON3
|
||||
EGREP
|
||||
GREP
|
||||
M4
|
||||
RANLIB
|
||||
INSTALL_DATA
|
||||
INSTALL_SCRIPT
|
||||
|
|
@ -712,6 +711,7 @@ infodir
|
|||
docdir
|
||||
oldincludedir
|
||||
includedir
|
||||
runstatedir
|
||||
localstatedir
|
||||
sharedstatedir
|
||||
sysconfdir
|
||||
|
|
@ -794,6 +794,7 @@ datadir='${datarootdir}'
|
|||
sysconfdir='${prefix}/etc'
|
||||
sharedstatedir='${prefix}/com'
|
||||
localstatedir='${prefix}/var'
|
||||
runstatedir='${localstatedir}/run'
|
||||
includedir='${prefix}/include'
|
||||
oldincludedir='/usr/include'
|
||||
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
|
||||
|
|
@ -1046,6 +1047,15 @@ do
|
|||
| -silent | --silent | --silen | --sile | --sil)
|
||||
silent=yes ;;
|
||||
|
||||
-runstatedir | --runstatedir | --runstatedi | --runstated \
|
||||
| --runstate | --runstat | --runsta | --runst | --runs \
|
||||
| --run | --ru | --r)
|
||||
ac_prev=runstatedir ;;
|
||||
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
|
||||
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
|
||||
| --run=* | --ru=* | --r=*)
|
||||
runstatedir=$ac_optarg ;;
|
||||
|
||||
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
|
||||
ac_prev=sbindir ;;
|
||||
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
|
||||
|
|
@ -1183,7 +1193,7 @@ fi
|
|||
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
|
||||
datadir sysconfdir sharedstatedir localstatedir includedir \
|
||||
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
|
||||
libdir localedir mandir
|
||||
libdir localedir mandir runstatedir
|
||||
do
|
||||
eval ac_val=\$$ac_var
|
||||
# Remove trailing slashes.
|
||||
|
|
@ -1336,6 +1346,7 @@ Fine tuning of the installation directories:
|
|||
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
|
||||
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
|
||||
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
|
||||
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
|
||||
--libdir=DIR object code libraries [EPREFIX/lib]
|
||||
--includedir=DIR C header files [PREFIX/include]
|
||||
--oldincludedir=DIR C header files for non-gcc [/usr/include]
|
||||
|
|
@ -3690,56 +3701,6 @@ else
|
|||
fi
|
||||
|
||||
|
||||
for ac_prog in gm4 gnum4 m4
|
||||
do
|
||||
# Extract the first word of "$ac_prog", so it can be a program name with args.
|
||||
set dummy $ac_prog; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_path_M4+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
case $M4 in
|
||||
[\\/]* | ?:[\\/]*)
|
||||
ac_cv_path_M4="$M4" # Let the user override the test with a path.
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_path_M4="$as_dir/$ac_word$ac_exec_ext"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
M4=$ac_cv_path_M4
|
||||
if test -n "$M4"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $M4" >&5
|
||||
$as_echo "$M4" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
test -n "$M4" && break
|
||||
done
|
||||
test -n "$M4" || M4="no"
|
||||
|
||||
if test x$M4 = xno; then
|
||||
as_fn_error $? "M4 is required" "$LINENO" 5
|
||||
fi
|
||||
|
||||
|
||||
if test "$CPP" = "$CC -E" ; then
|
||||
CPP="$CPP -x c"
|
||||
|
|
@ -6065,7 +6026,6 @@ fi
|
|||
|
||||
|
||||
if test $usingTcl ; then
|
||||
usingX11=1
|
||||
cadinstall="$cadinstall tcltk"
|
||||
modules="$modules tcltk"
|
||||
programs="$programs tcltk"
|
||||
|
|
@ -6075,7 +6035,11 @@ if test $usingTcl ; then
|
|||
|
||||
extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o"
|
||||
extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\""
|
||||
stub_defs="$stub_defs -DUSE_TCL_STUBS -DUSE_TK_STUBS"
|
||||
if test $usingX11 ; then
|
||||
stub_defs="$stub_defs -DUSE_TCL_STUBS"
|
||||
else
|
||||
stub_defs="$stub_defs -DUSE_TCL_STUBS -DUSE_TK_STUBS"
|
||||
fi
|
||||
else
|
||||
programs="$programs netgen"
|
||||
unused="$unused tcltk"
|
||||
|
|
@ -6160,6 +6124,7 @@ if test $usingTcl ; then
|
|||
# Tk libraries and header files
|
||||
#
|
||||
# -----------------------------------------------------------------------
|
||||
if test $usingX11 ; then
|
||||
if test "${TK_INC_DIR}" != "/usr/include" ; then
|
||||
INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}"
|
||||
fi
|
||||
|
|
@ -6176,6 +6141,7 @@ if test $usingTcl ; then
|
|||
loader_run_path="${TK_LIB_DIR}:${loader_run_path}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
#
|
||||
|
|
@ -6285,7 +6251,7 @@ if test $usingTcl ; then
|
|||
|
||||
*darwin*)
|
||||
SHDLIB_EXT=".dylib"
|
||||
LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind"
|
||||
LDDL_FLAGS="-dynamiclib -undefined dynamic_lookup"
|
||||
LDFLAGS="${LDFLAGS} ${LIB_SPECS}"
|
||||
CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common"
|
||||
;;
|
||||
|
|
|
|||
|
|
@ -26,12 +26,6 @@ AC_ISC_POSIX
|
|||
AC_PROG_INSTALL
|
||||
AC_PROG_RANLIB
|
||||
|
||||
dnl GNU M4 is preferred due to some of the option switches.
|
||||
AC_PATH_PROGS([M4], [gm4 gnum4 m4], [no])
|
||||
if test x$M4 = xno; then
|
||||
AC_MSG_ERROR([M4 is required])
|
||||
fi
|
||||
|
||||
dnl check size of pointer for correct behavior on 64-bit systems
|
||||
dnl If the C preprocessor is GCC, we need to force the flag to
|
||||
dnl assert that input files are of type C, or else the preprocessing
|
||||
|
|
@ -807,7 +801,6 @@ dnl "make" instead of requiring "make tcl"
|
|||
dnl ----------------------------------------------------------------
|
||||
|
||||
if test $usingTcl ; then
|
||||
usingX11=1
|
||||
cadinstall="$cadinstall tcltk"
|
||||
modules="$modules tcltk"
|
||||
programs="$programs tcltk"
|
||||
|
|
@ -816,7 +809,11 @@ if test $usingTcl ; then
|
|||
AC_DEFINE(TCL_NETGEN)
|
||||
extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o"
|
||||
extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\""
|
||||
stub_defs="$stub_defs -DUSE_TCL_STUBS -DUSE_TK_STUBS"
|
||||
if test $usingX11 ; then
|
||||
stub_defs="$stub_defs -DUSE_TCL_STUBS"
|
||||
else
|
||||
stub_defs="$stub_defs -DUSE_TCL_STUBS -DUSE_TK_STUBS"
|
||||
fi
|
||||
else
|
||||
programs="$programs netgen"
|
||||
unused="$unused tcltk"
|
||||
|
|
@ -903,6 +900,7 @@ if test $usingTcl ; then
|
|||
# Tk libraries and header files
|
||||
#
|
||||
# -----------------------------------------------------------------------
|
||||
if test $usingX11 ; then
|
||||
if test "${TK_INC_DIR}" != "/usr/include" ; then
|
||||
INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}"
|
||||
fi
|
||||
|
|
@ -919,6 +917,7 @@ if test $usingTcl ; then
|
|||
loader_run_path="${TK_LIB_DIR}:${loader_run_path}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
#
|
||||
|
|
@ -1028,7 +1027,7 @@ if test $usingTcl ; then
|
|||
|
||||
*darwin*)
|
||||
SHDLIB_EXT=".dylib"
|
||||
LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind"
|
||||
LDDL_FLAGS="-dynamiclib -undefined dynamic_lookup"
|
||||
LDFLAGS="${LDFLAGS} ${LIB_SPECS}"
|
||||
CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common"
|
||||
;;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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@
|
||||
|
|
|
|||
|
|
@ -62,16 +62,18 @@ proc netgen::convert_to_json {filename lvs_final} {
|
|||
puts $fjson " \["
|
||||
set cktval [lindex $value 0]
|
||||
foreach pin [lrange $cktval 0 end-1] {
|
||||
puts $fjson " \"$pin\","
|
||||
set pinstr [string map {"\\" "\\\\"} $pin]
|
||||
puts $fjson " \"$pinstr\","
|
||||
}
|
||||
set pin [lindex $cktval end]
|
||||
set pin [string map {"\\" "\\\\"} [lindex $cktval end]]
|
||||
puts $fjson " \"$pin\""
|
||||
puts $fjson " \], \["
|
||||
set cktval [lindex $value 1]
|
||||
foreach pin [lrange $cktval 0 end-1] {
|
||||
puts $fjson " \"$pin\","
|
||||
set pinstr [string map {"\\" "\\\\"} $pin]
|
||||
puts $fjson " \"$pinstr\","
|
||||
}
|
||||
set pin [lindex $cktval end]
|
||||
set pin [string map {"\\" "\\\\"} [lindex $cktval end]]
|
||||
puts $fjson " \"$pin\""
|
||||
puts $fjson " \]"
|
||||
if {$kidx == $nkeys} {
|
||||
|
|
@ -393,7 +395,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
|||
# If argument is a filename then read the list of cells from it;
|
||||
# otherwise, argument is the list of files itself in quotes or
|
||||
# braces.
|
||||
if {![catch {file exists $value}]} {
|
||||
if {[file exists $value]} {
|
||||
if {![catch {open $value r} fnf]} {
|
||||
while {[gets $fnf line] >= 0} {
|
||||
if {[lindex $line 0] != "#"} {
|
||||
|
|
@ -427,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]
|
||||
|
|
@ -444,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]
|
||||
|
|
@ -459,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
|
||||
|
|
@ -467,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
|
||||
|
|
@ -475,10 +477,26 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
|||
set cell2 [lindex $clist2 $cidx]
|
||||
}
|
||||
|
||||
# The "noflat" list is non-file-specific, so run on each file.
|
||||
foreach cell $noflat {
|
||||
set cidx [lsearch -regexp $clist1 ^$cell$]
|
||||
if {$cidx >= 0} {
|
||||
netgen::flatten prohibit "$fnum1 $cell"
|
||||
}
|
||||
set cidx [lsearch -regexp $clist2 ^$cell$]
|
||||
if {$cidx >= 0} {
|
||||
netgen::flatten prohibit "$fnum2 $cell"
|
||||
}
|
||||
}
|
||||
|
||||
netgen::compare assign "$fnum1 $cell1" "$fnum2 $cell2"
|
||||
|
||||
if {[file exists $setupfile]} {
|
||||
puts stdout "Reading setup file $setupfile"
|
||||
if {$setupfile == ""} {
|
||||
puts stdout "\nNo setup file specified. Using trivial default setup.\n"
|
||||
netgen::permute default ;# transistors and resistors
|
||||
netgen::property default
|
||||
} elseif {[file exists $setupfile]} {
|
||||
puts stdout "\nReading setup file $setupfile\n"
|
||||
# Instead of sourcing the setup file, run each line so we can
|
||||
# catch individual errors and not let them halt the LVS process
|
||||
set perrors 0
|
||||
|
|
@ -498,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"
|
||||
}
|
||||
|
|
@ -506,8 +532,10 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
|||
puts stdout "Warning: There were errors reading the setup file"
|
||||
}
|
||||
} elseif {[string first nosetup $setupfile] < 0} {
|
||||
netgen::permute default ;# transistors and resistors
|
||||
netgen::property default
|
||||
puts stderr "\nError: Setup file $setupfile does not exist.\n"
|
||||
return
|
||||
} else {
|
||||
puts stderr "\nNo setup file specified. Continuing without a setup.\n"
|
||||
}
|
||||
|
||||
if {[string first nolog $logfile] < 0} {
|
||||
|
|
@ -532,14 +560,24 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
|||
}
|
||||
set properr {}
|
||||
set matcherr {}
|
||||
set pinsgood -1
|
||||
set childMismatch 0 ;# 1 indicates black-box child subcircuit mismatch
|
||||
while {$endval != {}} {
|
||||
if {$dolist == 1} {
|
||||
netgen::run -list converge
|
||||
} else {
|
||||
netgen::run converge
|
||||
}
|
||||
netgen::log echo on
|
||||
set pinMismatch 0 ;# indicates pin mismatch in top cell
|
||||
set doCheckFlatten 0
|
||||
set doFlatten 0
|
||||
if {[netgen::print queue] == {}} {
|
||||
set doEquatePins 1 ;# run equate pins on top cell
|
||||
} else {
|
||||
set doEquatePins 0 ;# don't run equate pins unless unique match
|
||||
}
|
||||
set forceMatch 0 ;# for pin matching
|
||||
netgen::log echo off
|
||||
|
||||
if {[verify equivalent]} {
|
||||
# Resolve automorphisms by pin and property
|
||||
if {$dolist == 1} {
|
||||
|
|
@ -548,96 +586,113 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
|||
netgen::run resolve
|
||||
}
|
||||
set uresult [verify unique]
|
||||
# uresult: -3 : unique with property error
|
||||
# -2 : equivalent with port errors
|
||||
# -1 : black box
|
||||
# 0 : equivalent but not unique
|
||||
# 1 : unique
|
||||
if {$uresult == 0} {
|
||||
netgen::log echo on
|
||||
netgen::log put " Networks match locally but not globally.\n"
|
||||
netgen::log put " Probably connections are swapped.\n"
|
||||
netgen::log put " Check the end of logfile ${logfile} for implicated nodes.\n"
|
||||
netgen::log echo off
|
||||
if {$dolist == 1} {
|
||||
verify -list nodes
|
||||
} else {
|
||||
verify nodes
|
||||
}
|
||||
|
||||
# Flatten the non-matching subcircuit (but not the top-level cells)
|
||||
if {[netgen::print queue] != {}} {
|
||||
if {([lsearch $noflat [lindex $endval 0]] == -1) &&
|
||||
([lsearch $noflat [lindex $endval 1]] == -1)} {
|
||||
netgen::log put " Flattening non-matched subcircuits $endval\n"
|
||||
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||
netgen::flatten class "[lindex $endval 1] $fnum2"
|
||||
} else {
|
||||
netgen::log put " Continuing with black-boxed subcircuits $endval\n"
|
||||
lappend matcherr [lindex $endval 0]"($fnum1)"
|
||||
lappend matcherr [lindex $endval 1]"($fnum2)"
|
||||
# Match pins
|
||||
netgen::log echo off
|
||||
if {$dolist == 1} {
|
||||
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
} else {
|
||||
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
}
|
||||
if {$result != 0} {
|
||||
equate classes "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"
|
||||
}
|
||||
set pinsgood $result
|
||||
netgen::log echo on
|
||||
}
|
||||
}
|
||||
set doCheckFlatten 1
|
||||
} else {
|
||||
netgen::log echo off
|
||||
if {$dolist == 1} {
|
||||
set result [equate -list pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
} else {
|
||||
set result [equate pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
}
|
||||
if {$result != 0} {
|
||||
equate classes "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"
|
||||
}
|
||||
# If $uresult == -1 then these are black-box entries and
|
||||
# $pinsgood should not be set to the resulting value.
|
||||
if {$uresult > 0} {
|
||||
set pinsgood $result
|
||||
}
|
||||
netgen::log echo on
|
||||
# Equate pins for black boxes, unique matches (possibly with property
|
||||
# errors), and unique with port errors
|
||||
set doEquatePins 1
|
||||
}
|
||||
if {$uresult == -1} { ;# black box
|
||||
set forceMatch 1
|
||||
} elseif {$uresult == -3} { ;# property error
|
||||
lappend properr [lindex $endval 0]
|
||||
} elseif {$uresult == -2} { ;# unmatched pins
|
||||
set doCheckFlatten 1
|
||||
} elseif {$uresult == -4} { ;# unmatched pins and properties
|
||||
lappend properr [lindex $endval 0]
|
||||
set doCheckFlatten 1
|
||||
}
|
||||
if {$uresult == 2} {lappend properr [lindex $endval 0]}
|
||||
} else {
|
||||
# Flatten the non-matching subcircuit (but not the top-level cells)
|
||||
if {[netgen::print queue] != {}} {
|
||||
# not equivalent
|
||||
netgen::log echo on
|
||||
# netgen::log put " DEBUG: not equivalent $endval\n"
|
||||
netgen::log echo off
|
||||
set doCheckFlatten 1
|
||||
}
|
||||
if {$doCheckFlatten} {
|
||||
# Flatten the non-matching subcircuit (but not the top-level cell,
|
||||
# or cells explicitly prohibited from flattening)
|
||||
if {[netgen::print queue] != {}} {
|
||||
if {([lsearch $noflat [lindex $endval 0]] == -1) &&
|
||||
([lsearch $noflat [lindex $endval 1]] == -1)} {
|
||||
netgen::log put " Flattening non-matched subcircuits $endval\n"
|
||||
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||
netgen::flatten class "[lindex $endval 1] $fnum2"
|
||||
([lsearch $noflat [lindex $endval 1]] == -1)} {
|
||||
set doFlatten 1
|
||||
} else {
|
||||
netgen::log echo on
|
||||
netgen::log put " Continuing with black-boxed subcircuits $endval\n"
|
||||
netgen::log echo off
|
||||
lappend matcherr [lindex $endval 0]"($fnum1)"
|
||||
lappend matcherr [lindex $endval 0]"($fnum2)"
|
||||
# Match pins
|
||||
netgen::log echo off
|
||||
if {$dolist == 1} {
|
||||
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
} else {
|
||||
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
}
|
||||
if {$result != 0} {
|
||||
equate classes "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"
|
||||
}
|
||||
set pinsgood $result
|
||||
netgen::log echo on
|
||||
lappend matcherr [lindex $endval 1]"($fnum2)"
|
||||
netgen::flatten prohibit "[lindex $endval 0] $fnum1"
|
||||
netgen::flatten prohibit "[lindex $endval 1] $fnum2"
|
||||
set doEquatePins 1
|
||||
set childMismatch 1
|
||||
set forceMatch 1
|
||||
}
|
||||
}
|
||||
}
|
||||
netgen::log echo off
|
||||
if {$doEquatePins} {
|
||||
# Match pins
|
||||
if {$dolist == 1} {
|
||||
if {$forceMatch} {
|
||||
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
} else {
|
||||
set result [equate -list pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
}
|
||||
} else {
|
||||
if {$forceMatch} {
|
||||
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
} else {
|
||||
set result [equate pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
}
|
||||
}
|
||||
if {$result >= 0} {
|
||||
equate classes "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"
|
||||
}
|
||||
# Do not set pinMismatch for black boxes
|
||||
if {$result < 0} {
|
||||
if {$result == -1 && [netgen::print queue] != {} && $forceMatch != 1} {
|
||||
# flatten pin mismatch, but not empty cells (-2) or top cell or
|
||||
# cells prohibited from flattening.
|
||||
set doFlatten 1
|
||||
}
|
||||
} 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} {
|
||||
netgen::log echo on
|
||||
netgen::log put " Flattening non-matched subcircuits $endval\n"
|
||||
netgen::log echo off
|
||||
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||
netgen::flatten class "[lindex $endval 1] $fnum2"
|
||||
}
|
||||
|
||||
if {$dolist == 1} {
|
||||
catch {lappend lvs_final $lvs_out}
|
||||
set lvs_out {}
|
||||
|
|
@ -646,20 +701,23 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
|||
set endval [netgen::compare hierarchical]
|
||||
}
|
||||
}
|
||||
netgen::log echo off
|
||||
puts stdout "Result: " nonewline
|
||||
netgen::log echo on
|
||||
if {$pinsgood == 0} {
|
||||
# NOTE: Need to disambiguate these two cases. . .
|
||||
netgen::log put "Cells failed matching, or top level cell failed pin matching.\n"
|
||||
netgen::log put "\nFinal result: "
|
||||
if {$pinMismatch || $childMismatch} {
|
||||
if {$childMismatch} {
|
||||
netgen::log put "Subcell(s) failed matching.\n"
|
||||
}
|
||||
if {$pinMismatch} {
|
||||
netgen::log put "Top level cell failed pin matching.\n"
|
||||
}
|
||||
} else {
|
||||
verify only
|
||||
}
|
||||
if {$properr != {}} {
|
||||
netgen::log put "The following cells had property errors:\n " [regsub -all { } $properr "\n "] "\n"
|
||||
netgen::log put "\nThe following cells had property errors:\n " [regsub -all { } $properr "\n "] "\n"
|
||||
}
|
||||
if {$matcherr != {}} {
|
||||
netgen::log put "The following subcells failed to match:\n " [regsub -all { } $matcherr "\n "] "\n"
|
||||
netgen::log put "\nThe following subcells failed to match:\n " [regsub -all { } $matcherr "\n "] "\n"
|
||||
}
|
||||
if {$dolog} {
|
||||
netgen::log end
|
||||
|
|
@ -711,6 +769,19 @@ set auto_noexec 1 ;# don't EVER call UNIX commands w/o "shell" in front
|
|||
# Cross-Application section
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
# For use with open_pdks, set PDK_ROOT from the environment. If no
|
||||
# such environment variable exists, check some common locations.
|
||||
|
||||
if {[catch {set PDK_ROOT $::env(PDK_ROOT)}]} {
|
||||
if {[file isdir /usr/local/share/pdk] == 1} {
|
||||
set PDK_ROOT /usr/local/share/pdk
|
||||
} elseif {[file isdir /usr/share/pdk] == 1} {
|
||||
set PDK_ROOT /usr/share/pdk
|
||||
} elseif {[file isdir /foss/pdk] == 1} {
|
||||
set PDK_ROOT /foss/pdk
|
||||
}
|
||||
}
|
||||
|
||||
# Setup IRSIM assuming that the Tcl version is installed.
|
||||
# We do not need to rename procedure irsim to NULL because it is
|
||||
# redefined in a script, which simply overwrites the original.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
115
tcltk/tkcon.tcl
115
tcltk/tkcon.tcl
|
|
@ -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}
|
||||
|
|
@ -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
|
||||
|
|
@ -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]}"
|
||||
}
|
||||
}
|
||||
|
|
@ -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]
|
||||
|
|
@ -2798,13 +2793,19 @@ proc tkcon_puts 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
|
||||
|
|
@ -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
|
||||
|
|
@ -4134,6 +4174,9 @@ proc ::tkcon::Bindings {} {
|
|||
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]} {
|
||||
|
|
|
|||
Loading…
Reference in New Issue