Compare commits
57 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
b826870be9 | |
|
|
ed5276d67b | |
|
|
69c9d85be7 | |
|
|
ad05d059c7 | |
|
|
1b2cd1497c | |
|
|
d9d5a46c6e | |
|
|
d73b711e3a | |
|
|
1428580109 | |
|
|
210dfb25c3 | |
|
|
27f2ab8b3f | |
|
|
1be00bbd99 | |
|
|
03b241a5d4 | |
|
|
43cebd1ef9 | |
|
|
0490959b07 | |
|
|
dc841f3293 | |
|
|
05bcfede69 | |
|
|
72ed78e55a | |
|
|
59bb8a89c0 | |
|
|
9bdaee652e | |
|
|
9879b58f83 | |
|
|
9e3b705fcc | |
|
|
d2c9129242 | |
|
|
942f421fa3 | |
|
|
6bc948d8ba | |
|
|
c1ad37f05a | |
|
|
9edefe7d59 | |
|
|
f6b9629521 | |
|
|
7b2e01f2af | |
|
|
224050f153 | |
|
|
74e8c3e168 | |
|
|
95a29fcd8c | |
|
|
723a950fd3 | |
|
|
e3368cb22a | |
|
|
f06e6548bb | |
|
|
72ed19ff36 | |
|
|
39b8e3d14a | |
|
|
b63dfa8638 | |
|
|
f918f33c51 | |
|
|
63b2e48ea1 | |
|
|
6e63f49d53 | |
|
|
419b6de29a | |
|
|
205cf2aa58 | |
|
|
52b6766fc8 | |
|
|
7b0bdd29e8 | |
|
|
433cbd090a | |
|
|
3087bd3337 | |
|
|
b79a29d662 | |
|
|
bf9c61e412 | |
|
|
8d34bd372d | |
|
|
229c2931a8 | |
|
|
b8da97deb1 | |
|
|
b7187d5899 | |
|
|
d27d441c58 | |
|
|
48c9e6b292 | |
|
|
ced5846da3 | |
|
|
b99d33064f | |
|
|
399472e940 |
|
|
@ -1,40 +0,0 @@
|
||||||
# This is a basic workflow to help you get started with Actions
|
|
||||||
|
|
||||||
name: CI
|
|
||||||
|
|
||||||
# Controls when the workflow will run
|
|
||||||
on:
|
|
||||||
# Triggers the workflow on push or pull request events but only for the master branch
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
# Allows you to run this workflow manually from the Actions tab
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
|
||||||
jobs:
|
|
||||||
# This workflow contains a single job called "build"
|
|
||||||
build:
|
|
||||||
# The type of runner that the job will run on
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
|
||||||
steps:
|
|
||||||
# Runs a set of commands using the runners shell
|
|
||||||
#- name: Logging into Dockerhub
|
|
||||||
# run: docker login -u ${{ secrets.DOCKERHUB_USERNAME }} -p ${{ secrets.DOCKERHUB_PASSWORD }}
|
|
||||||
|
|
||||||
- name: Pulling the docker image
|
|
||||||
run: docker pull vezzal/vezzal:v1
|
|
||||||
|
|
||||||
- name: Start the container with the docker image
|
|
||||||
run: docker run -id --name test_netgen vezzal/vezzal:v1 bash | exit
|
|
||||||
|
|
||||||
- name: Run the testing on the container and send the mail
|
|
||||||
run: docker exec test_netgen /vezzal/test_netgen.sh "tim@opencircuitdesign.com,lankasaicharan123@gmail.com" ${{ secrets.MAILING_KEY }}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -7,11 +7,8 @@ config.log
|
||||||
scripts/config.log
|
scripts/config.log
|
||||||
config.status
|
config.status
|
||||||
scripts/config.status
|
scripts/config.status
|
||||||
python/lvs_manager.py
|
|
||||||
*.o
|
*.o
|
||||||
*.so
|
*.so
|
||||||
*~
|
*~
|
||||||
*.log
|
*.log
|
||||||
UPDATE_ME
|
UPDATE_ME
|
||||||
tcltk/netgen.sh
|
|
||||||
tcltk/netgen.tcl
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,4 @@
|
||||||

|
NETGEN: VERSION 1.5
|
||||||
|
|
||||||
# NETGEN
|
|
||||||
|
|
||||||
### VERSION 1.5
|
|
||||||
|
|
||||||
NETGEN is a general-purpose netlist management system. It can read
|
NETGEN is a general-purpose netlist management system. It can read
|
||||||
and write several netlist formats, including NTK (Caltech, CMU),
|
and write several netlist formats, including NTK (Caltech, CMU),
|
||||||
|
|
@ -91,49 +87,6 @@ and IRSIM version 9.7:
|
||||||
|
|
||||||
Note: For FreeBSD, use 'gmake' instead.
|
Note: For FreeBSD, use 'gmake' instead.
|
||||||
|
|
||||||
Note: On MacOS (Big Sur) follow the following procedure. If you have installed `xschem` and `magic` already on MacOS then steps (1) and (2) can likely be skipped.
|
|
||||||
|
|
||||||
**1) Build Tcl for X11**
|
|
||||||
|
|
||||||
We are following the instructions from `xschem` (https://github.com/StefanSchippers/xschem/blob/master/README_MacOS.md).
|
|
||||||
|
|
||||||
* Download `Tcl` from https://prdownloads.sourceforge.net/tcl/tcl8.6.10-src.tar.gz
|
|
||||||
|
|
||||||
We are using not `opt` but `opt2` so that this `Tcl` does not interfere with `tcl-tk` from HomeBrew.
|
|
||||||
|
|
||||||
```
|
|
||||||
./configure --prefix=/usr/local/opt2/tcl-tk
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
```
|
|
||||||
|
|
||||||
**2) Build Tk for X11**
|
|
||||||
|
|
||||||
* Download `Tk` from https://prdownloads.sourceforge.net/tcl/tk8.6.10-src.tar.gz
|
|
||||||
|
|
||||||
```
|
|
||||||
./configure --prefix=/usr/local/opt2/tcl-tk \
|
|
||||||
--with-tcl=/usr/local/opt2/tcl-tk/lib --with-x \
|
|
||||||
--x-includes=/opt/X11/include --x-libraries=/opt/X11/lib
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
```
|
|
||||||
|
|
||||||
**3) Build netgen**
|
|
||||||
|
|
||||||
We need to provide this custom-built `tcl-tk` and suppress compilation errors.
|
|
||||||
|
|
||||||
```
|
|
||||||
./configure --with-tcl=/usr/local/opt2/tcl-tk/lib \
|
|
||||||
--with-tk=/usr/local/opt2/tcl-tk/lib \
|
|
||||||
--x-includes=/opt/X11/include \
|
|
||||||
--x-libraries=/opt/X11/lib \
|
|
||||||
CFLAGS=-Wno-error=implicit-function-declaration
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
IN CASE OF FAILURE
|
IN CASE OF FAILURE
|
||||||
-------------------
|
-------------------
|
||||||
Please contact me (tim@opencircuitdesign.com) to report compile-time and
|
Please contact me (tim@opencircuitdesign.com) to report compile-time and
|
||||||
|
|
@ -22,7 +22,6 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <strings.h>
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#ifdef IBMPC
|
#ifdef IBMPC
|
||||||
#include <stdlib.h> /* for strtol on PC */
|
#include <stdlib.h> /* for strtol on PC */
|
||||||
|
|
@ -91,7 +90,7 @@ char *ActelName(char *Name)
|
||||||
/* strip physical-pin information, if it exists */
|
/* strip physical-pin information, if it exists */
|
||||||
if ((nm = strrchr(name,PHYSICALPIN[0])) != NULL) *nm = '\0';
|
if ((nm = strrchr(name,PHYSICALPIN[0])) != NULL) *nm = '\0';
|
||||||
if (strlen(name) > 13) {
|
if (strlen(name) > 13) {
|
||||||
ActelIndex = (ActelIndex + 1) % ACTELNAMESIZE;
|
ActelIndex = (++ActelIndex) % ACTELNAMESIZE;
|
||||||
/* format the value of the hashed value of the string */
|
/* format the value of the hashed value of the string */
|
||||||
sprintf(ActelNames[ActelIndex], "$%lX", ActelNameHash(name));
|
sprintf(ActelNames[ActelIndex], "$%lX", ActelNameHash(name));
|
||||||
if (Debug)
|
if (Debug)
|
||||||
|
|
@ -102,7 +101,7 @@ Printf("ActelNameHash returns %s on name %s\n",ActelNames[ActelIndex], name);
|
||||||
NeedsQuoting = 0;
|
NeedsQuoting = 0;
|
||||||
if (NULL != strpbrk(name, ".,:; \t\"'\n\r")) NeedsQuoting = 1;
|
if (NULL != strpbrk(name, ".,:; \t\"'\n\r")) NeedsQuoting = 1;
|
||||||
|
|
||||||
ActelIndex = (ActelIndex + 1) % ACTELNAMESIZE;
|
ActelIndex = (++ActelIndex) % ACTELNAMESIZE;
|
||||||
if (!NeedsQuoting) {
|
if (!NeedsQuoting) {
|
||||||
strcpy(ActelNames[ActelIndex], name);
|
strcpy(ActelNames[ActelIndex], name);
|
||||||
return(ActelNames[ActelIndex]);
|
return(ActelNames[ActelIndex]);
|
||||||
|
|
@ -132,7 +131,7 @@ if format = 1, use the actel .pin file format
|
||||||
struct nlist *tp;
|
struct nlist *tp;
|
||||||
struct objlist *ob, *ob2;
|
struct objlist *ob, *ob2;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
char physicalpin[MAX_STR_LEN];
|
char physicalpin[200];
|
||||||
|
|
||||||
tp = LookupCell(name);
|
tp = LookupCell(name);
|
||||||
if (tp == NULL) return;
|
if (tp == NULL) return;
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,4 @@ extern int open(char *path, int oflag, ...); /* HPUX has it in <sys/fcntl.h> */
|
||||||
#define FALSE 0
|
#define FALSE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_STR_LEN 256
|
|
||||||
|
|
||||||
#endif /* _CONFIG_H */
|
#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)
|
int LenEmbed(char *prefix, struct nlist *np, struct embed *E, int flatten)
|
||||||
/* return the number of characters required to print element E */
|
/* return the number of characters required to print element E */
|
||||||
{
|
{
|
||||||
char longstr[MAX_STR_LEN];
|
char longstr[200];
|
||||||
|
|
||||||
if (E == NULL) return(0);
|
if (E == NULL) return(0);
|
||||||
if (E->left == NULL && E->right == NULL) {
|
if (E->left == NULL && E->right == NULL) {
|
||||||
|
|
@ -668,7 +668,7 @@ void PrintEmb(FILE *outfile, char *prefix, struct nlist *np,
|
||||||
struct objlist *ob;
|
struct objlist *ob;
|
||||||
char *instancename;
|
char *instancename;
|
||||||
struct nlist *np2;
|
struct nlist *np2;
|
||||||
char name[MAX_STR_LEN];
|
char name[200];
|
||||||
|
|
||||||
ob = InstanceNumber(np,E->instancenumber);
|
ob = InstanceNumber(np,E->instancenumber);
|
||||||
instancename = ob->instance.name;
|
instancename = ob->instance.name;
|
||||||
|
|
@ -706,7 +706,7 @@ void PrintEmbed(FILE *outfile, char *prefix, struct nlist *np,
|
||||||
struct objlist *ob;
|
struct objlist *ob;
|
||||||
char *instancename;
|
char *instancename;
|
||||||
struct nlist *np2;
|
struct nlist *np2;
|
||||||
char name[MAX_STR_LEN];
|
char name[200];
|
||||||
|
|
||||||
ob = InstanceNumber(np,E->instancenumber);
|
ob = InstanceNumber(np,E->instancenumber);
|
||||||
instancename = ob->instance.name;
|
instancename = ob->instance.name;
|
||||||
|
|
|
||||||
358
base/ext.c
358
base/ext.c
|
|
@ -23,15 +23,12 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h> /* for strtod() */
|
#include <stdlib.h> /* for strtod() */
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#include "netgen.h"
|
#include "netgen.h"
|
||||||
|
#include "hash.h"
|
||||||
#include "objlist.h"
|
#include "objlist.h"
|
||||||
#include "netfile.h"
|
#include "netfile.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "hash.h"
|
|
||||||
|
|
||||||
static int invlambda = 100; /* Used in sim and prm files */
|
|
||||||
|
|
||||||
void extCell(char *name, int filenum)
|
void extCell(char *name, int filenum)
|
||||||
{
|
{
|
||||||
|
|
@ -169,7 +166,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
||||||
int filenum;
|
int filenum;
|
||||||
|
|
||||||
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
|
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
|
||||||
char name[MAX_STR_LEN];
|
char name[100];
|
||||||
|
|
||||||
SetExtension(name, fname, EXT_EXTENSION);
|
SetExtension(name, fname, EXT_EXTENSION);
|
||||||
if ((filenum = OpenParseFile(name, *fnum)) < 0) {
|
if ((filenum = OpenParseFile(name, *fnum)) < 0) {
|
||||||
|
|
@ -189,7 +186,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
||||||
/* Make sure all .ext file reading is case sensitive */
|
/* Make sure all .ext file reading is case sensitive */
|
||||||
matchfunc = match;
|
matchfunc = match;
|
||||||
matchintfunc = matchfile;
|
matchintfunc = matchfile;
|
||||||
hashfunc = hashcase;
|
hashfunc = hash;
|
||||||
|
|
||||||
if (LookupCellFile(fname, filenum) != NULL) {
|
if (LookupCellFile(fname, filenum) != NULL) {
|
||||||
Printf("Error: Duplicate cell name \"%s\"!\n", fname);
|
Printf("Error: Duplicate cell name \"%s\"!\n", fname);
|
||||||
|
|
@ -210,7 +207,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
||||||
else if (match(nexttok, "style")) SkipNewLine(NULL);
|
else if (match(nexttok, "style")) SkipNewLine(NULL);
|
||||||
else if (match(nexttok, "resistclasses")) SkipNewLine(NULL);
|
else if (match(nexttok, "resistclasses")) SkipNewLine(NULL);
|
||||||
else if (match(nexttok, "node")) {
|
else if (match(nexttok, "node")) {
|
||||||
char name[MAX_STR_LEN];
|
char name[200];
|
||||||
|
|
||||||
/* No cell is generated until at least one valid "node" or "use" */
|
/* No cell is generated until at least one valid "node" or "use" */
|
||||||
/* has been read in the file. */
|
/* has been read in the file. */
|
||||||
|
|
@ -225,8 +222,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
||||||
SkipNewLine(NULL);
|
SkipNewLine(NULL);
|
||||||
}
|
}
|
||||||
else if (match(nexttok, "equiv")) {
|
else if (match(nexttok, "equiv")) {
|
||||||
char name[MAX_STR_LEN];
|
char name[200];
|
||||||
char name2[MAX_STR_LEN];
|
char name2[200];
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
GetExtName(name, nexttok);
|
GetExtName(name, nexttok);
|
||||||
if (LookupObject(name,CurrentCell) == NULL) Node(name);
|
if (LookupObject(name,CurrentCell) == NULL) Node(name);
|
||||||
|
|
@ -237,8 +234,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
||||||
SkipNewLine(NULL);
|
SkipNewLine(NULL);
|
||||||
}
|
}
|
||||||
else if (match(nexttok, "device")) {
|
else if (match(nexttok, "device")) {
|
||||||
char dev_name[MAX_STR_LEN], dev_class[MAX_STR_LEN];
|
char dev_name[100], dev_class[100];
|
||||||
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN], subs[MAX_STR_LEN];
|
char gate[200], drain[200], source[200], subs[200];
|
||||||
char inststr[64];
|
char inststr[64];
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
strcpy(dev_class, nexttok);
|
strcpy(dev_class, nexttok);
|
||||||
|
|
@ -308,8 +305,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
||||||
SkipNewLine(NULL);
|
SkipNewLine(NULL);
|
||||||
}
|
}
|
||||||
else if (match(nexttok, "fet")) { /* old-style FET record */
|
else if (match(nexttok, "fet")) { /* old-style FET record */
|
||||||
char fet_class[MAX_STR_LEN];
|
char fet_class[100];
|
||||||
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN], subs[MAX_STR_LEN];
|
char gate[200], drain[200], source[200], subs[200];
|
||||||
char inststr[64];
|
char inststr[64];
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
strcpy(fet_class, nexttok);
|
strcpy(fet_class, nexttok);
|
||||||
|
|
@ -367,7 +364,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
||||||
SkipNewLine(NULL);
|
SkipNewLine(NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
char ctop[MAX_STR_LEN], cbot[MAX_STR_LEN], cdummy[MAX_STR_LEN];
|
char ctop[200], cbot[200], cdummy[200];
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
GetExtName(ctop, nexttok);
|
GetExtName(ctop, nexttok);
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
|
|
@ -377,8 +374,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (match(nexttok, "use")) {
|
else if (match(nexttok, "use")) {
|
||||||
char name[MAX_STR_LEN];
|
char name[200];
|
||||||
char instancename[MAX_STR_LEN];
|
char instancename[200];
|
||||||
char *basename;
|
char *basename;
|
||||||
|
|
||||||
/* No cell is generated until at least one valid "node" or "use" */
|
/* No cell is generated until at least one valid "node" or "use" */
|
||||||
|
|
@ -392,7 +389,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
GetExtName(name, nexttok);
|
GetExtName(name, nexttok);
|
||||||
if ((basename = strrchr(name,'/')) != NULL) {
|
if ((basename = strrchr(name,'/')) != NULL) {
|
||||||
char tmp[MAX_STR_LEN];
|
char tmp[200];
|
||||||
strcpy(tmp, basename+1);
|
strcpy(tmp, basename+1);
|
||||||
strcpy(name, tmp);
|
strcpy(name, tmp);
|
||||||
}
|
}
|
||||||
|
|
@ -407,8 +404,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
||||||
SkipNewLine(NULL);
|
SkipNewLine(NULL);
|
||||||
}
|
}
|
||||||
else if (match(nexttok, "merge")) {
|
else if (match(nexttok, "merge")) {
|
||||||
char name[MAX_STR_LEN];
|
char name[200];
|
||||||
char name2[MAX_STR_LEN];
|
char name2[200];
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
GetExtName(name, nexttok);
|
GetExtName(name, nexttok);
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
|
|
@ -452,8 +449,7 @@ void simCell(char *name, int filenum)
|
||||||
struct nlist *tp, *tp2;
|
struct nlist *tp, *tp2;
|
||||||
struct objlist *ob, *ob2;
|
struct objlist *ob, *ob2;
|
||||||
char FileName[500], simclass;
|
char FileName[500], simclass;
|
||||||
char writeLine[1024], paramString[128];
|
short i;
|
||||||
short i, p, mult;
|
|
||||||
double l, w, v;
|
double l, w, v;
|
||||||
|
|
||||||
tp = LookupCellFile(name, filenum);
|
tp = LookupCellFile(name, filenum);
|
||||||
|
|
@ -481,9 +477,9 @@ void simCell(char *name, int filenum)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print out header list */
|
/* print out header list */
|
||||||
/* distance units are multiplied by invlambda */
|
/* distance units are multiplied by 100 (distances are in um) */
|
||||||
|
|
||||||
FlushString("| units: %d tech: scmos\n", 100 * invlambda);
|
FlushString("| units: 100 tech: scmos\n");
|
||||||
|
|
||||||
/* now run through cell's contents, print instances */
|
/* now run through cell's contents, print instances */
|
||||||
for (ob = tp->cell; ob != NULL; ob = ob->next) {
|
for (ob = tp->cell; ob != NULL; ob = ob->next) {
|
||||||
|
|
@ -519,17 +515,13 @@ void simCell(char *name, int filenum)
|
||||||
case CLASS_NPN:
|
case CLASS_NPN:
|
||||||
simclass = 'b';
|
simclass = 'b';
|
||||||
break;
|
break;
|
||||||
case CLASS_SUBCKT:
|
|
||||||
case CLASS_MODULE:
|
|
||||||
simclass = 'x';
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
simclass = '|';
|
simclass = 'x';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (simclass != 'x')
|
if (simclass != 'x')
|
||||||
FlushString("%c", simclass);
|
FlushString("%c", simclass);
|
||||||
|
|
||||||
switch (tp2->class) {
|
switch (tp2->class) {
|
||||||
case CLASS_NMOS: case CLASS_NMOS4:
|
case CLASS_NMOS: case CLASS_NMOS4:
|
||||||
|
|
@ -597,115 +589,6 @@ void simCell(char *name, int filenum)
|
||||||
FlushString(" %g\n", v);
|
FlushString(" %g\n", v);
|
||||||
break;
|
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:
|
default:
|
||||||
FlushString("| unhandled component %s\n", tp2->name);
|
FlushString("| unhandled component %s\n", tp2->name);
|
||||||
break;
|
break;
|
||||||
|
|
@ -742,181 +625,6 @@ int StrIsInt(char *s)
|
||||||
return (1);
|
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 */
|
/* Read a .sim format file */
|
||||||
/*-------------------------*/
|
/*-------------------------*/
|
||||||
|
|
@ -931,11 +639,11 @@ char *ReadSim(char *fname, int *fnum)
|
||||||
double simscale = 1.0;
|
double simscale = 1.0;
|
||||||
|
|
||||||
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
|
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
|
||||||
char name[MAX_STR_LEN];
|
char name[100];
|
||||||
|
|
||||||
SetExtension(name, fname, SIM_EXTENSION);
|
SetExtension(name, fname, SIM_EXTENSION);
|
||||||
if (OpenParseFile(name, *fnum) < 0) {
|
if (OpenParseFile(name, *fnum) < 0) {
|
||||||
Printf("Error in sim file read: No file %s\n",name);
|
Printf("Error in ext file read: No file %s\n",name);
|
||||||
*fnum = filenum;
|
*fnum = filenum;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -944,7 +652,7 @@ char *ReadSim(char *fname, int *fnum)
|
||||||
/* Make sure all .sim file reading is case sensitive */
|
/* Make sure all .sim file reading is case sensitive */
|
||||||
matchfunc = match;
|
matchfunc = match;
|
||||||
matchintfunc = matchfile;
|
matchintfunc = matchfile;
|
||||||
hashfunc = hashcase;
|
hashfunc = hash;
|
||||||
|
|
||||||
CellDef(fname, filenum);
|
CellDef(fname, filenum);
|
||||||
|
|
||||||
|
|
@ -961,7 +669,7 @@ char *ReadSim(char *fname, int *fnum)
|
||||||
SkipNewLine(NULL);
|
SkipNewLine(NULL);
|
||||||
}
|
}
|
||||||
else if (match(nexttok, "n")) {
|
else if (match(nexttok, "n")) {
|
||||||
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN];
|
char gate[200], drain[200], source[200];
|
||||||
char inststr[25], *instptr = NULL;
|
char inststr[25], *instptr = NULL;
|
||||||
|
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
|
|
@ -1005,7 +713,7 @@ char *ReadSim(char *fname, int *fnum)
|
||||||
LinkProperties("n", kvlist);
|
LinkProperties("n", kvlist);
|
||||||
}
|
}
|
||||||
else if (match(nexttok, "p")) {
|
else if (match(nexttok, "p")) {
|
||||||
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN];
|
char gate[200], drain[200], source[200];
|
||||||
char inststr[25], *instptr = NULL;
|
char inststr[25], *instptr = NULL;
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
GetExtName(gate, nexttok);
|
GetExtName(gate, nexttok);
|
||||||
|
|
@ -1045,7 +753,7 @@ char *ReadSim(char *fname, int *fnum)
|
||||||
LinkProperties("p", kvlist);
|
LinkProperties("p", kvlist);
|
||||||
}
|
}
|
||||||
else if (match(nexttok, "e")) { /* 3-port capacitors (poly/poly2) */
|
else if (match(nexttok, "e")) { /* 3-port capacitors (poly/poly2) */
|
||||||
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN];
|
char gate[200], drain[200], source[200];
|
||||||
char inststr[25], *instptr = NULL;
|
char inststr[25], *instptr = NULL;
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
GetExtName(gate, nexttok);
|
GetExtName(gate, nexttok);
|
||||||
|
|
@ -1079,7 +787,7 @@ char *ReadSim(char *fname, int *fnum)
|
||||||
E(fname, instptr, gate, drain, source);
|
E(fname, instptr, gate, drain, source);
|
||||||
}
|
}
|
||||||
else if (match(nexttok, "b")) { /* bipolars added by Tim 7/16/96 */
|
else if (match(nexttok, "b")) { /* bipolars added by Tim 7/16/96 */
|
||||||
char base[MAX_STR_LEN], emitter[MAX_STR_LEN], collector[MAX_STR_LEN];
|
char base[200], emitter[200], collector[200];
|
||||||
char inststr[25], *instptr = NULL;
|
char inststr[25], *instptr = NULL;
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
GetExtName(base, nexttok);
|
GetExtName(base, nexttok);
|
||||||
|
|
@ -1117,7 +825,7 @@ char *ReadSim(char *fname, int *fnum)
|
||||||
SkipNewLine(NULL);
|
SkipNewLine(NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
char ctop[MAX_STR_LEN], cbot[MAX_STR_LEN], cdummy[MAX_STR_LEN];
|
char ctop[200], cbot[200], cdummy[200];
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
GetExtName(ctop, nexttok);
|
GetExtName(ctop, nexttok);
|
||||||
if (LookupObject(ctop, CurrentCell) == NULL)
|
if (LookupObject(ctop, CurrentCell) == NULL)
|
||||||
|
|
@ -1138,11 +846,11 @@ char *ReadSim(char *fname, int *fnum)
|
||||||
}
|
}
|
||||||
else if (match(nexttok, "r")) { /* 2-port resistors */
|
else if (match(nexttok, "r")) { /* 2-port resistors */
|
||||||
if (IgnoreRC) {
|
if (IgnoreRC) {
|
||||||
/* ignore all resistances */
|
/* ignore all capacitances */
|
||||||
SkipNewLine(NULL);
|
SkipNewLine(NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
char rtop[MAX_STR_LEN], rbot[MAX_STR_LEN];
|
char rtop[200], rbot[200];
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
GetExtName(rtop, nexttok);
|
GetExtName(rtop, nexttok);
|
||||||
if (LookupObject(rtop, CurrentCell) == NULL)
|
if (LookupObject(rtop, CurrentCell) == NULL)
|
||||||
|
|
@ -1166,7 +874,7 @@ char *ReadSim(char *fname, int *fnum)
|
||||||
SkipNewLine(NULL);
|
SkipNewLine(NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
char rtop[MAX_STR_LEN], rbot[MAX_STR_LEN], rdummy[MAX_STR_LEN];
|
char rtop[200], rbot[200], rdummy[200];
|
||||||
char inststr[25], *instptr = NULL;
|
char inststr[25], *instptr = NULL;
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
GetExtName(rdummy, nexttok);
|
GetExtName(rdummy, nexttok);
|
||||||
|
|
@ -1208,7 +916,7 @@ char *ReadSim(char *fname, int *fnum)
|
||||||
SkipNewLine(NULL);
|
SkipNewLine(NULL);
|
||||||
}
|
}
|
||||||
else if (match(nexttok, "=")) {
|
else if (match(nexttok, "=")) {
|
||||||
char node1[MAX_STR_LEN], node2[MAX_STR_LEN];
|
char node1[200], node2[200];
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
GetExtName(node1, nexttok);
|
GetExtName(node1, nexttok);
|
||||||
SkipTok(NULL);
|
SkipTok(NULL);
|
||||||
|
|
|
||||||
946
base/flatten.c
946
base/flatten.c
File diff suppressed because it is too large
Load Diff
|
|
@ -1,8 +0,0 @@
|
||||||
#ifndef _FLATTEN_H
|
|
||||||
#define _FLATTEN_H
|
|
||||||
|
|
||||||
extern int UniquePins(char *name, int filenum);
|
|
||||||
extern void flattenCell(char *name, int file);
|
|
||||||
extern int HasContents(struct nlist *);
|
|
||||||
|
|
||||||
#endif /* _FLATTEN_H */
|
|
||||||
37
base/hash.c
37
base/hash.c
|
|
@ -30,8 +30,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "netgen.h"
|
#include "netgen.h"
|
||||||
#include "objlist.h"
|
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
#include "objlist.h"
|
||||||
|
|
||||||
unsigned long (*hashfunc)(char *, int) = NULL;
|
unsigned long (*hashfunc)(char *, int) = NULL;
|
||||||
int (*matchfunc)(char *, char *) = NULL;
|
int (*matchfunc)(char *, char *) = NULL;
|
||||||
|
|
@ -137,39 +137,32 @@ static unsigned char uppercase[] = {
|
||||||
// horrible things can happen, as, for example, names AOI12 and OAI12
|
// horrible things can happen, as, for example, names AOI12 and OAI12
|
||||||
// have exactly the same hash result. Lousy for binning and even
|
// have exactly the same hash result. Lousy for binning and even
|
||||||
// lousier for generating class magic numbers.
|
// 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 hashnocase(char *s, int hashsize)
|
||||||
{
|
{
|
||||||
unsigned long hashval = 2166136261ul;
|
unsigned long hashval;
|
||||||
for (; *s != '\0'; s++) {
|
|
||||||
hashval ^= uppercase[*s];
|
for (hashval = 0; *s != '\0'; )
|
||||||
hashval *= 16777619ul;
|
hashval = uppercase[*s++]
|
||||||
}
|
+ (hashval << 6) + (hashval << 16) - hashval;
|
||||||
return (hashsize == 0) ? hashval : (hashval % hashsize);
|
return (hashsize == 0) ? hashval : (hashval % hashsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long hashcase(char *s, int hashsize)
|
unsigned long hash(char *s, int hashsize)
|
||||||
{
|
{
|
||||||
unsigned long hashval = 2166136261ul;
|
unsigned long hashval;
|
||||||
for (; *s != '\0'; s++) {
|
|
||||||
hashval ^= (unsigned char)(*s);
|
for (hashval = 0; *s != '\0'; )
|
||||||
hashval *= 16777619ul;
|
hashval = (*s++) + (hashval << 6) + (hashval << 16) - hashval;
|
||||||
}
|
|
||||||
return (hashsize == 0) ? hashval : (hashval % hashsize);
|
return (hashsize == 0) ? hashval : (hashval % hashsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long genhash(char *s, int c, int hashsize)
|
unsigned long genhash(char *s, int c, int hashsize)
|
||||||
{
|
{
|
||||||
unsigned long hashval = 2166136261ul;
|
unsigned long hashval;
|
||||||
hashval ^= (unsigned long)c;
|
|
||||||
hashval *= 16777619ul;
|
for (hashval = (unsigned long)c; *s != '\0'; )
|
||||||
for (; *s != '\0'; s++) {
|
hashval = (*s++) + (hashval << 6) + (hashval << 16) - hashval;
|
||||||
hashval ^= (unsigned char)(*s);
|
|
||||||
hashval *= 16777619ul;
|
|
||||||
}
|
|
||||||
return (hashsize == 0) ? hashval : (hashval % hashsize);
|
return (hashsize == 0) ? hashval : (hashval % hashsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ extern void *HashFirst(struct hashdict *dict);
|
||||||
extern void *HashNext(struct hashdict *dict);
|
extern void *HashNext(struct hashdict *dict);
|
||||||
|
|
||||||
extern unsigned long hashnocase(char *s, int hashsize);
|
extern unsigned long hashnocase(char *s, int hashsize);
|
||||||
extern unsigned long hashcase(char *s, int hashsize);
|
extern unsigned long hash(char *s, int hashsize);
|
||||||
|
|
||||||
extern int (*matchfunc)(char *, char *);
|
extern int (*matchfunc)(char *, char *);
|
||||||
/* matchintfunc() compares based on the name and the first */
|
/* matchintfunc() compares based on the name and the first */
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ along with this program; see the file copying. If not, write to
|
||||||
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
|
|
||||||
/* inetcomp.c -- a simple wrapper to the NETCOMP() function */
|
/* inetcomp.c -- a simple wrapper to the NETCOMP() function */
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "netgen.h"
|
#include "netgen.h"
|
||||||
|
|
@ -34,7 +33,7 @@ void STRCPY(char *dest, char *source)
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
|
char cell1[200], cell2[200];
|
||||||
|
|
||||||
Debug = 0;
|
Debug = 0;
|
||||||
if (argc != 1) {
|
if (argc != 1) {
|
||||||
|
|
|
||||||
2791
base/netcmp.c
2791
base/netcmp.c
File diff suppressed because it is too large
Load Diff
|
|
@ -7,7 +7,6 @@ extern struct nlist *Circuit1;
|
||||||
extern struct nlist *Circuit2;
|
extern struct nlist *Circuit2;
|
||||||
|
|
||||||
extern int ExhaustiveSubdivision;
|
extern int ExhaustiveSubdivision;
|
||||||
extern int ExactTopology;
|
|
||||||
|
|
||||||
extern int left_col_end;
|
extern int left_col_end;
|
||||||
extern int right_col_end;
|
extern int right_col_end;
|
||||||
|
|
@ -27,7 +26,6 @@ extern void PrintCoreStats(void);
|
||||||
extern void ResetState(void);
|
extern void ResetState(void);
|
||||||
extern void CreateTwoLists(char *name1, int file1, char *name2, int file2,
|
extern void CreateTwoLists(char *name1, int file1, char *name2, int file2,
|
||||||
int dolist);
|
int dolist);
|
||||||
extern void DescribeContents(char *name1, int file1, char *name2, int file2);
|
|
||||||
extern int Iterate(void);
|
extern int Iterate(void);
|
||||||
extern int VerifyMatching(void);
|
extern int VerifyMatching(void);
|
||||||
extern void PrintAutomorphisms(void);
|
extern void PrintAutomorphisms(void);
|
||||||
|
|
@ -38,8 +36,7 @@ extern int PermuteSetup(char *model, int filenum, char *pin1, char *pin2);
|
||||||
extern int PermuteForget(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 EquivalenceElements(char *name1, int file1, char *name2, int file2);
|
||||||
extern int EquivalenceNodes(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 IgnoreClass(char *name, int file, unsigned char type);
|
||||||
extern int MatchPins(struct nlist *tp1, struct nlist *tp2, int dolist);
|
extern int MatchPins(struct nlist *tp1, struct nlist *tp2, int dolist);
|
||||||
extern int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run,
|
extern int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run,
|
||||||
|
|
@ -49,7 +46,6 @@ extern int CreateCompareQueue(char *, int, char *, int);
|
||||||
extern int GetCompareQueueTop(char **, int *, char **, int *);
|
extern int GetCompareQueueTop(char **, int *, char **, int *);
|
||||||
extern int PeekCompareQueueTop(char **, int *, char **, int *);
|
extern int PeekCompareQueueTop(char **, int *, char **, int *);
|
||||||
extern void RemoveCompareQueue();
|
extern void RemoveCompareQueue();
|
||||||
extern int FlattenUnmatched(struct nlist *, char *, int, int);
|
|
||||||
|
|
||||||
extern void PrintIllegalClasses();
|
extern void PrintIllegalClasses();
|
||||||
extern void PrintIllegalNodeClasses();
|
extern void PrintIllegalNodeClasses();
|
||||||
|
|
@ -58,20 +54,9 @@ extern void PrintIllegalElementClasses();
|
||||||
extern void DumpNetwork(struct objlist *ob, int cidx);
|
extern void DumpNetwork(struct objlist *ob, int cidx);
|
||||||
extern void DumpNetworkAll(char *name, int file);
|
extern void DumpNetworkAll(char *name, int file);
|
||||||
|
|
||||||
extern void RegroupDataStructures();
|
|
||||||
extern void FormatIllegalElementClasses();
|
|
||||||
extern void FormatIllegalNodeClasses();
|
|
||||||
extern int ResolveAutomorphsByProperty();
|
|
||||||
extern int ResolveAutomorphsByPin(int match_nets);
|
|
||||||
extern void SummarizeElementClasses(struct ElementClass *EC);
|
|
||||||
extern int remove_group_tags(struct objlist *ob);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef TCL_NETGEN
|
#ifdef TCL_NETGEN
|
||||||
extern int EquivalentNode();
|
extern int EquivalentNode();
|
||||||
extern int EquivalentElement();
|
extern int EquivalentElement();
|
||||||
extern void DeriveAreaProperty();
|
|
||||||
extern void DerivePerimeterProperty();
|
|
||||||
|
|
||||||
extern void enable_interrupt();
|
extern void enable_interrupt();
|
||||||
extern void disable_interrupt();
|
extern void disable_interrupt();
|
||||||
|
|
|
||||||
237
base/netfile.c
237
base/netfile.c
|
|
@ -183,6 +183,7 @@ void CloseFile(char *filename)
|
||||||
fclose(outfile);
|
fclose(outfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* STUFF TO READ INPUT FILES */
|
/* STUFF TO READ INPUT FILES */
|
||||||
|
|
||||||
static char *line = NULL; /* actual line read in */
|
static char *line = NULL; /* actual line read in */
|
||||||
|
|
@ -206,21 +207,6 @@ struct hashdict *definitions = (struct hashdict *)NULL;
|
||||||
|
|
||||||
#define WHITESPACE_DELIMITER " \t\n\r"
|
#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() --- */
|
/* TrimQuoted() --- */
|
||||||
/* Remove spaces from inside single- or double-quoted strings. */
|
/* Remove spaces from inside single- or double-quoted strings. */
|
||||||
|
|
@ -302,7 +288,7 @@ int GetNextLineNoNewline(char *delimiter)
|
||||||
{
|
{
|
||||||
char *newbuf;
|
char *newbuf;
|
||||||
int testc;
|
int testc;
|
||||||
static int nested = 0;
|
int nested = 0;
|
||||||
int llen;
|
int llen;
|
||||||
|
|
||||||
if (feof(infile)) return -1;
|
if (feof(infile)) return -1;
|
||||||
|
|
@ -329,11 +315,6 @@ int GetNextLineNoNewline(char *delimiter)
|
||||||
llen = strlen(line);
|
llen = strlen(line);
|
||||||
}
|
}
|
||||||
while (llen == linesize - 1) {
|
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);
|
newbuf = (char *)MALLOC(linesize + 501);
|
||||||
strcpy(newbuf, line);
|
strcpy(newbuf, line);
|
||||||
FREE(line);
|
FREE(line);
|
||||||
|
|
@ -350,88 +331,78 @@ int GetNextLineNoNewline(char *delimiter)
|
||||||
linetok = (char *)MALLOC(linesize + 1);
|
linetok = (char *)MALLOC(linesize + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (definitions == NULL)
|
/* Check for substitutions (verilog only). Make sure linetok is */
|
||||||
strcpy(linetok, line);
|
/* large enough to hold the entire line after substitutions. */
|
||||||
else {
|
|
||||||
char *s, *t, *w, e;
|
if (definitions != NULL) {
|
||||||
|
char *s, *w, e;
|
||||||
struct property *kl;
|
struct property *kl;
|
||||||
int len, dlen, vlen, addin = 0;
|
int len, dlen, vlen, addin = 0;
|
||||||
int oldlinesize = linesize;
|
unsigned char found = FALSE;
|
||||||
unsigned char found = TRUE;
|
|
||||||
|
|
||||||
/* Check for substitutions (verilog only). Make sure linetok is */
|
for (s = line; *s != '\0'; s++) {
|
||||||
/* large enough to hold the entire line after substitutions. */
|
if (*s == '`') {
|
||||||
|
w = s + 1;
|
||||||
while (found) { /* Do this recursively, for nested definitions */
|
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
|
||||||
found = FALSE;
|
e = *w;
|
||||||
|
*w = '\0';
|
||||||
for (s = line; *s != '\0'; s++) {
|
kl = (struct property *)HashLookup(s + 1, definitions);
|
||||||
if (*s == '`') {
|
if (kl != NULL) {
|
||||||
w = s + 1;
|
dlen = strlen(s);
|
||||||
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
|
if (kl->type == PROP_STRING) {
|
||||||
e = *w;
|
vlen = strlen(kl->pdefault.string);
|
||||||
*w = '\0';
|
}
|
||||||
kl = (struct property *)HashLookup(s + 1, definitions);
|
else vlen = 12; /* Leave room for numeric conversion */
|
||||||
if (kl != NULL) {
|
addin += vlen - dlen + 1;
|
||||||
dlen = strlen(s);
|
found = TRUE;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
*w = e;
|
||||||
if (found) {
|
}
|
||||||
len = strlen(line);
|
}
|
||||||
if (len + addin > linesize) {
|
if (found) {
|
||||||
while (len + addin > linesize) linesize += 500;
|
len = strlen(line);
|
||||||
FREE(linetok);
|
if (len + addin > linesize) {
|
||||||
linetok = (char *)MALLOC(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;
|
|
||||||
}
|
|
||||||
*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;
|
|
||||||
}
|
}
|
||||||
strcpy(line, linetok);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make definition substitutions (verilog only) */
|
||||||
|
|
||||||
|
if (definitions != NULL) {
|
||||||
|
char *s, *t, *w, e;
|
||||||
|
struct property *kl;
|
||||||
|
|
||||||
|
t = linetok;
|
||||||
|
for (s = line; *s != '\0'; s++) {
|
||||||
|
if (*s == '`') {
|
||||||
|
w = s + 1;
|
||||||
|
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
|
||||||
|
e = *w;
|
||||||
|
*w = '\0';
|
||||||
|
kl = (struct property *)HashLookup(s + 1, definitions);
|
||||||
|
if (kl != NULL) {
|
||||||
|
if (kl->type == PROP_STRING)
|
||||||
|
strcpy(t, kl->pdefault.string);
|
||||||
|
else if (kl->type == PROP_INTEGER)
|
||||||
|
sprintf(t, "%d", kl->pdefault.ival);
|
||||||
|
else if (kl->type == PROP_DOUBLE)
|
||||||
|
sprintf(t, "%g", kl->pdefault.dval);
|
||||||
|
t += strlen(t);
|
||||||
|
s = w - 1;
|
||||||
|
}
|
||||||
|
else *t++ = *s;
|
||||||
|
*w = e;
|
||||||
|
}
|
||||||
|
else *t++ = *s;
|
||||||
|
}
|
||||||
|
*t = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
strcpy(linetok, line);
|
||||||
|
|
||||||
TrimQuoted(linetok);
|
TrimQuoted(linetok);
|
||||||
linenum++;
|
linenum++;
|
||||||
|
|
||||||
|
|
@ -592,31 +563,19 @@ void SkipTokNoNewline(char *delimiter)
|
||||||
/* */
|
/* */
|
||||||
/* Modified 3/30/2015 to include the condition where a comment line is */
|
/* Modified 3/30/2015 to include the condition where a comment line is */
|
||||||
/* in the middle of a series of continuation lines. */
|
/* 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)
|
void SpiceTokNoNewline(void)
|
||||||
{
|
{
|
||||||
int contline;
|
int contline;
|
||||||
|
|
||||||
if ((nexttok = strdtok0(NULL, WHITESPACE_DELIMITER, NULL, FALSE)) != NULL) return;
|
if ((nexttok = strdtok(NULL, WHITESPACE_DELIMITER, NULL)) != NULL) return;
|
||||||
|
|
||||||
while (nexttok == NULL) {
|
while (nexttok == NULL) {
|
||||||
contline = getc(infile);
|
contline = getc(infile);
|
||||||
if (contline == '*') {
|
if (contline == '*') {
|
||||||
char testline = ' ';
|
GetNextLine(WHITESPACE_DELIMITER);
|
||||||
while ((testline == ' ') || (testline == '\t'))
|
SkipNewLine(NULL);
|
||||||
testline = getc(infile);
|
|
||||||
if (testline != '\n') {
|
|
||||||
ungetc(testline, infile);
|
|
||||||
GetNextLine(WHITESPACE_DELIMITER);
|
|
||||||
SkipNewLine(NULL);
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (contline != '+') {
|
else if (contline != '+') {
|
||||||
|
|
@ -628,8 +587,7 @@ void SpiceTokNoNewline(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
/* Skip to the next token, ignoring any C-style comments and verilog */
|
/* Skip to the next token, ignoring any C-style comments. */
|
||||||
/* "(* ... *)"-style comments. */
|
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
void SkipTokComments(char *delimiter)
|
void SkipTokComments(char *delimiter)
|
||||||
|
|
@ -645,11 +603,6 @@ void SkipTokComments(char *delimiter)
|
||||||
SkipTok(delimiter);
|
SkipTok(delimiter);
|
||||||
if (nexttok) SkipTok(delimiter);
|
if (nexttok) SkipTok(delimiter);
|
||||||
}
|
}
|
||||||
else if (match(nexttok, "(*")) {
|
|
||||||
while (nexttok && !match(nexttok, "*)"))
|
|
||||||
SkipTok(delimiter);
|
|
||||||
if (nexttok) SkipTok(delimiter);
|
|
||||||
}
|
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -685,7 +638,6 @@ void SpiceSkipNewLine(void)
|
||||||
ungetc(contline, infile);
|
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 */
|
/* Function similar to strtok() for token parsing. The difference is */
|
||||||
/* that it takes two sets of delimiters. The first is whitespace */
|
/* that it takes two sets of delimiters. The first is whitespace */
|
||||||
|
|
@ -706,9 +658,8 @@ void SpiceSkipNewLine(void)
|
||||||
/* the first character of the delimiter string in addition to marking */
|
/* the first character of the delimiter string in addition to marking */
|
||||||
/* the boundary between two-character and one-character delimiters. */
|
/* the boundary between two-character and one-character delimiters. */
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
#endif
|
|
||||||
|
|
||||||
char *strdtok0(char *pstring, char *delim1, char *delim2, char isverilog)
|
char *strdtok(char *pstring, char *delim1, char *delim2)
|
||||||
{
|
{
|
||||||
static char *stoken = NULL;
|
static char *stoken = NULL;
|
||||||
static char *sstring = NULL;
|
static char *sstring = NULL;
|
||||||
|
|
@ -753,10 +704,10 @@ char *strdtok0(char *pstring, char *delim1, char *delim2, char isverilog)
|
||||||
/* should know whether it is parsing SPICE or verilog and handle the syntax */
|
/* should know whether it is parsing SPICE or verilog and handle the syntax */
|
||||||
/* accordingly (needs to be done). */
|
/* accordingly (needs to be done). */
|
||||||
|
|
||||||
if (isverilog && (*s == '\\')) {
|
if (*s == '\\') {
|
||||||
s++;
|
s++;
|
||||||
while (*s != '\0') {
|
while (*s != '\0') {
|
||||||
if ((*s == ' ') || ((*s == '\\') && (*(s + 1) == '\0'))) {
|
if ((*s == ' ') || (*s == '\\')) {
|
||||||
s++;
|
s++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -824,17 +775,6 @@ char *strdtok0(char *pstring, char *delim1, char *delim2, char isverilog)
|
||||||
return sstring;
|
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)
|
void InputParseError(FILE *f)
|
||||||
|
|
@ -916,7 +856,7 @@ char *ReadNetlist(char *fname, int *fnum)
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef mips
|
#ifdef mips
|
||||||
struct filetype formats[8];
|
struct filetype formats[7];
|
||||||
|
|
||||||
formats[0].extension = NTK_EXTENSION;
|
formats[0].extension = NTK_EXTENSION;
|
||||||
formats[0].proc = ReadNtk;
|
formats[0].proc = ReadNtk;
|
||||||
|
|
@ -924,16 +864,14 @@ char *ReadNetlist(char *fname, int *fnum)
|
||||||
formats[1].proc = ReadExtHier;
|
formats[1].proc = ReadExtHier;
|
||||||
formats[2].extension = SIM_EXTENSION;
|
formats[2].extension = SIM_EXTENSION;
|
||||||
formats[2].proc = ReadSim;
|
formats[2].proc = ReadSim;
|
||||||
formats[3].extension = PRM_EXTENSION;
|
formats[3].extension = SPICE_EXTENSION;
|
||||||
formats[3].proc = ReadPrm;
|
formats[3].proc = ReadSpice;
|
||||||
formats[4].extension = SPICE_EXTENSION;
|
formats[4].extension = NETGEN_EXTENSION;
|
||||||
formats[4].proc = ReadSpice;
|
formats[4].proc = ReadNetgenFile;
|
||||||
formats[5].extension = NETGEN_EXTENSION;
|
formats[5].extension = VERILOG_EXTENSION;
|
||||||
formats[5].proc = ReadNetgenFile;
|
formats[5].proc = ReadVerilogFile;
|
||||||
formats[6].extension = VERILOG_EXTENSION;
|
formats[6].extension = NULL;
|
||||||
formats[6].proc = ReadVerilogFile;
|
formats[6].proc = NULL;
|
||||||
formats[7].extension = NULL;
|
|
||||||
formats[7].proc = NULL;
|
|
||||||
|
|
||||||
#else /* not mips (i.e. compiler with reasonable initializers) */
|
#else /* not mips (i.e. compiler with reasonable initializers) */
|
||||||
|
|
||||||
|
|
@ -942,7 +880,6 @@ char *ReadNetlist(char *fname, int *fnum)
|
||||||
{NTK_EXTENSION, ReadNtk},
|
{NTK_EXTENSION, ReadNtk},
|
||||||
{EXT_EXTENSION, ReadExtHier},
|
{EXT_EXTENSION, ReadExtHier},
|
||||||
{SIM_EXTENSION, ReadSim},
|
{SIM_EXTENSION, ReadSim},
|
||||||
{PRM_EXTENSION, ReadPrm},
|
|
||||||
{SPICE_EXTENSION, ReadSpice},
|
{SPICE_EXTENSION, ReadSpice},
|
||||||
{SPICE_EXT2, ReadSpice},
|
{SPICE_EXT2, ReadSpice},
|
||||||
{SPICE_EXT3, ReadSpice},
|
{SPICE_EXT3, ReadSpice},
|
||||||
|
|
@ -959,15 +896,13 @@ char *ReadNetlist(char *fname, int *fnum)
|
||||||
|
|
||||||
/* make first pass looking for extension */
|
/* make first pass looking for extension */
|
||||||
for (index = 0; formats[index].extension != NULL; index++) {
|
for (index = 0; formats[index].extension != NULL; index++) {
|
||||||
int extlen = strlen(formats[index].extension);
|
if (strstr(fname, formats[index].extension) != NULL) {
|
||||||
int flen = strlen(fname);
|
|
||||||
if (!strcmp(fname + flen - extlen, formats[index].extension)) {
|
|
||||||
return (*(formats[index].proc))(fname, fnum);
|
return (*(formats[index].proc))(fname, fnum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* try appending extensions in sequence, and testing for file existance */
|
/* try appending extensions in sequence, and testing for file existance */
|
||||||
for (index = 0; formats[index].extension != NULL; index++) {
|
for (index = 0; formats[index].extension != NULL; index++) {
|
||||||
char testname[MAX_STR_LEN];
|
char testname[200];
|
||||||
strcpy(testname, fname);
|
strcpy(testname, fname);
|
||||||
strcat(testname, formats[index].extension);
|
strcat(testname, formats[index].extension);
|
||||||
if (OpenParseFile(testname, *fnum) >= 0) {
|
if (OpenParseFile(testname, *fnum) >= 0) {
|
||||||
|
|
@ -1072,7 +1007,7 @@ void WriteNetgenFile(char *name, char *filename)
|
||||||
|
|
||||||
char *ReadNetgenFile (char *fname, int *fnum)
|
char *ReadNetgenFile (char *fname, int *fnum)
|
||||||
{
|
{
|
||||||
char name[MAX_STR_LEN];
|
char name[100];
|
||||||
char *LastCellRead = NULL;
|
char *LastCellRead = NULL;
|
||||||
int filenum;
|
int filenum;
|
||||||
|
|
||||||
|
|
@ -1308,7 +1243,7 @@ int READ(void *buf, int bytes)
|
||||||
|
|
||||||
char *ReadNetgenFile (char *fname, int *fnum)
|
char *ReadNetgenFile (char *fname, int *fnum)
|
||||||
{
|
{
|
||||||
char name[MAX_STR_LEN];
|
char name[100];
|
||||||
int len, chars;
|
int len, chars;
|
||||||
char *LastCellRead = NULL;
|
char *LastCellRead = NULL;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
#define WOMBAT_EXTENSION ".wom"
|
#define WOMBAT_EXTENSION ".wom"
|
||||||
#define EXT_EXTENSION ".ext"
|
#define EXT_EXTENSION ".ext"
|
||||||
#define SIM_EXTENSION ".sim"
|
#define SIM_EXTENSION ".sim"
|
||||||
#define PRM_EXTENSION ".prm"
|
|
||||||
#define SPICE_EXTENSION ".spice"
|
#define SPICE_EXTENSION ".spice"
|
||||||
#define SPICE_EXT2 ".spc"
|
#define SPICE_EXT2 ".spc"
|
||||||
#define SPICE_EXT3 ".sp"
|
#define SPICE_EXT3 ".sp"
|
||||||
|
|
@ -36,7 +35,6 @@ extern struct hashdict *definitions;
|
||||||
|
|
||||||
extern char *nexttok;
|
extern char *nexttok;
|
||||||
#define SKIPTO(a) do {SkipTok(NULL);} while (!match(nexttok,a))
|
#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 *strdtok(char *pstring, char *delim1, char *delim2);
|
||||||
extern char *GetLineAtTok();
|
extern char *GetLineAtTok();
|
||||||
extern void SkipTok(char *delimiter);
|
extern void SkipTok(char *delimiter);
|
||||||
|
|
@ -49,7 +47,5 @@ extern void InputParseError(FILE *f);
|
||||||
extern int OpenParseFile(char *name, int fnum);
|
extern int OpenParseFile(char *name, int fnum);
|
||||||
extern int EndParseFile(void);
|
extern int EndParseFile(void);
|
||||||
extern int CloseParseFile(void);
|
extern int CloseParseFile(void);
|
||||||
extern void SeekFile(long offset); /* handles verilog 'for' loops */
|
|
||||||
extern long TellFile(); /* handles verilog 'for' loops */
|
|
||||||
|
|
||||||
#endif /* _NETFILE_H */
|
#endif /* _NETFILE_H */
|
||||||
|
|
|
||||||
1232
base/netgen.c
1232
base/netgen.c
File diff suppressed because it is too large
Load Diff
|
|
@ -39,13 +39,11 @@ extern void SetParallelCombine(int value);
|
||||||
extern void SetSeriesCombine(int value);
|
extern void SetSeriesCombine(int value);
|
||||||
extern int PropertyTolerance(char *name, int fnum, char *key, int ival,
|
extern int PropertyTolerance(char *name, int fnum, char *key, int ival,
|
||||||
double dval);
|
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,
|
extern int PropertyMerge(char *name, int fnum, char *key, int merge_type,
|
||||||
int merge_mask);
|
int merge_mask);
|
||||||
extern void ResolveProperties(char *name1, int file1, char *name2, int file2);
|
extern void ResolveProperties(char *name1, int file1, char *name2, int file2);
|
||||||
extern void CopyProperties(struct objlist *obj_to, struct objlist *obj_from);
|
extern void CopyProperties(struct objlist *obj_to, struct objlist *obj_from);
|
||||||
extern int PromoteProperty(struct property *, struct valuelist *,
|
extern int PromoteProperty(struct property *, struct valuelist *);
|
||||||
struct objlist *, struct nlist *);
|
|
||||||
extern int SetPropertyDefault(struct property *, struct valuelist *);
|
extern int SetPropertyDefault(struct property *, struct valuelist *);
|
||||||
extern struct objlist *LinkProperties(char *model, struct keyvalue *topptr);
|
extern struct objlist *LinkProperties(char *model, struct keyvalue *topptr);
|
||||||
extern int ReduceExpressions(struct objlist *instprop, struct objlist *parprops,
|
extern int ReduceExpressions(struct objlist *instprop, struct objlist *parprops,
|
||||||
|
|
@ -67,15 +65,6 @@ extern void AssignCircuits(char *name1, int file1, char *name2, int file2);
|
||||||
/* flatten.c */
|
/* flatten.c */
|
||||||
extern int PrematchLists(char *, int, char *, int);
|
extern int PrematchLists(char *, int, char *, int);
|
||||||
|
|
||||||
/* verilog.c */
|
|
||||||
struct cellstack {
|
|
||||||
char *cellname;
|
|
||||||
struct cellstack *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
|
||||||
int blackbox);
|
|
||||||
|
|
||||||
/* Define (enumerate) various device classes, largely based on SPICE */
|
/* Define (enumerate) various device classes, largely based on SPICE */
|
||||||
/* model types, mixed with some ext/sim types. */
|
/* model types, mixed with some ext/sim types. */
|
||||||
|
|
||||||
|
|
@ -151,7 +140,6 @@ extern int NoOutput; /* set this to 1 to disable stdout output */
|
||||||
extern int Composition; /* direction of composition */
|
extern int Composition; /* direction of composition */
|
||||||
extern int UnixWildcards; /* TRUE if *,?,{},[] only; false if full REGEXP */
|
extern int UnixWildcards; /* TRUE if *,?,{},[] only; false if full REGEXP */
|
||||||
extern int GlobalParallelNone; /* If TRUE, don't parallel combine any cells */
|
extern int GlobalParallelNone; /* If TRUE, don't parallel combine any cells */
|
||||||
extern int GlobalParallelOpen; /* If TRUE, parallel combine cells w/no-connects */
|
|
||||||
/* magic internal flag to restrict searches to recently placed cells */
|
/* magic internal flag to restrict searches to recently placed cells */
|
||||||
extern int QuickSearch;
|
extern int QuickSearch;
|
||||||
/* does re"CellDef"ing a cell add to it or overwrite it??? */
|
/* does re"CellDef"ing a cell add to it or overwrite it??? */
|
||||||
|
|
@ -191,7 +179,6 @@ extern char *ReadNtk (char *fname, int *fnum);
|
||||||
extern char *ReadExtHier(char *fname, int *fnum);
|
extern char *ReadExtHier(char *fname, int *fnum);
|
||||||
extern char *ReadExtFlat(char *fname, int *fnum);
|
extern char *ReadExtFlat(char *fname, int *fnum);
|
||||||
extern char *ReadSim(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 *ReadSpice(char *fname, int *fnum);
|
||||||
extern char *ReadSpiceLib(char *fname, int *fnum);
|
extern char *ReadSpiceLib(char *fname, int *fnum);
|
||||||
extern char *ReadNetgenFile (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 *ReadNtk (char *fname, int *fnum)
|
||||||
{
|
{
|
||||||
char model[MAX_STR_LEN], instancename[MAX_STR_LEN], name[MAX_STR_LEN];
|
char model[100], instancename[100], name[100];
|
||||||
struct objlist *ob;
|
struct objlist *ob;
|
||||||
int CellDefInProgress = 0;
|
int CellDefInProgress = 0;
|
||||||
int filenum;
|
int filenum;
|
||||||
|
|
@ -218,7 +218,7 @@ char *ReadNtk (char *fname, int *fnum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (match(nexttok, "s")) {
|
else if (match(nexttok, "s")) {
|
||||||
char last[MAX_STR_LEN];
|
char last[100];
|
||||||
*last = '\0';
|
*last = '\0';
|
||||||
if (!CellDefInProgress) {
|
if (!CellDefInProgress) {
|
||||||
/* fake cell declaration for top-level call */
|
/* fake cell declaration for top-level call */
|
||||||
|
|
|
||||||
251
base/objlist.c
251
base/objlist.c
|
|
@ -22,7 +22,6 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <limits.h>
|
|
||||||
#ifdef IBMPC
|
#ifdef IBMPC
|
||||||
#include <alloc.h>
|
#include <alloc.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -32,13 +31,13 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "netgen.h"
|
#include "netgen.h"
|
||||||
|
#include "hash.h"
|
||||||
#include "objlist.h"
|
#include "objlist.h"
|
||||||
#include "regexp.h"
|
#include "regexp.h"
|
||||||
#include "dbug.h"
|
#include "dbug.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "netfile.h"
|
#include "netfile.h"
|
||||||
#include "netcmp.h"
|
#include "netcmp.h"
|
||||||
#include "hash.h"
|
|
||||||
|
|
||||||
#ifdef TCL_NETGEN
|
#ifdef TCL_NETGEN
|
||||||
extern Tcl_Interp *netgeninterp;
|
extern Tcl_Interp *netgeninterp;
|
||||||
|
|
@ -130,7 +129,6 @@ struct property *NewProperty(void)
|
||||||
|
|
||||||
kl = (struct property *)CALLOC(1,sizeof(struct property));
|
kl = (struct property *)CALLOC(1,sizeof(struct property));
|
||||||
if (kl == NULL) Fprintf(stderr,"NewProperty: Core allocation error\n");
|
if (kl == NULL) Fprintf(stderr,"NewProperty: Core allocation error\n");
|
||||||
kl->pin = (char *)NULL;
|
|
||||||
return (kl);
|
return (kl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,35 +221,12 @@ int matchnocase(char *st1, char *st2)
|
||||||
{
|
{
|
||||||
char *sp1 = st1;
|
char *sp1 = st1;
|
||||||
char *sp2 = st2;
|
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') {
|
while (*sp1 != '\0' && *sp2 != '\0') {
|
||||||
if (to_lower[*sp1] != to_lower[*sp2]) break;
|
if (to_lower[*sp1] != to_lower[*sp2]) break;
|
||||||
sp1++;
|
sp1++;
|
||||||
sp2++;
|
sp2++;
|
||||||
}
|
}
|
||||||
if (v1 && (*sp1 == ' ')) sp1++;
|
|
||||||
if (v2 && (*sp2 == ' ')) sp2++;
|
|
||||||
|
|
||||||
if ((*sp1 != '\0') || (*sp2 != '\0')) return 0;
|
if ((*sp1 != '\0') || (*sp2 != '\0')) return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -282,33 +257,6 @@ int matchfilenocase(char *st1, char *st2, int f1, int f2)
|
||||||
return 1;
|
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
|
#ifdef HAVE_MALLINFO
|
||||||
void PrintMemoryStats(void)
|
void PrintMemoryStats(void)
|
||||||
{
|
{
|
||||||
|
|
@ -340,7 +288,7 @@ static struct hashdict cell_dict;
|
||||||
|
|
||||||
void InitCellHashTable(void)
|
void InitCellHashTable(void)
|
||||||
{
|
{
|
||||||
hashfunc = hashcase;
|
hashfunc = hash;
|
||||||
matchfunc = NULL;
|
matchfunc = NULL;
|
||||||
matchintfunc = matchfile;
|
matchintfunc = matchfile;
|
||||||
InitializeHashTable(&cell_dict, CELLHASHSIZE);
|
InitializeHashTable(&cell_dict, CELLHASHSIZE);
|
||||||
|
|
@ -476,7 +424,6 @@ int removeshorted(struct hashlist *p, int file)
|
||||||
ob = nob;
|
ob = nob;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove shorted instances of class "class" from the database */
|
/* Remove shorted instances of class "class" from the database */
|
||||||
|
|
@ -492,32 +439,15 @@ void RemoveShorted(char *class, int file)
|
||||||
RecurseCellFileHashTable(removeshorted, 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)
|
int deleteclass(struct hashlist *p, int file)
|
||||||
{
|
{
|
||||||
struct nlist *ptr;
|
struct nlist *ptr;
|
||||||
struct objlist *ob, *lob, *nob, *portnode;
|
struct objlist *ob, *lob, *nob;
|
||||||
unsigned char *checknodes;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ptr = (struct nlist *)(p->ptr);
|
ptr = (struct nlist *)(p->ptr);
|
||||||
|
|
||||||
if ((file != -1) && (ptr->file != file)) return 0;
|
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;
|
lob = NULL;
|
||||||
for (ob = ptr->cell; ob != NULL;) {
|
for (ob = ptr->cell; ob != NULL;) {
|
||||||
nob = ob->next;
|
nob = ob->next;
|
||||||
|
|
@ -525,8 +455,6 @@ int deleteclass(struct hashlist *p, int file)
|
||||||
if ((*matchfunc)(ob->model.class, OldCell->name)) {
|
if ((*matchfunc)(ob->model.class, OldCell->name)) {
|
||||||
HashDelete(ob->instance.name, &(ptr->instdict));
|
HashDelete(ob->instance.name, &(ptr->instdict));
|
||||||
while (1) {
|
while (1) {
|
||||||
if (ob->type >= FIRSTPIN)
|
|
||||||
checknodes[ob->node] = (unsigned char)1;
|
|
||||||
FreeObjectAndHash(ob, ptr);
|
FreeObjectAndHash(ob, ptr);
|
||||||
ob = nob;
|
ob = nob;
|
||||||
if (ob == NULL) break;
|
if (ob == NULL) break;
|
||||||
|
|
@ -548,26 +476,6 @@ int deleteclass(struct hashlist *p, int file)
|
||||||
ob = nob;
|
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 */
|
/* Remove all instances of class "class" from the database */
|
||||||
|
|
@ -605,7 +513,6 @@ int renameinstances(struct hashlist *p, int file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceRename(char *from, char *to, int file)
|
void InstanceRename(char *from, char *to, int file)
|
||||||
|
|
@ -628,10 +535,9 @@ int freeprop(struct hashlist *p)
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
|
|
||||||
prop = (struct property *)(p->ptr);
|
prop = (struct property *)(p->ptr);
|
||||||
if (prop->type == PROP_STRING) {
|
if (prop->type == PROP_STRING)
|
||||||
if (prop->pdefault.string != NULL)
|
if (prop->pdefault.string != NULL)
|
||||||
FREE(prop->pdefault.string);
|
FREE(prop->pdefault.string);
|
||||||
}
|
|
||||||
else if (prop->type == PROP_EXPRESSION) {
|
else if (prop->type == PROP_EXPRESSION) {
|
||||||
struct tokstack *stackptr, *nptr;
|
struct tokstack *stackptr, *nptr;
|
||||||
stackptr = prop->pdefault.stack;
|
stackptr = prop->pdefault.stack;
|
||||||
|
|
@ -650,65 +556,65 @@ int freeprop(struct hashlist *p)
|
||||||
|
|
||||||
void CellDelete(char *name, int fnum)
|
void CellDelete(char *name, int fnum)
|
||||||
{
|
{
|
||||||
/* delete all the contents of cell 'name', and remove 'name' from
|
/* delete all the contents of cell 'name', and remove 'name' from
|
||||||
the cell hash table. NOTE: this procedure does not care or check
|
the cell hash table. NOTE: this procedure does not care or check
|
||||||
if 'name' has been instanced anywhere. It is assumed that if this
|
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.
|
is the case, the user will (quickly) define a new cell of that name.
|
||||||
*/
|
*/
|
||||||
struct objlist *ob, *obnext;
|
struct objlist *ob, *obnext;
|
||||||
struct nlist *tp;
|
struct nlist *tp;
|
||||||
|
|
||||||
tp = LookupCellFile(name, fnum);
|
tp = LookupCellFile(name, fnum);
|
||||||
if (tp == NULL) {
|
if (tp == NULL) {
|
||||||
Printf ("No cell '%s' found.\n", name);
|
Printf ("No cell '%s' found.\n", name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashIntDelete(name, fnum, &cell_dict);
|
HashIntDelete(name, fnum, &cell_dict);
|
||||||
/* now make sure that we free all the fields of the nlist struct */
|
/* now make sure that we free all the fields of the nlist struct */
|
||||||
if (tp->name != NULL) FREE(tp->name);
|
if (tp->name != NULL) FREE(tp->name);
|
||||||
HashKill(&(tp->objdict));
|
HashKill(&(tp->objdict));
|
||||||
HashKill(&(tp->instdict));
|
HashKill(&(tp->instdict));
|
||||||
RecurseHashTable(&(tp->propdict), freeprop);
|
RecurseHashTable(&(tp->propdict), freeprop);
|
||||||
HashKill(&(tp->propdict));
|
HashKill(&(tp->propdict));
|
||||||
FreeNodeNames(tp);
|
FreeNodeNames(tp);
|
||||||
ob = tp->cell;
|
ob = tp->cell;
|
||||||
while (ob != NULL) {
|
while (ob != NULL) {
|
||||||
obnext = ob->next;
|
obnext = ob->next;
|
||||||
FreeObject (ob);
|
FreeObject (ob);
|
||||||
ob = obnext;
|
ob = obnext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PrintCellHashTableElement(struct hashlist *p)
|
static int PrintCellHashTableElement(struct hashlist *p)
|
||||||
{
|
{
|
||||||
struct nlist *ptr;
|
struct nlist *ptr;
|
||||||
|
|
||||||
ptr = (struct nlist *)(p->ptr);
|
ptr = (struct nlist *)(p->ptr);
|
||||||
if ((TopFile >= 0) && (ptr->file != TopFile)) return 1;
|
if ((TopFile >= 0) && (ptr->file != TopFile)) return 1;
|
||||||
|
|
||||||
if ((ptr->class != CLASS_SUBCKT) && (ptr->class != CLASS_MODULE)) {
|
if (ptr->class != CLASS_SUBCKT) {
|
||||||
/* only print primitive cells if Debug is enabled */
|
/* only print primitive cells if Debug is enabled */
|
||||||
if (Debug == 1) Printf("Cell: %s (instanced %d times); Primitive\n",
|
if (Debug == 1) Printf("Cell: %s (instanced %d times); Primitive\n",
|
||||||
ptr->name, ptr->number);
|
ptr->name, ptr->number);
|
||||||
else if (Debug == 3) { /* list */
|
else if (Debug == 3) { /* list */
|
||||||
#ifdef TCL_NETGEN
|
#ifdef TCL_NETGEN
|
||||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||||
#else
|
#else
|
||||||
Printf("%s ", ptr->name);
|
Printf("%s ", ptr->name);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((Debug == 2) || (Debug == 3)) { /* list only */
|
else if ((Debug == 2) || (Debug == 3)) { /* list only */
|
||||||
#ifdef TCL_NETGEN
|
#ifdef TCL_NETGEN
|
||||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||||
#else
|
#else
|
||||||
Printf("%s ", ptr->name);
|
Printf("%s ", ptr->name);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Printf("Cell: %s (instanced %d times)\n", ptr->name, ptr->number);
|
Printf("Cell: %s (instanced %d times)\n",ptr->name,ptr->number);
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print the contents of the cell hash table. */
|
/* Print the contents of the cell hash table. */
|
||||||
|
|
@ -717,65 +623,65 @@ static int PrintCellHashTableElement(struct hashlist *p)
|
||||||
|
|
||||||
void PrintCellHashTable(int full, int filenum)
|
void PrintCellHashTable(int full, int filenum)
|
||||||
{
|
{
|
||||||
int total, bins;
|
int total, bins;
|
||||||
int OldDebug;
|
int OldDebug;
|
||||||
|
|
||||||
if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
|
if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
|
||||||
PrintCellHashTable(full, Circuit1->file);
|
PrintCellHashTable(full, Circuit1->file);
|
||||||
PrintCellHashTable(full, Circuit2->file);
|
PrintCellHashTable(full, Circuit2->file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TopFile = filenum;
|
TopFile = filenum;
|
||||||
|
|
||||||
bins = RecurseHashTable(&cell_dict, CountHashTableBinsUsed);
|
bins = RecurseHashTable(&cell_dict, CountHashTableBinsUsed);
|
||||||
total = RecurseHashTable(&cell_dict, CountHashTableEntries);
|
total = RecurseHashTable(&cell_dict, CountHashTableEntries);
|
||||||
if (full < 2)
|
if (full < 2)
|
||||||
Printf("Hash table: %d of %d bins used; %d cells total (%.2f per bin)\n",
|
Printf("Hash table: %d of %d bins used; %d cells total (%.2f per bin)\n",
|
||||||
bins, CELLHASHSIZE, total, (bins == 0) ? 0 :
|
bins, CELLHASHSIZE, total, (bins == 0) ? 0 :
|
||||||
(float)((float)total / (float)bins));
|
(float)((float)total / (float)bins));
|
||||||
|
|
||||||
OldDebug = Debug;
|
OldDebug = Debug;
|
||||||
Debug = full;
|
Debug = full;
|
||||||
RecurseHashTable(&cell_dict, PrintCellHashTableElement);
|
RecurseHashTable(&cell_dict, PrintCellHashTableElement);
|
||||||
Debug = OldDebug;
|
Debug = OldDebug;
|
||||||
#ifndef TCL_NETGEN
|
#ifndef TCL_NETGEN
|
||||||
if (full >= 2) Printf("\n");
|
if (full >= 2) Printf("\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nlist *FirstCell(void)
|
struct nlist *FirstCell(void)
|
||||||
{
|
{
|
||||||
return((struct nlist *)HashFirst(&cell_dict));
|
return((struct nlist *)HashFirst(&cell_dict));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nlist *NextCell(void)
|
struct nlist *NextCell(void)
|
||||||
{
|
{
|
||||||
return((struct nlist *)HashNext(&cell_dict));
|
return((struct nlist *)HashNext(&cell_dict));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ClearDumpedElement(struct hashlist *np)
|
static int ClearDumpedElement(struct hashlist *np)
|
||||||
{
|
{
|
||||||
struct nlist *p;
|
struct nlist *p;
|
||||||
|
|
||||||
p = (struct nlist *)(np->ptr);
|
p = (struct nlist *)(np->ptr);
|
||||||
p->dumped = 0;
|
p->dumped = 0;
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearDumpedList(void)
|
void ClearDumpedList(void)
|
||||||
{
|
{
|
||||||
RecurseHashTable(&cell_dict, ClearDumpedElement);
|
RecurseHashTable(&cell_dict, ClearDumpedElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
int RecurseCellHashTable(int (*foo)(struct hashlist *np))
|
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)
|
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 */
|
/* Yet another version, passing one parameter that is a pointer */
|
||||||
|
|
@ -783,14 +689,14 @@ int RecurseCellFileHashTable(int (*foo)(struct hashlist *, int), int value)
|
||||||
struct nlist *RecurseCellHashTable2(struct nlist *(*foo)(struct hashlist *,
|
struct nlist *RecurseCellHashTable2(struct nlist *(*foo)(struct hashlist *,
|
||||||
void *), void *pointer)
|
void *), void *pointer)
|
||||||
{
|
{
|
||||||
return RecurseHashTablePointer(&cell_dict, foo, pointer);
|
return RecurseHashTablePointer(&cell_dict, foo, pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************** WILD-CARD STUFF *******************************/
|
/************************** WILD-CARD STUFF *******************************/
|
||||||
|
|
||||||
char *FixTemplate(char *t)
|
char *FixTemplate(char *t)
|
||||||
{
|
{
|
||||||
char buffer[MAX_STR_LEN];
|
char buffer[200];
|
||||||
char *rstr;
|
char *rstr;
|
||||||
int i,j;
|
int i,j;
|
||||||
int InsideBrace;
|
int InsideBrace;
|
||||||
|
|
@ -1069,7 +975,6 @@ struct objlist *CopyObjList(struct objlist *oldlist, unsigned char doforall)
|
||||||
newob->model.class = NULL;
|
newob->model.class = NULL;
|
||||||
else
|
else
|
||||||
newob->model.class = strsave(tmp->model.class);
|
newob->model.class = strsave(tmp->model.class);
|
||||||
newob->flags = tmp->flags;
|
|
||||||
newob->instance.name = (tmp->instance.name) ?
|
newob->instance.name = (tmp->instance.name) ?
|
||||||
strsave(tmp->instance.name) : NULL;
|
strsave(tmp->instance.name) : NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -1207,17 +1112,13 @@ void FreeObjectAndHash(struct objlist *ob, struct nlist *ptr)
|
||||||
|
|
||||||
/*************** GENERAL UTILITIES ****************************/
|
/*************** GENERAL UTILITIES ****************************/
|
||||||
|
|
||||||
int NumberOfPorts(char *cellname, int file)
|
int NumberOfPorts(char *cellname)
|
||||||
{
|
{
|
||||||
struct nlist *tp;
|
struct nlist *tp;
|
||||||
struct objlist *ob;
|
struct objlist *ob;
|
||||||
int ports;
|
int ports;
|
||||||
|
|
||||||
if (file == -1)
|
tp = LookupCell(cellname);
|
||||||
tp = LookupCell(cellname);
|
|
||||||
else
|
|
||||||
tp = LookupCellFile(cellname, file);
|
|
||||||
|
|
||||||
if (tp == NULL) return(0);
|
if (tp == NULL) return(0);
|
||||||
ports = 0;
|
ports = 0;
|
||||||
for (ob = tp->cell; ob != NULL; ob = ob->next)
|
for (ob = tp->cell; ob != NULL; ob = ob->next)
|
||||||
|
|
@ -1301,7 +1202,7 @@ static char *OldNodeName(struct nlist *tp, int node)
|
||||||
struct objlist *firstuniqueglobal;
|
struct objlist *firstuniqueglobal;
|
||||||
struct objlist *firstglobal;
|
struct objlist *firstglobal;
|
||||||
struct objlist *firstpin;
|
struct objlist *firstpin;
|
||||||
static char StrBuffer[MAX_STR_LEN];
|
static char StrBuffer[100];
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* make second pass, looking for ports */
|
/* make second pass, looking for ports */
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@
|
||||||
|
|
||||||
#define PROXY (0) /* Used in model.port record of ports */
|
#define PROXY (0) /* Used in model.port record of ports */
|
||||||
|
|
||||||
#define NO_CONNECT 1 /* Use in object list to flag an isolated net */
|
|
||||||
|
|
||||||
/* Lists of device properties. Order is defined at the time of */
|
/* Lists of device properties. Order is defined at the time of */
|
||||||
/* the cell definition; values are sorted at the time instances */
|
/* the cell definition; values are sorted at the time instances */
|
||||||
/* are read. */
|
/* are read. */
|
||||||
|
|
@ -135,7 +133,6 @@ struct property {
|
||||||
unsigned char idx; /* index into valuelist */
|
unsigned char idx; /* index into valuelist */
|
||||||
unsigned char type; /* string, integer, double, value, expression */
|
unsigned char type; /* string, integer, double, value, expression */
|
||||||
unsigned char merge; /* how property changes when devices are merged */
|
unsigned char merge; /* how property changes when devices are merged */
|
||||||
char *pin; /* associated pin (or NULL if not associated) */
|
|
||||||
union {
|
union {
|
||||||
char *string;
|
char *string;
|
||||||
double dval;
|
double dval;
|
||||||
|
|
@ -165,7 +162,6 @@ struct objlist {
|
||||||
/* (string) value of property for properties */
|
/* (string) value of property for properties */
|
||||||
struct valuelist *props; /* Property record */
|
struct valuelist *props; /* Property record */
|
||||||
} instance;
|
} instance;
|
||||||
unsigned char flags; /* Used by NODE type to flag isolated net */
|
|
||||||
int node; /* the electrical node number of the port/node/pin */
|
int node; /* the electrical node number of the port/node/pin */
|
||||||
struct objlist *next;
|
struct objlist *next;
|
||||||
};
|
};
|
||||||
|
|
@ -196,8 +192,9 @@ struct Permutation {
|
||||||
struct Permutation *next;
|
struct Permutation *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OBJHASHSIZE 42073 /* the size of the object and instance hash lists */
|
#define OBJHASHSIZE 997 /* the size of the object and instance hash lists */
|
||||||
/* prime numbers are good choices as hash sizes */
|
/* prime numbers are good choices as hash sizes */
|
||||||
|
/* 101 is a good number for IBMPC */
|
||||||
|
|
||||||
/* cell definition for hash table */
|
/* cell definition for hash table */
|
||||||
/* NOTE: "file" must come first for the hash matching by name and file */
|
/* NOTE: "file" must come first for the hash matching by name and file */
|
||||||
|
|
@ -207,7 +204,7 @@ struct nlist {
|
||||||
char *name;
|
char *name;
|
||||||
int number; /* number of instances defined */
|
int number; /* number of instances defined */
|
||||||
int dumped; /* instance count, and general-purpose marker */
|
int dumped; /* instance count, and general-purpose marker */
|
||||||
unsigned short flags;
|
unsigned char flags;
|
||||||
unsigned char class;
|
unsigned char class;
|
||||||
unsigned long classhash; /* randomized hash value for cell class */
|
unsigned long classhash; /* randomized hash value for cell class */
|
||||||
struct Permutation *permutes; /* list of permuting pins */
|
struct Permutation *permutes; /* list of permuting pins */
|
||||||
|
|
@ -223,18 +220,17 @@ struct nlist {
|
||||||
|
|
||||||
/* Defined nlist structure flags */
|
/* Defined nlist structure flags */
|
||||||
|
|
||||||
#define CELL_MATCHED 0x001 /* cell matched to another */
|
#define CELL_MATCHED 0x01 /* cell matched to another */
|
||||||
#define CELL_NOCASE 0x002 /* cell is case-insensitive (e.g., SPICE) */
|
#define CELL_NOCASE 0x02 /* cell is case-insensitive (e.g., SPICE) */
|
||||||
#define CELL_TOP 0x004 /* cell is a top-level cell */
|
#define CELL_TOP 0x04 /* cell is a top-level cell */
|
||||||
#define CELL_PLACEHOLDER 0x008 /* cell is a placeholder cell */
|
#define CELL_PLACEHOLDER 0x08 /* cell is a placeholder cell */
|
||||||
#define CELL_PROPSMATCHED 0x010 /* properties matched to matching cell */
|
#define CELL_PROPSMATCHED 0x10 /* properties matched to matching cell */
|
||||||
#define CELL_DUPLICATE 0x020 /* cell has a duplicate */
|
#define CELL_DUPLICATE 0x20 /* cell has a duplicate */
|
||||||
#define CELL_VERILOG 0x040 /* cell is verilog module */
|
|
||||||
|
|
||||||
/* Flags for combination allowances and prohibitions */
|
/* Flags for combination allowances and prohibitions */
|
||||||
|
|
||||||
#define COMB_SERIES 0x100
|
#define COMB_SERIES 0x40
|
||||||
#define COMB_NO_PARALLEL 0x200
|
#define COMB_NO_PARALLEL 0x80
|
||||||
|
|
||||||
extern struct nlist *CurrentCell;
|
extern struct nlist *CurrentCell;
|
||||||
extern struct objlist *CurrentTail;
|
extern struct objlist *CurrentTail;
|
||||||
|
|
@ -246,7 +242,7 @@ extern void FreeObjectAndHash(struct objlist *ob, struct nlist *ptr);
|
||||||
extern void FreePorts(char *cellname);
|
extern void FreePorts(char *cellname);
|
||||||
extern struct IgnoreList *ClassIgnore;
|
extern struct IgnoreList *ClassIgnore;
|
||||||
|
|
||||||
extern int NumberOfPorts(char *cellname, int file);
|
extern int NumberOfPorts(char *cellname);
|
||||||
extern struct objlist *InstanceNumber(struct nlist *tp, int inst);
|
extern struct objlist *InstanceNumber(struct nlist *tp, int inst);
|
||||||
|
|
||||||
extern struct objlist *List(char *list_template);
|
extern struct objlist *List(char *list_template);
|
||||||
|
|
@ -309,26 +305,11 @@ extern int match(char *, char *);
|
||||||
extern int matchnocase(char *, char *);
|
extern int matchnocase(char *, char *);
|
||||||
extern int matchfile(char *, char *, int, int);
|
extern int matchfile(char *, char *, int, int);
|
||||||
extern int matchfilenocase(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 GarbageCollect(void);
|
||||||
extern void InitGarbageCollection(void);
|
extern void InitGarbageCollection(void);
|
||||||
extern void AddToGarbageList(struct objlist *head);
|
extern void AddToGarbageList(struct objlist *head);
|
||||||
|
|
||||||
extern void DeleteProperties(struct keyvalue **topptr);
|
|
||||||
extern void AddProperty(struct keyvalue **topptr, char *key, char *value);
|
|
||||||
extern void AddScaledProperty(struct keyvalue **topptr, char *key, char *value, double scale);
|
|
||||||
extern void DeleteProperties(struct keyvalue **topptr);
|
|
||||||
extern struct objlist *LinkProperties(char *model, struct keyvalue *topptr);
|
|
||||||
|
|
||||||
extern void ClassDelete(char *class, int file);
|
|
||||||
extern void RemoveShorted(char *class, int file);
|
|
||||||
extern void CellRehash(char *name, char *newname, int file);
|
|
||||||
|
|
||||||
/* defined in netgen.c */
|
|
||||||
extern int ConvertStringToInteger(char *string, int *ival);
|
|
||||||
|
|
||||||
#ifdef HAVE_MALLINFO
|
#ifdef HAVE_MALLINFO
|
||||||
void PrintMemoryStats(void);
|
void PrintMemoryStats(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
20
base/place.c
20
base/place.c
|
|
@ -511,8 +511,8 @@ int OpenEmbeddingFile(char *cellname, char *filename)
|
||||||
/* returns 1 if OK */
|
/* returns 1 if OK */
|
||||||
{
|
{
|
||||||
struct nlist *tp;
|
struct nlist *tp;
|
||||||
char outfilename[MAX_STR_LEN];
|
char outfilename[200];
|
||||||
char logfilename[MAX_STR_LEN];
|
char logfilename[200];
|
||||||
|
|
||||||
tp = LookupCell(cellname);
|
tp = LookupCell(cellname);
|
||||||
if (tp == NULL) {
|
if (tp == NULL) {
|
||||||
|
|
@ -783,7 +783,7 @@ void SetupArray(char *prompt1, char *prompt2, char *prompt3, int *data,
|
||||||
void (*proc)(void))
|
void (*proc)(void))
|
||||||
{
|
{
|
||||||
int i, oldfanout;
|
int i, oldfanout;
|
||||||
char name[MAX_STR_LEN];
|
char name[100];
|
||||||
|
|
||||||
Printf(prompt1);
|
Printf(prompt1);
|
||||||
for (i = 1; i <= MAX_TREE_DEPTH; i++)
|
for (i = 1; i <= MAX_TREE_DEPTH; i++)
|
||||||
|
|
@ -792,7 +792,7 @@ void SetupArray(char *prompt1, char *prompt2, char *prompt3, int *data,
|
||||||
|
|
||||||
oldfanout = 1;
|
oldfanout = 1;
|
||||||
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
|
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
|
||||||
char prompt[MAX_STR_LEN];
|
char prompt[100];
|
||||||
int newfanout;
|
int newfanout;
|
||||||
sprintf(prompt, prompt2, i);
|
sprintf(prompt, prompt2, i);
|
||||||
promptstring(prompt, name);
|
promptstring(prompt, name);
|
||||||
|
|
@ -822,7 +822,7 @@ void SetupArrayFromString(char *prompt1, char *prompt3, int *data,
|
||||||
void (*proc)(void), char *text)
|
void (*proc)(void), char *text)
|
||||||
{
|
{
|
||||||
int i, oldfanout, newfanout;
|
int i, oldfanout, newfanout;
|
||||||
char string[MAX_STR_LEN];
|
char string[100];
|
||||||
char *ch;
|
char *ch;
|
||||||
char *endch;
|
char *endch;
|
||||||
|
|
||||||
|
|
@ -929,7 +929,7 @@ void ToggleDebug(void)
|
||||||
void DescribeCell(char *name, int detail)
|
void DescribeCell(char *name, int detail)
|
||||||
{
|
{
|
||||||
Printf("Cell: %s contains %d instances, %d nodes and %d ports\n", name,
|
Printf("Cell: %s contains %d instances, %d nodes and %d ports\n", name,
|
||||||
NumberOfInstances(name), RenumberNodes(name), NumberOfPorts(name, -1));
|
NumberOfInstances(name), RenumberNodes(name), NumberOfPorts(name));
|
||||||
PrintEmbeddingTree(stdout,name,detail);
|
PrintEmbeddingTree(stdout,name,detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -962,7 +962,7 @@ void ProtoPrintParameters(void)
|
||||||
void PROTOCHIP(void)
|
void PROTOCHIP(void)
|
||||||
/* a simple command interpreter to manage embedding/routing */
|
/* a simple command interpreter to manage embedding/routing */
|
||||||
{
|
{
|
||||||
char name[MAX_STR_LEN];
|
char name[100];
|
||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
InitializeFanout();
|
InitializeFanout();
|
||||||
|
|
@ -1136,7 +1136,7 @@ void PROTOCHIP(void)
|
||||||
|
|
||||||
oldfanout = 1;
|
oldfanout = 1;
|
||||||
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
|
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
|
||||||
char prompt[MAX_STR_LEN];
|
char prompt[100];
|
||||||
int newfanout;
|
int newfanout;
|
||||||
sprintf(prompt,"Fanout for level %d (0 to quit): ",i);
|
sprintf(prompt,"Fanout for level %d (0 to quit): ",i);
|
||||||
promptstring(prompt, name);
|
promptstring(prompt, name);
|
||||||
|
|
@ -1168,7 +1168,7 @@ void PROTOCHIP(void)
|
||||||
|
|
||||||
oldfanout = 1;
|
oldfanout = 1;
|
||||||
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
|
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
|
||||||
char prompt[MAX_STR_LEN];
|
char prompt[100];
|
||||||
int newfanout;
|
int newfanout;
|
||||||
sprintf(prompt,"Common nodes for level %d (0 to quit): ",i);
|
sprintf(prompt,"Common nodes for level %d (0 to quit): ",i);
|
||||||
promptstring(prompt, name);
|
promptstring(prompt, name);
|
||||||
|
|
@ -1200,7 +1200,7 @@ void PROTOCHIP(void)
|
||||||
|
|
||||||
oldfanout = 1;
|
oldfanout = 1;
|
||||||
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
|
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
|
||||||
char prompt[MAX_STR_LEN];
|
char prompt[100];
|
||||||
int newfanout;
|
int newfanout;
|
||||||
sprintf(prompt,"Used leaves for level %d (0 to quit): ",i);
|
sprintf(prompt,"Used leaves for level %d (0 to quit): ",i);
|
||||||
promptstring(prompt, name);
|
promptstring(prompt, name);
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ extern int ColumnBase;
|
||||||
|
|
||||||
struct filestr {
|
struct filestr {
|
||||||
FILE *f;
|
FILE *f;
|
||||||
char buffer[MAX_STR_LEN];
|
char buffer[200];
|
||||||
int wrap; /* column to wrap around in, or 0 if no wrap */
|
int wrap; /* column to wrap around in, or 0 if no wrap */
|
||||||
} file_buffers[MAXFILES];
|
} file_buffers[MAXFILES];
|
||||||
|
|
||||||
|
|
@ -107,7 +107,7 @@ void Fprintf(FILE *f, char *format, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int FileIndex;
|
int FileIndex;
|
||||||
char tmpstr[MAX_STR_LEN];
|
char tmpstr[200];
|
||||||
int bufferlongenough;
|
int bufferlongenough;
|
||||||
int linewrapexceeded;
|
int linewrapexceeded;
|
||||||
|
|
||||||
|
|
@ -203,7 +203,7 @@ void Printf(char *format, ...)
|
||||||
void Printf(char *format, ...)
|
void Printf(char *format, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char tmpstr[MAX_STR_LEN];
|
char tmpstr[200];
|
||||||
|
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
vsprintf(tmpstr, format, ap);
|
vsprintf(tmpstr, format, ap);
|
||||||
|
|
|
||||||
30
base/query.c
30
base/query.c
|
|
@ -52,7 +52,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
static int SuppressPrompts = 0;
|
static int SuppressPrompts = 0;
|
||||||
static char InputLine[MAX_STR_LEN];
|
static char InputLine[200];
|
||||||
|
|
||||||
void typeahead(char *str)
|
void typeahead(char *str)
|
||||||
{
|
{
|
||||||
|
|
@ -73,7 +73,7 @@ but reads from 'promptstring_infile' if nec. */
|
||||||
/* If interactive, puts out 'prompt' */
|
/* If interactive, puts out 'prompt' */
|
||||||
{
|
{
|
||||||
char *nexttok;
|
char *nexttok;
|
||||||
char tmpstr[MAX_STR_LEN];
|
char tmpstr[200];
|
||||||
int echo;
|
int echo;
|
||||||
|
|
||||||
if (promptstring_infile == NULL)
|
if (promptstring_infile == NULL)
|
||||||
|
|
@ -319,7 +319,7 @@ void Fanout(char *cell, char *node, int filter)
|
||||||
while (ob != NULL) {
|
while (ob != NULL) {
|
||||||
char *obname = ob->name;
|
char *obname = ob->name;
|
||||||
if (*obname == '/') obname++;
|
if (*obname == '/') obname++;
|
||||||
if (ob->node == nodenum) {
|
if (ob->node == nodenum)
|
||||||
if (filter == ALLOBJECTS) {
|
if (filter == ALLOBJECTS) {
|
||||||
Printf(" %s (", obname);
|
Printf(" %s (", obname);
|
||||||
PrintObjectType(ob->type);
|
PrintObjectType(ob->type);
|
||||||
|
|
@ -331,7 +331,6 @@ void Fanout(char *cell, char *node, int filter)
|
||||||
else if (ob->type == filter) {
|
else if (ob->type == filter) {
|
||||||
Printf(" %s\n", obname);
|
Printf(" %s\n", obname);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ob = ob->next;
|
ob = ob->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -806,14 +805,11 @@ void DescribeInstance(char *name, int file)
|
||||||
/* All black-box modules and placeholders by definition have all */
|
/* All black-box modules and placeholders by definition have all */
|
||||||
/* disconnected pins, so don't report those. */
|
/* disconnected pins, so don't report those. */
|
||||||
|
|
||||||
if ((!(tp->flags & CELL_PLACEHOLDER)) && (tp->class != CLASS_MODULE)) {
|
if (!(tp->flags & CELL_PLACEHOLDER) && (tp->class != CLASS_MODULE))
|
||||||
// if (disconnectednodes == 0) Fprintf(stderr, "\n");
|
{
|
||||||
|
if (disconnectednodes == 0) Fprintf(stderr, "\n");
|
||||||
disconnectednodes++;
|
disconnectednodes++;
|
||||||
/* Don't report on ports marked "port_match_error", which is just confusing. */
|
Fprintf(stderr, "Cell %s disconnected node: %s\n", tp->name, ob->name);
|
||||||
if (strcmp(ob->name, "port_match_error")) {
|
|
||||||
Fprintf(stderr, "Cell %s (%d) disconnected node: %s\n",
|
|
||||||
tp->name, tp->file, ob->name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -911,7 +907,7 @@ void PrintLeavesInCell(char *cellname, int filenum)
|
||||||
np->dumped = 1;
|
np->dumped = 1;
|
||||||
|
|
||||||
if (np->class != CLASS_SUBCKT) {
|
if (np->class != CLASS_SUBCKT) {
|
||||||
Printf("%s; %d ports; Primitive.\n", cellname, NumberOfPorts(cellname, filenum));
|
Printf("%s; %d ports; Primitive.\n", cellname, NumberOfPorts(cellname));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -924,7 +920,7 @@ void PrintLeavesInCell(char *cellname, int filenum)
|
||||||
am_a_leaf = 0;
|
am_a_leaf = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (am_a_leaf) Printf("%s; %d ports\n", cellname, NumberOfPorts(cellname, filenum));
|
if (am_a_leaf) Printf("%s; %d ports\n", cellname, NumberOfPorts(cellname));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -934,7 +930,7 @@ static int PrintLeavesInCellHash(struct hashlist *p)
|
||||||
struct nlist *ptr;
|
struct nlist *ptr;
|
||||||
|
|
||||||
ptr = (struct nlist *)(p->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);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -960,8 +956,8 @@ void Query(void)
|
||||||
{
|
{
|
||||||
/* little interactive debugger */
|
/* little interactive debugger */
|
||||||
char reply;
|
char reply;
|
||||||
char repstr[MAX_STR_LEN];
|
char repstr[100];
|
||||||
char repstr2[MAX_STR_LEN];
|
char repstr2[100];
|
||||||
float StartTime; /* for elapsed CPU times */
|
float StartTime; /* for elapsed CPU times */
|
||||||
int Timing; /* if true, print times of each command */
|
int Timing; /* if true, print times of each command */
|
||||||
int filenum = -1;
|
int filenum = -1;
|
||||||
|
|
@ -1037,7 +1033,7 @@ void Query(void)
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
promptstring("Write Verilog: circuit name: ", repstr);
|
promptstring("Write Verilog: circuit name: ", repstr);
|
||||||
VerilogTop(repstr, filenum, "");
|
VerilogModule(repstr, filenum, "");
|
||||||
break;
|
break;
|
||||||
case 'E':
|
case 'E':
|
||||||
promptstring("Write ESACAP: circuit name: ", repstr);
|
promptstring("Write ESACAP: circuit name: ", repstr);
|
||||||
|
|
|
||||||
385
base/spice.c
385
base/spice.c
|
|
@ -21,15 +21,11 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
|
||||||
#include <strings.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#if 0
|
#if 0
|
||||||
#include <stdarg.h> /* what about varargs, like in pdutils.c ??? */
|
#include <stdarg.h> /* what about varargs, like in pdutils.c ??? */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h> /* for calloc(), free(), getenv() */
|
#include <stdlib.h> /* for calloc(), free(), getenv() */
|
||||||
#include <ctype.h> /* for toupper(), isascii() */
|
|
||||||
#ifndef IBMPC
|
#ifndef IBMPC
|
||||||
#include <sys/types.h> /* for getpwnam() tilde expansion */
|
#include <sys/types.h> /* for getpwnam() tilde expansion */
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
|
@ -44,9 +40,6 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
#include "objlist.h"
|
#include "objlist.h"
|
||||||
#include "netfile.h"
|
#include "netfile.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "query.h"
|
|
||||||
#include "objlist.h"
|
|
||||||
#include "netcmp.h"
|
|
||||||
|
|
||||||
// Global storage for parameters from .PARAM
|
// Global storage for parameters from .PARAM
|
||||||
struct hashdict spiceparams;
|
struct hashdict spiceparams;
|
||||||
|
|
@ -196,7 +189,7 @@ void SpiceSubCell(struct nlist *tp, int IsSubCell)
|
||||||
if (ob->type == PROPERTY) {
|
if (ob->type == PROPERTY) {
|
||||||
struct valuelist *vl;
|
struct valuelist *vl;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0;; i++) {
|
for (i == 0;; i++) {
|
||||||
vl = &(ob->instance.props[i]);
|
vl = &(ob->instance.props[i]);
|
||||||
if (vl->type == PROP_ENDLIST) break;
|
if (vl->type == PROP_ENDLIST) break;
|
||||||
else if (vl->type == PROP_VALUE) {
|
else if (vl->type == PROP_VALUE) {
|
||||||
|
|
@ -216,7 +209,7 @@ void SpiceSubCell(struct nlist *tp, int IsSubCell)
|
||||||
if (ob->type == PROPERTY) {
|
if (ob->type == PROPERTY) {
|
||||||
struct valuelist *vl;
|
struct valuelist *vl;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0;; i++) {
|
for (i == 0;; i++) {
|
||||||
vl = &(ob->instance.props[i]);
|
vl = &(ob->instance.props[i]);
|
||||||
if (vl->type == PROP_ENDLIST) break;
|
if (vl->type == PROP_ENDLIST) break;
|
||||||
else if (vl->type == PROP_VALUE) {
|
else if (vl->type == PROP_VALUE) {
|
||||||
|
|
@ -236,7 +229,7 @@ void SpiceSubCell(struct nlist *tp, int IsSubCell)
|
||||||
if (ob->type == PROPERTY) {
|
if (ob->type == PROPERTY) {
|
||||||
struct valuelist *vl;
|
struct valuelist *vl;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0;; i++) {
|
for (i == 0;; i++) {
|
||||||
vl = &(ob->instance.props[i]);
|
vl = &(ob->instance.props[i]);
|
||||||
if (vl->type == PROP_ENDLIST) break;
|
if (vl->type == PROP_ENDLIST) break;
|
||||||
else if (vl->type == PROP_VALUE) {
|
else if (vl->type == PROP_VALUE) {
|
||||||
|
|
@ -399,7 +392,7 @@ int renamepins(struct hashlist *p, int file)
|
||||||
ptr = (struct nlist *)(p->ptr);
|
ptr = (struct nlist *)(p->ptr);
|
||||||
|
|
||||||
if (ptr->file != file)
|
if (ptr->file != file)
|
||||||
return 0;
|
return 1;
|
||||||
|
|
||||||
for (ob = ptr->cell; ob != NULL; ob = ob->next) {
|
for (ob = ptr->cell; ob != NULL; ob = ob->next) {
|
||||||
if (ob->type == FIRSTPIN) {
|
if (ob->type == FIRSTPIN) {
|
||||||
|
|
@ -426,7 +419,6 @@ int renamepins(struct hashlist *p, int file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If any pins are marked unconnected, see if there are */
|
/* If any pins are marked unconnected, see if there are */
|
||||||
|
|
@ -481,6 +473,15 @@ void CleanupSubcell() {
|
||||||
SetClass(CLASS_MODULE);
|
SetClass(CLASS_MODULE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------*/
|
||||||
|
/* Structure for stacking nested subcircuit definitions */
|
||||||
|
/*------------------------------------------------------*/
|
||||||
|
|
||||||
|
struct cellstack {
|
||||||
|
char *cellname;
|
||||||
|
struct cellstack *next;
|
||||||
|
};
|
||||||
|
|
||||||
/*------------------------------------------------------*/
|
/*------------------------------------------------------*/
|
||||||
/* Push a subcircuit name onto the stack */
|
/* Push a subcircuit name onto the stack */
|
||||||
/*------------------------------------------------------*/
|
/*------------------------------------------------------*/
|
||||||
|
|
@ -523,27 +524,21 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||||
int warnings = 0, update = 0, hasports = 0;
|
int warnings = 0, update = 0, hasports = 0;
|
||||||
char *eqptr, devtype, in_subckt;
|
char *eqptr, devtype, in_subckt;
|
||||||
struct keyvalue *kvlist = NULL;
|
struct keyvalue *kvlist = NULL;
|
||||||
char inst[MAX_STR_LEN], model[MAX_STR_LEN], instname[MAX_STR_LEN];
|
char inst[256], model[256], instname[256];
|
||||||
struct nlist *tp, *tpsave;
|
struct nlist *tp;
|
||||||
struct objlist *parent, *sobj, *nobj, *lobj, *pobj;
|
struct objlist *parent, *sobj, *nobj, *lobj, *pobj;
|
||||||
|
|
||||||
inst[MAX_STR_LEN-1] = '\0';
|
inst[255] = '\0';
|
||||||
model[MAX_STR_LEN-1] = '\0';
|
model[255] = '\0';
|
||||||
instname[MAX_STR_LEN-1] = '\0';
|
instname[255] = '\0';
|
||||||
in_subckt = (char)0;
|
in_subckt = (char)0;
|
||||||
|
|
||||||
while (!EndParseFile()) {
|
while (!EndParseFile()) {
|
||||||
|
|
||||||
SkipTok(NULL); /* get the next token */
|
SkipTok(NULL); /* get the next token */
|
||||||
if ((EndParseFile()) && (nexttok == NULL)) break;
|
if ((EndParseFile()) && (nexttok == NULL)) break;
|
||||||
if (nexttok == NULL) break;
|
|
||||||
|
|
||||||
/* Handle comment lines. Note that some variants of CDL format
|
if (nexttok[0] == '*') SkipNewLine(NULL);
|
||||||
* 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")) {
|
else if (matchnocase(nexttok, ".SUBCKT")) {
|
||||||
SpiceTokNoNewline();
|
SpiceTokNoNewline();
|
||||||
|
|
@ -566,9 +561,8 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||||
|
|
||||||
/* Check for existence of the cell. We may need to rename it. */
|
/* Check for existence of the cell. We may need to rename it. */
|
||||||
|
|
||||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
snprintf(model, 99, "%s", nexttok);
|
||||||
tp = LookupCellFile(nexttok, filenum);
|
tp = LookupCellFile(nexttok, filenum);
|
||||||
tpsave = NULL;
|
|
||||||
|
|
||||||
/* Check for name conflict with duplicate cell names */
|
/* Check for name conflict with duplicate cell names */
|
||||||
/* This may mean that the cell was used before it was */
|
/* This may mean that the cell was used before it was */
|
||||||
|
|
@ -607,46 +601,11 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||||
tp = LookupCellFile(nexttok, filenum);
|
tp = LookupCellFile(nexttok, filenum);
|
||||||
}
|
}
|
||||||
else if (tp != NULL) { /* Make a new definition for an empty cell */
|
else if (tp != NULL) { /* Make a new definition for an empty cell */
|
||||||
/* Handle issue with SPICE read after verilog, where a placeholder
|
FreePorts(nexttok);
|
||||||
* was created from the verilog. (1) If the pin names are "1", "2",
|
CellDelete(nexttok, filenum); /* This removes any PLACEHOLDER flag */
|
||||||
* "3", then this is a SPICE placeholder, and just remove the CellDef
|
CellDef(model, filenum);
|
||||||
* and re-create it. Otherwise, create new cell "_PLACEHOLDER_".
|
tp = LookupCellFile(model, filenum);
|
||||||
* (2) After encountering .ends, run MatchPins between the two cells.
|
update = 1; /* Will need to update existing instances */
|
||||||
* (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 */
|
else if (tp == NULL) { /* Completely new cell, no name conflict */
|
||||||
CellDef(model, filenum);
|
CellDef(model, filenum);
|
||||||
|
|
@ -738,38 +697,6 @@ skip_ends:
|
||||||
if (*CellStackPtr) PopStack(CellStackPtr);
|
if (*CellStackPtr) PopStack(CellStackPtr);
|
||||||
if (*CellStackPtr) ReopenCellDef((*CellStackPtr)->cellname, filenum);
|
if (*CellStackPtr) ReopenCellDef((*CellStackPtr)->cellname, filenum);
|
||||||
SkipNewLine(NULL);
|
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")) {
|
else if (matchnocase(nexttok, ".MODEL")) {
|
||||||
unsigned char class = CLASS_SUBCKT;
|
unsigned char class = CLASS_SUBCKT;
|
||||||
|
|
@ -782,7 +709,7 @@ skip_ends:
|
||||||
|
|
||||||
SpiceTokNoNewline();
|
SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) continue; /* Ignore if no model name */
|
if (nexttok == NULL) continue; /* Ignore if no model name */
|
||||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
snprintf(model, 99, "%s", nexttok);
|
||||||
SpiceTokNoNewline();
|
SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
|
|
||||||
|
|
@ -831,10 +758,7 @@ skip_ends:
|
||||||
|
|
||||||
// Handle some commonly-used cards
|
// Handle some commonly-used cards
|
||||||
|
|
||||||
/* .GLOBAL and *.GLOBAL. Note that *.GLOBAL is excepted from comment-line
|
else if (matchnocase(nexttok, ".GLOBAL")) {
|
||||||
* handling, above, so any line starting with '*' is "*.GLOBAL".
|
|
||||||
*/
|
|
||||||
else if (matchnocase(nexttok, ".GLOBAL") || (nexttok[0] == '*')) {
|
|
||||||
while (nexttok != NULL) {
|
while (nexttok != NULL) {
|
||||||
int numnodes = 0;
|
int numnodes = 0;
|
||||||
SpiceTokNoNewline();
|
SpiceTokNoNewline();
|
||||||
|
|
@ -950,17 +874,6 @@ skip_ends:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ignore anything in a .CONTROL ... .ENDC block */
|
|
||||||
else if (matchnocase(nexttok, ".CONTROL")) {
|
|
||||||
while (1) {
|
|
||||||
SpiceSkipNewLine();
|
|
||||||
SkipTok(NULL);
|
|
||||||
if (EndParseFile()) break;
|
|
||||||
if (matchnocase(nexttok, ".ENDC"))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blackbox (library) mode---parse only subcircuits and models;
|
// Blackbox (library) mode---parse only subcircuits and models;
|
||||||
// ignore all components.
|
// ignore all components.
|
||||||
|
|
||||||
|
|
@ -969,29 +882,29 @@ skip_ends:
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (toupper(nexttok[0]) == 'Q') {
|
else if (toupper(nexttok[0]) == 'Q') {
|
||||||
char emitter[MAX_STR_LEN], base[MAX_STR_LEN], collector[MAX_STR_LEN];
|
char emitter[100], base[100], collector[100];
|
||||||
emitter[MAX_STR_LEN-1] = '\0';
|
emitter[99] = '\0';
|
||||||
base[MAX_STR_LEN-1] = '\0';
|
base[99] = '\0';
|
||||||
collector[MAX_STR_LEN-1] = '\0';
|
collector[99] = '\0';
|
||||||
|
|
||||||
if (!(*CellStackPtr)) {
|
if (!(*CellStackPtr)) {
|
||||||
CellDef(fname, filenum);
|
CellDef(fname, filenum);
|
||||||
PushStack(fname, CellStackPtr);
|
PushStack(fname, CellStackPtr);
|
||||||
}
|
}
|
||||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(collector, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(collector, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(base, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(base, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(emitter, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(emitter, nexttok, 99); SpiceTokNoNewline();
|
||||||
/* make sure all the nodes exist */
|
/* make sure all the nodes exist */
|
||||||
if (LookupObject(collector, CurrentCell) == NULL) Node(collector);
|
if (LookupObject(collector, CurrentCell) == NULL) Node(collector);
|
||||||
if (LookupObject(base, CurrentCell) == NULL) Node(base);
|
if (LookupObject(base, CurrentCell) == NULL) Node(base);
|
||||||
if (LookupObject(emitter, CurrentCell) == NULL) Node(emitter);
|
if (LookupObject(emitter, CurrentCell) == NULL) Node(emitter);
|
||||||
|
|
||||||
/* Read the device model */
|
/* Read the device model */
|
||||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
snprintf(model, 99, "%s", nexttok);
|
||||||
|
|
||||||
while (nexttok != NULL)
|
while (nexttok != NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -1022,30 +935,30 @@ skip_ends:
|
||||||
goto baddevice;
|
goto baddevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
|
snprintf(instname, 255, "%s%s", model, inst);
|
||||||
Cell(instname, model, collector, base, emitter);
|
Cell(instname, model, collector, base, emitter);
|
||||||
pobj = LinkProperties(model, kvlist);
|
pobj = LinkProperties(model, kvlist);
|
||||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||||
DeleteProperties(&kvlist);
|
DeleteProperties(&kvlist);
|
||||||
}
|
}
|
||||||
else if (toupper(nexttok[0]) == 'M') {
|
else if (toupper(nexttok[0]) == 'M') {
|
||||||
char drain[MAX_STR_LEN], gate[MAX_STR_LEN], source[MAX_STR_LEN], bulk[MAX_STR_LEN];
|
char drain[100], gate[100], source[100], bulk[100];
|
||||||
drain[MAX_STR_LEN-1] = '\0';
|
drain[99] = '\0';
|
||||||
gate[MAX_STR_LEN-1] = '\0';
|
gate[99] = '\0';
|
||||||
source[MAX_STR_LEN-1] = '\0';
|
source[99] = '\0';
|
||||||
bulk[MAX_STR_LEN-1] = '\0';
|
bulk[99] = '\0';
|
||||||
|
|
||||||
if (!(*CellStackPtr)) {
|
if (!(*CellStackPtr)) {
|
||||||
CellDef(fname, filenum);
|
CellDef(fname, filenum);
|
||||||
PushStack(fname, CellStackPtr);
|
PushStack(fname, CellStackPtr);
|
||||||
}
|
}
|
||||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(drain, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(drain, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(gate, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(gate, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(source, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(source, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
/* make sure all the nodes exist */
|
/* make sure all the nodes exist */
|
||||||
if (LookupObject(drain, CurrentCell) == NULL) Node(drain);
|
if (LookupObject(drain, CurrentCell) == NULL) Node(drain);
|
||||||
|
|
@ -1053,11 +966,11 @@ skip_ends:
|
||||||
if (LookupObject(source, CurrentCell) == NULL) Node(source);
|
if (LookupObject(source, CurrentCell) == NULL) Node(source);
|
||||||
|
|
||||||
/* handle the substrate node */
|
/* handle the substrate node */
|
||||||
strncpy(bulk, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(bulk, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (LookupObject(bulk, CurrentCell) == NULL) Node(bulk);
|
if (LookupObject(bulk, CurrentCell) == NULL) Node(bulk);
|
||||||
|
|
||||||
/* Read the device model */
|
/* Read the device model */
|
||||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
snprintf(model, 99, "%s", nexttok);
|
||||||
|
|
||||||
while (nexttok != NULL)
|
while (nexttok != NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -1095,7 +1008,7 @@ skip_ends:
|
||||||
goto baddevice;
|
goto baddevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
|
snprintf(instname, 255, "%s%s", model, inst);
|
||||||
Cell(instname, model, drain, gate, source, bulk);
|
Cell(instname, model, drain, gate, source, bulk);
|
||||||
pobj = LinkProperties(model, kvlist);
|
pobj = LinkProperties(model, kvlist);
|
||||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||||
|
|
@ -1109,19 +1022,19 @@ skip_ends:
|
||||||
SpiceSkipNewLine();
|
SpiceSkipNewLine();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
char ctop[MAX_STR_LEN], cbot[MAX_STR_LEN];
|
char ctop[100], cbot[100];
|
||||||
ctop[MAX_STR_LEN-1] = '\0';
|
ctop[99] = '\0';
|
||||||
cbot[MAX_STR_LEN-1] = '\0';
|
cbot[99] = '\0';
|
||||||
|
|
||||||
if (!(*CellStackPtr)) {
|
if (!(*CellStackPtr)) {
|
||||||
CellDef(fname, filenum);
|
CellDef(fname, filenum);
|
||||||
PushStack(fname, CellStackPtr);
|
PushStack(fname, CellStackPtr);
|
||||||
}
|
}
|
||||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(ctop, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(ctop, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(cbot, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(cbot, nexttok, 99); SpiceTokNoNewline();
|
||||||
|
|
||||||
/* make sure all the nodes exist */
|
/* make sure all the nodes exist */
|
||||||
if (LookupObject(ctop, CurrentCell) == NULL) Node(ctop);
|
if (LookupObject(ctop, CurrentCell) == NULL) Node(ctop);
|
||||||
|
|
@ -1140,7 +1053,7 @@ skip_ends:
|
||||||
|
|
||||||
model[0] = '\0';
|
model[0] = '\0';
|
||||||
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
|
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
|
||||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
snprintf(model, 99, "%s", nexttok);
|
||||||
|
|
||||||
/* Any other device properties? */
|
/* Any other device properties? */
|
||||||
while (nexttok != NULL)
|
while (nexttok != NULL)
|
||||||
|
|
@ -1153,7 +1066,7 @@ skip_ends:
|
||||||
}
|
}
|
||||||
else if (!strncmp(nexttok, "$[", 2)) {
|
else if (!strncmp(nexttok, "$[", 2)) {
|
||||||
// Support for CDL modeled capacitor format
|
// Support for CDL modeled capacitor format
|
||||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok + 2);
|
snprintf(model, 99, "%s", nexttok + 2);
|
||||||
if ((eqptr = strchr(model, ']')) != NULL)
|
if ((eqptr = strchr(model, ']')) != NULL)
|
||||||
*eqptr = '\0';
|
*eqptr = '\0';
|
||||||
}
|
}
|
||||||
|
|
@ -1186,7 +1099,7 @@ skip_ends:
|
||||||
usemodel = 1;
|
usemodel = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
|
snprintf(instname, 255, "%s%s", model, inst);
|
||||||
if (usemodel)
|
if (usemodel)
|
||||||
Cell(instname, model, ctop, cbot);
|
Cell(instname, model, ctop, cbot);
|
||||||
else
|
else
|
||||||
|
|
@ -1203,19 +1116,19 @@ skip_ends:
|
||||||
SpiceSkipNewLine();
|
SpiceSkipNewLine();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
char rtop[MAX_STR_LEN], rbot[MAX_STR_LEN];
|
char rtop[100], rbot[100];
|
||||||
rtop[MAX_STR_LEN-1] = '\0';
|
rtop[99] = '\0';
|
||||||
rbot[MAX_STR_LEN-1] = '\0';
|
rbot[99] = '\0';
|
||||||
|
|
||||||
if (!(*CellStackPtr)) {
|
if (!(*CellStackPtr)) {
|
||||||
CellDef(fname, filenum);
|
CellDef(fname, filenum);
|
||||||
PushStack(fname, CellStackPtr);
|
PushStack(fname, CellStackPtr);
|
||||||
}
|
}
|
||||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(rtop, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(rtop, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(rbot, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(rbot, nexttok, 99); SpiceTokNoNewline();
|
||||||
/* make sure all the nodes exist */
|
/* make sure all the nodes exist */
|
||||||
if (LookupObject(rtop, CurrentCell) == NULL) Node(rtop);
|
if (LookupObject(rtop, CurrentCell) == NULL) Node(rtop);
|
||||||
if (LookupObject(rbot, CurrentCell) == NULL) Node(rbot);
|
if (LookupObject(rbot, CurrentCell) == NULL) Node(rbot);
|
||||||
|
|
@ -1234,7 +1147,7 @@ skip_ends:
|
||||||
|
|
||||||
model[0] = '\0';
|
model[0] = '\0';
|
||||||
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
|
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
|
||||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
snprintf(model, 99, "%s", nexttok);
|
||||||
|
|
||||||
/* Any other device properties? */
|
/* Any other device properties? */
|
||||||
while (nexttok != NULL) {
|
while (nexttok != NULL) {
|
||||||
|
|
@ -1246,7 +1159,7 @@ skip_ends:
|
||||||
}
|
}
|
||||||
else if (!strncmp(nexttok, "$[", 2)) {
|
else if (!strncmp(nexttok, "$[", 2)) {
|
||||||
// Support for CDL modeled resistor format
|
// Support for CDL modeled resistor format
|
||||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok + 2);
|
snprintf(model, 99, "%s", nexttok + 2);
|
||||||
if ((eqptr = strchr(model, ']')) != NULL)
|
if ((eqptr = strchr(model, ']')) != NULL)
|
||||||
*eqptr = '\0';
|
*eqptr = '\0';
|
||||||
}
|
}
|
||||||
|
|
@ -1271,7 +1184,7 @@ skip_ends:
|
||||||
else if (CountPorts(model, filenum) != 2) {
|
else if (CountPorts(model, filenum) != 2) {
|
||||||
/* Modeled device: Make sure it has the right number of ports */
|
/* Modeled device: Make sure it has the right number of ports */
|
||||||
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a "
|
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a "
|
||||||
"resistor.\n", model);
|
"resistor.\n");
|
||||||
goto baddevice;
|
goto baddevice;
|
||||||
}
|
}
|
||||||
usemodel = 1;
|
usemodel = 1;
|
||||||
|
|
@ -1279,7 +1192,7 @@ skip_ends:
|
||||||
else
|
else
|
||||||
strcpy(model, "r"); /* Use default resistor model */
|
strcpy(model, "r"); /* Use default resistor model */
|
||||||
|
|
||||||
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
|
snprintf(instname, 255, "%s%s", model, inst);
|
||||||
if (usemodel)
|
if (usemodel)
|
||||||
Cell(instname, model, rtop, rbot);
|
Cell(instname, model, rtop, rbot);
|
||||||
else
|
else
|
||||||
|
|
@ -1290,25 +1203,25 @@ skip_ends:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (toupper(nexttok[0]) == 'D') { /* diode */
|
else if (toupper(nexttok[0]) == 'D') { /* diode */
|
||||||
char cathode[MAX_STR_LEN], anode[MAX_STR_LEN];
|
char cathode[100], anode[100];
|
||||||
cathode[MAX_STR_LEN-1] = '\0';
|
cathode[99] = '\0';
|
||||||
anode[MAX_STR_LEN-1] = '\0';
|
anode[99] = '\0';
|
||||||
|
|
||||||
if (!(*CellStackPtr)) {
|
if (!(*CellStackPtr)) {
|
||||||
CellDef(fname, filenum);
|
CellDef(fname, filenum);
|
||||||
PushStack(fname, CellStackPtr);
|
PushStack(fname, CellStackPtr);
|
||||||
}
|
}
|
||||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(anode, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(anode, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(cathode, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(cathode, nexttok, 99); SpiceTokNoNewline();
|
||||||
/* make sure all the nodes exist */
|
/* make sure all the nodes exist */
|
||||||
if (LookupObject(anode, CurrentCell) == NULL) Node(anode);
|
if (LookupObject(anode, CurrentCell) == NULL) Node(anode);
|
||||||
if (LookupObject(cathode, CurrentCell) == NULL) Node(cathode);
|
if (LookupObject(cathode, CurrentCell) == NULL) Node(cathode);
|
||||||
|
|
||||||
/* Read the device model */
|
/* Read the device model */
|
||||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
snprintf(model, 99, "%s", nexttok);
|
||||||
|
|
||||||
while (nexttok != NULL)
|
while (nexttok != NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -1337,7 +1250,7 @@ skip_ends:
|
||||||
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a diode.\n");
|
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a diode.\n");
|
||||||
goto baddevice;
|
goto baddevice;
|
||||||
}
|
}
|
||||||
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
|
snprintf(instname, 255, "%s%s", model, inst);
|
||||||
Cell(instname, model, anode, cathode);
|
Cell(instname, model, anode, cathode);
|
||||||
pobj = LinkProperties(model, kvlist);
|
pobj = LinkProperties(model, kvlist);
|
||||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||||
|
|
@ -1350,25 +1263,25 @@ skip_ends:
|
||||||
SpiceSkipNewLine();
|
SpiceSkipNewLine();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
char node1[MAX_STR_LEN], node2[MAX_STR_LEN], node3[MAX_STR_LEN], node4[MAX_STR_LEN];
|
char node1[100], node2[100], node3[100], node4[100];
|
||||||
node1[MAX_STR_LEN-1] = '\0';
|
node1[99] = '\0';
|
||||||
node2[MAX_STR_LEN-1] = '\0';
|
node2[99] = '\0';
|
||||||
node3[MAX_STR_LEN-1] = '\0';
|
node3[99] = '\0';
|
||||||
node4[MAX_STR_LEN-1] = '\0';
|
node4[99] = '\0';
|
||||||
|
|
||||||
if (!(*CellStackPtr)) {
|
if (!(*CellStackPtr)) {
|
||||||
CellDef(fname, filenum);
|
CellDef(fname, filenum);
|
||||||
PushStack(fname, CellStackPtr);
|
PushStack(fname, CellStackPtr);
|
||||||
}
|
}
|
||||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(node1, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(node1, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(node2, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(node2, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(node3, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(node3, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(node4, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(node4, nexttok, 99); SpiceTokNoNewline();
|
||||||
/* make sure all the nodes exist */
|
/* make sure all the nodes exist */
|
||||||
if (LookupObject(node1, CurrentCell) == NULL) Node(node1);
|
if (LookupObject(node1, CurrentCell) == NULL) Node(node1);
|
||||||
if (LookupObject(node2, CurrentCell) == NULL) Node(node2);
|
if (LookupObject(node2, CurrentCell) == NULL) Node(node2);
|
||||||
|
|
@ -1380,7 +1293,7 @@ skip_ends:
|
||||||
|
|
||||||
model[0] = '\0';
|
model[0] = '\0';
|
||||||
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
|
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
|
||||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
snprintf(model, 99, "%s", nexttok);
|
||||||
|
|
||||||
/* Any other device properties? */
|
/* Any other device properties? */
|
||||||
while (nexttok != NULL) {
|
while (nexttok != NULL) {
|
||||||
|
|
@ -1416,7 +1329,7 @@ skip_ends:
|
||||||
else
|
else
|
||||||
strcpy(model, "t"); /* Use default xline model */
|
strcpy(model, "t"); /* Use default xline model */
|
||||||
|
|
||||||
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
|
snprintf(instname, 255, "%s%s", model, inst);
|
||||||
|
|
||||||
if (usemodel)
|
if (usemodel)
|
||||||
Cell(instname, model, node1, node2, node3, node4);
|
Cell(instname, model, node1, node2, node3, node4);
|
||||||
|
|
@ -1429,20 +1342,20 @@ skip_ends:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (toupper(nexttok[0]) == 'L') { /* inductor */
|
else if (toupper(nexttok[0]) == 'L') { /* inductor */
|
||||||
char end_a[MAX_STR_LEN], end_b[MAX_STR_LEN];
|
char end_a[100], end_b[100];
|
||||||
int usemodel = 0;
|
int usemodel = 0;
|
||||||
end_a[MAX_STR_LEN-1] = '\0';
|
end_a[99] = '\0';
|
||||||
end_b[MAX_STR_LEN-1] = '\0';
|
end_b[99] = '\0';
|
||||||
|
|
||||||
if (!(*CellStackPtr)) {
|
if (!(*CellStackPtr)) {
|
||||||
CellDef(fname, filenum);
|
CellDef(fname, filenum);
|
||||||
PushStack(fname, CellStackPtr);
|
PushStack(fname, CellStackPtr);
|
||||||
}
|
}
|
||||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(end_a, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(end_a, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(end_b, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(end_b, nexttok, 99); SpiceTokNoNewline();
|
||||||
/* make sure all the nodes exist */
|
/* make sure all the nodes exist */
|
||||||
if (LookupObject(end_a, CurrentCell) == NULL) Node(end_a);
|
if (LookupObject(end_a, CurrentCell) == NULL) Node(end_a);
|
||||||
if (LookupObject(end_b, CurrentCell) == NULL) Node(end_b);
|
if (LookupObject(end_b, CurrentCell) == NULL) Node(end_b);
|
||||||
|
|
@ -1461,7 +1374,7 @@ skip_ends:
|
||||||
|
|
||||||
model[0] = '\0';
|
model[0] = '\0';
|
||||||
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
|
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
|
||||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
snprintf(model, 99, "%s", nexttok);
|
||||||
|
|
||||||
/* Any other device properties? */
|
/* Any other device properties? */
|
||||||
while (nexttok != NULL)
|
while (nexttok != NULL)
|
||||||
|
|
@ -1499,7 +1412,7 @@ skip_ends:
|
||||||
else
|
else
|
||||||
strcpy(model, "l"); /* Use default inductor model */
|
strcpy(model, "l"); /* Use default inductor model */
|
||||||
|
|
||||||
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
|
snprintf(instname, 255, "%s%s", model, inst);
|
||||||
if (usemodel)
|
if (usemodel)
|
||||||
Cell(instname, model, end_a, end_b);
|
Cell(instname, model, end_a, end_b);
|
||||||
else
|
else
|
||||||
|
|
@ -1513,38 +1426,25 @@ skip_ends:
|
||||||
/* black-box subcircuits (class MODULE): V, I, E */
|
/* black-box subcircuits (class MODULE): V, I, E */
|
||||||
|
|
||||||
else if (toupper(nexttok[0]) == 'V') { /* voltage source */
|
else if (toupper(nexttok[0]) == 'V') { /* voltage source */
|
||||||
char pos[MAX_STR_LEN], neg[MAX_STR_LEN];
|
char pos[100], neg[100];
|
||||||
pos[MAX_STR_LEN-1] = '\0';
|
pos[99] = '\0';
|
||||||
neg[MAX_STR_LEN-1] = '\0';
|
neg[99] = '\0';
|
||||||
|
|
||||||
if (!(*CellStackPtr)) {
|
if (!(*CellStackPtr)) {
|
||||||
CellDef(fname, filenum);
|
CellDef(fname, filenum);
|
||||||
PushStack(fname, CellStackPtr);
|
PushStack(fname, CellStackPtr);
|
||||||
}
|
}
|
||||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(pos, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(pos, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(neg, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(neg, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
/* make sure all the nodes exist */
|
/* make sure all the nodes exist */
|
||||||
if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
|
if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
|
||||||
if (LookupObject(neg, CurrentCell) == NULL) Node(neg);
|
if (LookupObject(neg, CurrentCell) == NULL) Node(neg);
|
||||||
|
|
||||||
/* Get voltage value (if present); save as property "value" */
|
/* Any device properties? */
|
||||||
|
|
||||||
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)
|
while (nexttok != NULL)
|
||||||
{
|
{
|
||||||
SpiceTokNoNewline();
|
SpiceTokNoNewline();
|
||||||
|
|
@ -1572,7 +1472,7 @@ skip_ends:
|
||||||
else if (CountPorts(model, filenum) != 2) {
|
else if (CountPorts(model, filenum) != 2) {
|
||||||
/* Modeled device: Make sure it has the right number of ports */
|
/* Modeled device: Make sure it has the right number of ports */
|
||||||
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a "
|
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a "
|
||||||
"voltage source.\n", inst);
|
"voltage source.\n");
|
||||||
goto baddevice;
|
goto baddevice;
|
||||||
}
|
}
|
||||||
Cell(instname, model, pos, neg);
|
Cell(instname, model, pos, neg);
|
||||||
|
|
@ -1581,19 +1481,19 @@ skip_ends:
|
||||||
DeleteProperties(&kvlist);
|
DeleteProperties(&kvlist);
|
||||||
}
|
}
|
||||||
else if (toupper(nexttok[0]) == 'I') { /* current source */
|
else if (toupper(nexttok[0]) == 'I') { /* current source */
|
||||||
char pos[MAX_STR_LEN], neg[MAX_STR_LEN];
|
char pos[100], neg[100];
|
||||||
pos[MAX_STR_LEN-1] = '\0';
|
pos[99] = '\0';
|
||||||
neg[MAX_STR_LEN-1] = '\0';
|
neg[99] = '\0';
|
||||||
|
|
||||||
if (!(*CellStackPtr)) {
|
if (!(*CellStackPtr)) {
|
||||||
CellDef(fname, filenum);
|
CellDef(fname, filenum);
|
||||||
PushStack(fname, CellStackPtr);
|
PushStack(fname, CellStackPtr);
|
||||||
}
|
}
|
||||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(pos, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(pos, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(neg, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(neg, nexttok, 99); SpiceTokNoNewline();
|
||||||
/* make sure all the nodes exist */
|
/* make sure all the nodes exist */
|
||||||
if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
|
if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
|
||||||
if (LookupObject(neg, CurrentCell) == NULL) Node(neg);
|
if (LookupObject(neg, CurrentCell) == NULL) Node(neg);
|
||||||
|
|
@ -1635,25 +1535,25 @@ skip_ends:
|
||||||
DeleteProperties(&kvlist);
|
DeleteProperties(&kvlist);
|
||||||
}
|
}
|
||||||
else if (toupper(nexttok[0]) == 'E') { /* controlled voltage source */
|
else if (toupper(nexttok[0]) == 'E') { /* controlled voltage source */
|
||||||
char pos[MAX_STR_LEN], neg[MAX_STR_LEN], ctrlp[MAX_STR_LEN], ctrln[MAX_STR_LEN];
|
char pos[100], neg[100], ctrlp[100], ctrln[100];
|
||||||
pos[MAX_STR_LEN-1] = '\0';
|
pos[99] = '\0';
|
||||||
neg[MAX_STR_LEN-1] = '\0';
|
neg[99] = '\0';
|
||||||
ctrlp[MAX_STR_LEN-1] = '\0';
|
ctrlp[99] = '\0';
|
||||||
ctrln[MAX_STR_LEN-1] = '\0';
|
ctrln[99] = '\0';
|
||||||
|
|
||||||
if (!(*CellStackPtr)) {
|
if (!(*CellStackPtr)) {
|
||||||
CellDef(fname, filenum);
|
CellDef(fname, filenum);
|
||||||
PushStack(fname, CellStackPtr);
|
PushStack(fname, CellStackPtr);
|
||||||
}
|
}
|
||||||
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(pos, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(pos, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(neg, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(neg, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(ctrlp, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(ctrlp, nexttok, 99); SpiceTokNoNewline();
|
||||||
if (nexttok == NULL) goto baddevice;
|
if (nexttok == NULL) goto baddevice;
|
||||||
strncpy(ctrln, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
|
strncpy(ctrln, nexttok, 99); SpiceTokNoNewline();
|
||||||
|
|
||||||
/* make sure all the nodes exist */
|
/* make sure all the nodes exist */
|
||||||
if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
|
if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
|
||||||
|
|
@ -1701,11 +1601,11 @@ skip_ends:
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (toupper(nexttok[0]) == 'X') { /* subcircuit instances */
|
else if (toupper(nexttok[0]) == 'X') { /* subcircuit instances */
|
||||||
char instancename[MAX_STR_LEN], subcktname[MAX_STR_LEN];
|
char instancename[100], subcktname[100];
|
||||||
int itype, in_props;
|
int itype, in_props;
|
||||||
|
|
||||||
instancename[MAX_STR_LEN-1] = '\0';
|
instancename[99] = '\0';
|
||||||
subcktname[MAX_STR_LEN-1] = '\0';
|
subcktname[99] = '\0';
|
||||||
|
|
||||||
struct portelement {
|
struct portelement {
|
||||||
char *name;
|
char *name;
|
||||||
|
|
@ -1715,8 +1615,8 @@ skip_ends:
|
||||||
struct portelement *head, *tail, *scan, *scannext;
|
struct portelement *head, *tail, *scan, *scannext;
|
||||||
struct objlist *obptr;
|
struct objlist *obptr;
|
||||||
|
|
||||||
snprintf(instancename, MAX_STR_LEN-1, "%s", nexttok + 1);
|
snprintf(instancename, 99, "%s", nexttok + 1);
|
||||||
strncpy(instancename, nexttok + 1, MAX_STR_LEN-1);
|
strncpy(instancename, nexttok + 1, 99);
|
||||||
if (!(*CellStackPtr)) {
|
if (!(*CellStackPtr)) {
|
||||||
CellDef(fname, filenum);
|
CellDef(fname, filenum);
|
||||||
PushStack(fname, CellStackPtr);
|
PushStack(fname, CellStackPtr);
|
||||||
|
|
@ -1783,19 +1683,10 @@ skip_ends:
|
||||||
if (scan->next != NULL) scan = scan->next;
|
if (scan->next != NULL) scan = scan->next;
|
||||||
tail->next = NULL;
|
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 */
|
/* Check for ignored class */
|
||||||
|
|
||||||
if ((itype = IsIgnored(scan->name, filenum)) == IGNORE_CLASS) {
|
if ((itype = IsIgnored(subcktname, filenum)) == IGNORE_CLASS) {
|
||||||
Printf("Class '%s' instanced in input but is being ignored.\n", scan->name);
|
Printf("Class '%s' instanced in input but is being ignored.\n", model);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1810,7 +1701,7 @@ skip_ends:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (shorted == (unsigned char)1) {
|
if (shorted == (unsigned char)1) {
|
||||||
Printf("Instance of '%s' is shorted, ignoring.\n", scan->name);
|
Printf("Instance of '%s' is shorted, ignoring.\n", subcktname);
|
||||||
while (head) {
|
while (head) {
|
||||||
p = head->next;
|
p = head->next;
|
||||||
FREE(head);
|
FREE(head);
|
||||||
|
|
@ -1833,14 +1724,14 @@ skip_ends:
|
||||||
/* names. */
|
/* names. */
|
||||||
|
|
||||||
if (strncmp(instancename, scan->name, strlen(scan->name))) {
|
if (strncmp(instancename, scan->name, strlen(scan->name))) {
|
||||||
snprintf(subcktname, MAX_STR_LEN-1, "%s:%s", scan->name, instancename);
|
snprintf(subcktname, 99, "%s%s", scan->name, instancename);
|
||||||
strcpy(instancename, subcktname);
|
strcpy(instancename, subcktname);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
snprintf(subcktname, MAX_STR_LEN-1, "/%s", instancename);
|
snprintf(subcktname, 99, "/%s", instancename);
|
||||||
strcpy(instancename, subcktname);
|
strcpy(instancename, subcktname);
|
||||||
}
|
}
|
||||||
snprintf(subcktname, MAX_STR_LEN-1, "%s", scan->name);
|
snprintf(subcktname, 99, "%s", scan->name);
|
||||||
|
|
||||||
if (scan == head) {
|
if (scan == head) {
|
||||||
head = NULL;
|
head = NULL;
|
||||||
|
|
@ -1874,18 +1765,6 @@ skip_ends:
|
||||||
ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */
|
ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */
|
||||||
update = 1;
|
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 */
|
/* nexttok is now NULL, scan->name points to class */
|
||||||
|
|
||||||
|
|
@ -2088,7 +1967,7 @@ void IncludeSpice(char *fname, int parent, struct cellstack **CellStackPtr,
|
||||||
int blackbox)
|
int blackbox)
|
||||||
{
|
{
|
||||||
int filenum = -1;
|
int filenum = -1;
|
||||||
char name[MAX_STR_LEN];
|
char name[256];
|
||||||
|
|
||||||
/* If fname does not begin with "/", then assume that it is */
|
/* If fname does not begin with "/", then assume that it is */
|
||||||
/* in the same relative path as its parent. */
|
/* in the same relative path as its parent. */
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
#ifndef _TECH_H
|
|
||||||
#define _TECH_H
|
|
||||||
|
|
||||||
extern int ActelLibPresent(void);
|
|
||||||
extern void ActelLib(void);
|
|
||||||
extern void VerilogTop(char *name, int fnum, char *filename);
|
|
||||||
|
|
||||||
#endif /* _TECH_H */
|
|
||||||
|
|
@ -34,8 +34,6 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void Finsert(FILE *f);
|
|
||||||
|
|
||||||
void test_entry(void)
|
void test_entry(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
||||||
1452
base/verilog.c
1452
base/verilog.c
File diff suppressed because it is too large
Load Diff
|
|
@ -23,7 +23,6 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#ifdef IBMPC
|
#ifdef IBMPC
|
||||||
#include <stdlib.h> /* for strtol on PC */
|
#include <stdlib.h> /* for strtol on PC */
|
||||||
|
|
@ -34,8 +33,6 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
#include "netfile.h"
|
#include "netfile.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "xilinx.h"
|
|
||||||
#include "flatten.h"
|
|
||||||
|
|
||||||
#define XILINXHASHSIZE 99
|
#define XILINXHASHSIZE 99
|
||||||
static long xilinxhashbase = 0xA00;
|
static long xilinxhashbase = 0xA00;
|
||||||
|
|
@ -135,8 +132,10 @@ char *xilinx_class(model)
|
||||||
}
|
}
|
||||||
return(model);
|
return(model);
|
||||||
}
|
}
|
||||||
|
void
|
||||||
void Xilinx(char *cellname, char *filename)
|
Xilinx(cellname, filename)
|
||||||
|
char *cellname;
|
||||||
|
char *filename;
|
||||||
{
|
{
|
||||||
char Path[500];
|
char Path[500];
|
||||||
char FileName[500];
|
char FileName[500];
|
||||||
|
|
@ -164,7 +163,8 @@ void Xilinx(char *cellname, char *filename)
|
||||||
CloseFile(FileName);
|
CloseFile(FileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
int xilinxCell(char *cell)
|
xilinxCell(cell)
|
||||||
|
char *cell;
|
||||||
{
|
{
|
||||||
struct nlist *nl;
|
struct nlist *nl;
|
||||||
struct objlist *ob;
|
struct objlist *ob;
|
||||||
|
|
@ -252,7 +252,9 @@ struct objlist *xilinx_gate(ob,nl)
|
||||||
return(nob);
|
return(nob);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xilinx_sym(struct nlist *nl, struct objlist *gob)
|
xilinx_sym(nl,gob)
|
||||||
|
struct nlist *nl;
|
||||||
|
struct objlist *gob;
|
||||||
{
|
{
|
||||||
struct objlist *ob;
|
struct objlist *ob;
|
||||||
char *cp,*rindex();
|
char *cp,*rindex();
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
#ifndef _XILINX_H
|
|
||||||
#define _XILINX_H
|
|
||||||
|
|
||||||
extern void xilinx_sym(struct nlist *nl, struct objlist *gob);
|
|
||||||
extern void Xilinx(char *cellname, char *filename);
|
|
||||||
extern int xilinxCell(char *cell);
|
|
||||||
extern int XilinxLibPresent(void);
|
|
||||||
extern void XilinxLib(void);
|
|
||||||
|
|
||||||
#endif /* _XILINX_H */
|
|
||||||
|
|
@ -65,10 +65,10 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
|
|
||||||
Widget toplevel = NULL;
|
Widget toplevel = NULL;
|
||||||
|
|
||||||
char GlobalFileName[MAX_STR_LEN],
|
char GlobalFileName[100],
|
||||||
GlobalCellName[MAX_STR_LEN],
|
GlobalCellName[100],
|
||||||
GlobalOtherName[MAX_STR_LEN],
|
GlobalOtherName[100],
|
||||||
GlobalDataName[MAX_STR_LEN];
|
GlobalDataName[100];
|
||||||
|
|
||||||
/*********************************************************
|
/*********************************************************
|
||||||
* Menu structure: attaches label string to a function,
|
* Menu structure: attaches label string to a function,
|
||||||
|
|
@ -1708,7 +1708,7 @@ void X_main_loop(int argc, char *argv[])
|
||||||
|
|
||||||
XmStringCharSet cs = "ISOLatin1";
|
XmStringCharSet cs = "ISOLatin1";
|
||||||
|
|
||||||
static char prompt_response[MAX_STR_LEN];
|
static char prompt_response[100];
|
||||||
int prompt_done;
|
int prompt_done;
|
||||||
int calling_editor; /* which string are we trying to get ? */
|
int calling_editor; /* which string are we trying to get ? */
|
||||||
#define FILE_NAME 1
|
#define FILE_NAME 1
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,4 @@
|
||||||
# all of its config scripts in a different directory than the configure
|
# all of its config scripts in a different directory than the configure
|
||||||
# script itself.
|
# script itself.
|
||||||
|
|
||||||
export CFLAGS="$CFLAGS -g"
|
( CFLAGS="-g" ; export CFLAGS ; cd scripts ; ./configure "$@" )
|
||||||
cd scripts
|
|
||||||
exec ./configure "$@"
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ along with this program; see the file copying. If not, write to
|
||||||
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
|
|
||||||
/* inetcomp.c -- a simple wrapper to the NETCOMP() function */
|
/* inetcomp.c -- a simple wrapper to the NETCOMP() function */
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "netgen.h"
|
#include "netgen.h"
|
||||||
|
|
@ -34,7 +33,7 @@ void STRCPY(char *dest, char *source)
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
|
char cell1[200], cell2[200];
|
||||||
|
|
||||||
Debug = 0;
|
Debug = 0;
|
||||||
if (argc != 1) {
|
if (argc != 1) {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ along with this program; see the file copying. If not, write to
|
||||||
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
|
|
||||||
/* netcomp.c -- a simple wrapper to provide netlist comparison functionality */
|
/* netcomp.c -- a simple wrapper to provide netlist comparison functionality */
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "netgen.h"
|
#include "netgen.h"
|
||||||
|
|
@ -52,7 +51,7 @@ void STRCPY(char *dest, char *source)
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
#ifndef HAVE_GETOPT
|
#ifndef HAVE_GETOPT
|
||||||
char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
|
char cell1[200], cell2[200];
|
||||||
int filenum = -1;
|
int filenum = -1;
|
||||||
|
|
||||||
Debug = 0;
|
Debug = 0;
|
||||||
|
|
@ -68,7 +67,7 @@ int main(int argc, char *argv[])
|
||||||
STRCPY(cell2, ReadNetlist(argv[2], &filenum));
|
STRCPY(cell2, ReadNetlist(argv[2], &filenum));
|
||||||
if (argc == 5) STRCPY(cell2, argv[4]); /* if explicit cell name specified */
|
if (argc == 5) STRCPY(cell2, argv[4]); /* if explicit cell name specified */
|
||||||
#else
|
#else
|
||||||
char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
|
char cell1[200], cell2[200];
|
||||||
int usage = 0;
|
int usage = 0;
|
||||||
int args;
|
int args;
|
||||||
int c;
|
int c;
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
#include <stdlib.h> /* for getenv */
|
#include <stdlib.h> /* for getenv */
|
||||||
#endif
|
#endif
|
||||||
#include "netgen.h"
|
#include "netgen.h"
|
||||||
#include "print.h"
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,9 @@ along with this program; see the file copying. If not, write to
|
||||||
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||||
|
|
||||||
/* ntk2xnf.c -- a simple wrapper to translate .ntk to Xilinx XNF format */
|
/* ntk2xnf.c -- a simple wrapper to translate .ntk to Xilinx XNF format */
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "netgen.h"
|
#include "netgen.h"
|
||||||
#include "xilinx.h"
|
|
||||||
|
|
||||||
#ifdef HAVE_X11
|
#ifdef HAVE_X11
|
||||||
/* the following two X procedures are to permit linking
|
/* the following two X procedures are to permit linking
|
||||||
|
|
@ -49,7 +47,7 @@ void STRCPY(char *dest, char *source)
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char cellname[MAX_STR_LEN];
|
char cellname[200];
|
||||||
int filenum = -1;
|
int filenum = -1;
|
||||||
|
|
||||||
Debug = 0;
|
Debug = 0;
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,6 @@ SCRIPTINSTALL = $(DESTDIR)${INSTALL_PYDIR}
|
||||||
|
|
||||||
include ${NETGENDIR}/defs.mak
|
include ${NETGENDIR}/defs.mak
|
||||||
|
|
||||||
CLEANS += lvs_manager.py
|
|
||||||
|
|
||||||
main: lvs_manager.py
|
main: lvs_manager.py
|
||||||
|
|
||||||
tcl-main: lvs_manager.py
|
tcl-main: lvs_manager.py
|
||||||
|
|
@ -29,7 +27,6 @@ lvs_manager.py: lvs_manager.py.in
|
||||||
$(DESTDIR)${INSTALL_PYDIR}/lvs_manager.py: lvs_manager.py
|
$(DESTDIR)${INSTALL_PYDIR}/lvs_manager.py: lvs_manager.py
|
||||||
${RM} $@
|
${RM} $@
|
||||||
${CP} lvs_manager.py $@
|
${CP} lvs_manager.py $@
|
||||||
chmod a+x $@
|
|
||||||
|
|
||||||
$(DESTDIR)${INSTALL_PYDIR}/treeviewsplit.py: treeviewsplit.py
|
$(DESTDIR)${INSTALL_PYDIR}/treeviewsplit.py: treeviewsplit.py
|
||||||
${RM} $@
|
${RM} $@
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,819 @@
|
||||||
|
#!/bin/env python3
|
||||||
|
#
|
||||||
|
#--------------------------------------------------------
|
||||||
|
# LVS Manager GUI.
|
||||||
|
#
|
||||||
|
# This is a Python tkinter script that handles the
|
||||||
|
# process of running LVS and interpreting results.
|
||||||
|
#
|
||||||
|
#--------------------------------------------------------
|
||||||
|
# Written by Tim Edwards
|
||||||
|
# efabless, inc.
|
||||||
|
# Version 1. November 30, 2016
|
||||||
|
# Version 2. March 6, 2017. Reads JSON format output
|
||||||
|
# Version 3. April 25, 2018. Handles layout vs. verilog
|
||||||
|
#--------------------------------------------------------
|
||||||
|
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import shutil
|
||||||
|
import signal
|
||||||
|
import socket
|
||||||
|
import select
|
||||||
|
import datetime
|
||||||
|
import contextlib
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
import tkinter
|
||||||
|
from tkinter import ttk
|
||||||
|
from tkinter import filedialog
|
||||||
|
|
||||||
|
import tksimpledialog
|
||||||
|
import tooltip
|
||||||
|
from consoletext import ConsoleText
|
||||||
|
from helpwindow import HelpWindow
|
||||||
|
from treeviewsplit import TreeViewSplit
|
||||||
|
|
||||||
|
# User preferences file (if it exists)
|
||||||
|
prefsfile = '~/.profile/prefs.json'
|
||||||
|
|
||||||
|
netgen_script_dir = '/usr/local/lib/netgen/python'
|
||||||
|
|
||||||
|
#------------------------------------------------------
|
||||||
|
# Simple dialog for confirming quit
|
||||||
|
#------------------------------------------------------
|
||||||
|
|
||||||
|
class ConfirmDialog(tksimpledialog.Dialog):
|
||||||
|
def body(self, master, warning, seed):
|
||||||
|
if warning:
|
||||||
|
ttk.Label(master, text=warning, wraplength=500).grid(row = 0, columnspan = 2, sticky = 'wns')
|
||||||
|
return self
|
||||||
|
|
||||||
|
def apply(self):
|
||||||
|
return 'okay'
|
||||||
|
|
||||||
|
#------------------------------------------------------
|
||||||
|
# Main class for this application
|
||||||
|
#------------------------------------------------------
|
||||||
|
|
||||||
|
class LVSManager(ttk.Frame):
|
||||||
|
"""LVS Manager GUI."""
|
||||||
|
|
||||||
|
def __init__(self, parent, *args, **kwargs):
|
||||||
|
ttk.Frame.__init__(self, parent, *args, **kwargs)
|
||||||
|
self.root = parent
|
||||||
|
self.init_gui()
|
||||||
|
parent.protocol("WM_DELETE_WINDOW", self.on_quit)
|
||||||
|
|
||||||
|
def on_quit(self):
|
||||||
|
"""Exits program."""
|
||||||
|
if self.msock:
|
||||||
|
self.msock.close()
|
||||||
|
quit()
|
||||||
|
|
||||||
|
def init_gui(self):
|
||||||
|
"""Builds GUI."""
|
||||||
|
global prefsfile
|
||||||
|
|
||||||
|
message = []
|
||||||
|
fontsize = 11
|
||||||
|
|
||||||
|
# Read user preferences file, get default font size from it.
|
||||||
|
prefspath = os.path.expanduser(prefsfile)
|
||||||
|
if os.path.exists(prefspath):
|
||||||
|
with open(prefspath, 'r') as f:
|
||||||
|
self.prefs = json.load(f)
|
||||||
|
if 'fontsize' in self.prefs:
|
||||||
|
fontsize = self.prefs['fontsize']
|
||||||
|
else:
|
||||||
|
self.prefs = {}
|
||||||
|
|
||||||
|
s = ttk.Style()
|
||||||
|
|
||||||
|
available_themes = s.theme_names()
|
||||||
|
s.theme_use(available_themes[0])
|
||||||
|
|
||||||
|
s.configure('bg.TFrame', background='gray40')
|
||||||
|
s.configure('italic.TLabel', font=('Helvetica', fontsize, 'italic'))
|
||||||
|
s.configure('title.TLabel', font=('Helvetica', fontsize, 'bold italic'),
|
||||||
|
foreground = 'brown', anchor = 'center')
|
||||||
|
s.configure('normal.TLabel', font=('Helvetica', fontsize))
|
||||||
|
s.configure('red.TLabel', font=('Helvetica', fontsize), foreground = 'red')
|
||||||
|
s.configure('green.TLabel', font=('Helvetica', fontsize), foreground = 'green3')
|
||||||
|
s.configure('blue.TLabel', font=('Helvetica', fontsize), foreground = 'blue')
|
||||||
|
s.configure('normal.TButton', font=('Helvetica', fontsize),
|
||||||
|
border = 3, relief = 'raised')
|
||||||
|
s.configure('red.TButton', font=('Helvetica', fontsize), foreground = 'red',
|
||||||
|
border = 3, relief = 'raised')
|
||||||
|
s.configure('green.TButton', font=('Helvetica', fontsize), foreground = 'green3',
|
||||||
|
border = 3, relief = 'raised')
|
||||||
|
s.configure('blue.TButton', font=('Helvetica', fontsize), foreground = 'blue',
|
||||||
|
border = 3, relief = 'raised')
|
||||||
|
s.configure('redtitle.TButton', font=('Helvetica', fontsize, 'bold italic'),
|
||||||
|
foreground = 'red', border = 3, relief = 'raised')
|
||||||
|
s.configure('bluetitle.TButton', font=('Helvetica', fontsize, 'bold italic'),
|
||||||
|
foreground = 'blue', border = 3, relief = 'raised')
|
||||||
|
|
||||||
|
# These values to be overridden from arguments
|
||||||
|
self.rootpath = None
|
||||||
|
self.project = None
|
||||||
|
self.logfile = None
|
||||||
|
self.msock = None
|
||||||
|
self.help = None
|
||||||
|
|
||||||
|
# Create the help window
|
||||||
|
if os.path.exists(netgen_script_dir + '/netgen_help.txt'):
|
||||||
|
self.help = HelpWindow(self, fontsize = fontsize)
|
||||||
|
with io.StringIO() as buf, contextlib.redirect_stdout(buf):
|
||||||
|
self.help.add_pages_from_file('lvs_help.txt')
|
||||||
|
message = buf.getvalue()
|
||||||
|
|
||||||
|
# Set the help display to the first page
|
||||||
|
self.help.page(0)
|
||||||
|
|
||||||
|
# Variables used by option menus and other stuff
|
||||||
|
self.project = "(no selection)"
|
||||||
|
self.layout = "(default)"
|
||||||
|
self.schematic = "(default)"
|
||||||
|
self.tech = "(none)"
|
||||||
|
self.lvs_setup = ''
|
||||||
|
self.lvsdata = {}
|
||||||
|
|
||||||
|
# Root window title
|
||||||
|
self.root.title('LVS Manager')
|
||||||
|
self.root.option_add('*tearOff', 'FALSE')
|
||||||
|
self.pack(side = 'top', fill = 'both', expand = 'true')
|
||||||
|
|
||||||
|
pane = tkinter.PanedWindow(self, orient = 'vertical', sashrelief='groove', sashwidth=6)
|
||||||
|
pane.pack(side = 'top', fill = 'both', expand = 'true')
|
||||||
|
self.toppane = ttk.Frame(pane)
|
||||||
|
self.botpane = ttk.Frame(pane)
|
||||||
|
|
||||||
|
# Get username
|
||||||
|
if 'username' in self.prefs:
|
||||||
|
username = self.prefs['username']
|
||||||
|
else:
|
||||||
|
username = os.environ['USER']
|
||||||
|
|
||||||
|
# Label with the user
|
||||||
|
self.toppane.title_frame = ttk.Frame(self.toppane)
|
||||||
|
self.toppane.title_frame.pack(side = 'top', fill = 'x')
|
||||||
|
|
||||||
|
self.toppane.title_frame.title = ttk.Label(self.toppane.title_frame, text='User:', style = 'red.TLabel')
|
||||||
|
self.toppane.title_frame.user = ttk.Label(self.toppane.title_frame, text=username, style = 'blue.TLabel')
|
||||||
|
|
||||||
|
self.toppane.title_frame.title.grid(column=0, row=0, ipadx = 5)
|
||||||
|
self.toppane.title_frame.user.grid(column=1, row=0, ipadx = 5)
|
||||||
|
|
||||||
|
self.toppane.title2_frame = ttk.Frame(self.toppane)
|
||||||
|
self.toppane.title2_frame.pack(side = 'top', fill = 'x')
|
||||||
|
self.toppane.title2_frame.project_label = ttk.Label(self.toppane.title2_frame, text="Project:",
|
||||||
|
style = 'title.TLabel')
|
||||||
|
self.toppane.title2_frame.project_label.grid(column=0, row=0, ipadx = 5)
|
||||||
|
|
||||||
|
# New project select button
|
||||||
|
self.toppane.title2_frame.project_select = ttk.Button(self.toppane.title2_frame,
|
||||||
|
text=self.project, style='normal.TButton', command=self.choose_project)
|
||||||
|
self.toppane.title2_frame.project_select.grid(column=1, row=0, ipadx = 5)
|
||||||
|
|
||||||
|
tooltip.ToolTip(self.toppane.title2_frame.project_select,
|
||||||
|
text = "Select new project")
|
||||||
|
|
||||||
|
# Show path to project
|
||||||
|
self.toppane.title2_frame.path_label = ttk.Label(self.toppane.title2_frame, text=self.project,
|
||||||
|
style = 'normal.TLabel')
|
||||||
|
self.toppane.title2_frame.path_label.grid(column=2, row=0, ipadx = 5, padx = 10)
|
||||||
|
|
||||||
|
# Show top-level layout cellname with select button. Initial cell name is the top-level cell.
|
||||||
|
self.toppane.title2_frame.tech_label = ttk.Label(self.toppane.title2_frame, text="Technology setup:",
|
||||||
|
style = 'title.TLabel')
|
||||||
|
|
||||||
|
self.toppane.title2_frame.tech_label.grid(column=3, row=0, ipadx = 5)
|
||||||
|
self.toppane.title2_frame.tech_select = ttk.Button(self.toppane.title2_frame,
|
||||||
|
text=self.tech, style='normal.TButton', command=self.choose_tech)
|
||||||
|
self.toppane.title2_frame.tech_select.grid(column=4, row=0, ipadx = 3, padx = 3)
|
||||||
|
|
||||||
|
self.toppane.title2_frame.layout_label = ttk.Label(self.toppane.title2_frame, text="Layout:",
|
||||||
|
style = 'title.TLabel')
|
||||||
|
self.toppane.title2_frame.layout_label.grid(column=0, row=1, ipadx = 5)
|
||||||
|
self.toppane.title2_frame.layout_select = ttk.Button(self.toppane.title2_frame,
|
||||||
|
text=self.layout, style='normal.TButton', command=self.choose_layout)
|
||||||
|
self.toppane.title2_frame.layout_select.grid(column=1, row=1, ipadx = 3, padx = 3)
|
||||||
|
|
||||||
|
# Show top-level schematic cellname with select button. Initial cell name is the top-level cell.
|
||||||
|
self.toppane.title2_frame.schem_label = ttk.Label(self.toppane.title2_frame, text="Schematic:",
|
||||||
|
style = 'title.TLabel')
|
||||||
|
self.toppane.title2_frame.schem_label.grid(column=3, row=1, ipadx = 5)
|
||||||
|
self.toppane.title2_frame.schem_select = ttk.Button(self.toppane.title2_frame,
|
||||||
|
text=self.schematic, style='normal.TButton', command=self.choose_netlist)
|
||||||
|
self.toppane.title2_frame.schem_select.grid(column=4, row=1, ipadx = 3, padx = 3)
|
||||||
|
|
||||||
|
tooltip.ToolTip(self.toppane.title2_frame.project_select,
|
||||||
|
text = "Select new project")
|
||||||
|
tooltip.ToolTip(self.toppane.title2_frame.layout_select,
|
||||||
|
text = "Select a layout subcirucit to compare")
|
||||||
|
tooltip.ToolTip(self.toppane.title2_frame.schem_select,
|
||||||
|
text = "Select a schematic subcirucit to compare")
|
||||||
|
|
||||||
|
#---------------------------------------------
|
||||||
|
ttk.Separator(self.toppane, orient='horizontal').pack(side = 'top', fill = 'x')
|
||||||
|
#---------------------------------------------
|
||||||
|
|
||||||
|
# Create listbox of Circuit1 vs. Circuit2 results
|
||||||
|
height = 10
|
||||||
|
self.toppane.lvsreport = TreeViewSplit(self.toppane, fontsize = fontsize)
|
||||||
|
self.toppane.lvsreport.populate("Layout:", [], "Schematic:", [],
|
||||||
|
[["Run", True, self.run_lvs],
|
||||||
|
# ["Find", True, self.findrecord]
|
||||||
|
], height = height)
|
||||||
|
self.toppane.lvsreport.set_title("Line")
|
||||||
|
self.toppane.lvsreport.pack(side = 'top', fill = 'both', expand = 'true')
|
||||||
|
|
||||||
|
tooltip.ToolTip(self.toppane.lvsreport.get_button(0), text="Run LVS")
|
||||||
|
|
||||||
|
#---------------------------------------------
|
||||||
|
# ttk.Separator(self, orient='horizontal').grid(column=0, row=3, sticky='ew')
|
||||||
|
#---------------------------------------------
|
||||||
|
|
||||||
|
# Add a text window below the project name to capture output. Redirect
|
||||||
|
# print statements to it.
|
||||||
|
|
||||||
|
self.botpane.console = ttk.Frame(self.botpane)
|
||||||
|
self.botpane.console.pack(side = 'top', fill = 'both', expand = 'true')
|
||||||
|
|
||||||
|
self.text_box = ConsoleText(self.botpane.console, wrap='word', height = 4)
|
||||||
|
self.text_box.pack(side='left', fill='both', expand='true')
|
||||||
|
console_scrollbar = ttk.Scrollbar(self.botpane.console)
|
||||||
|
console_scrollbar.pack(side='right', fill='y')
|
||||||
|
# attach console to scrollbar
|
||||||
|
self.text_box.config(yscrollcommand = console_scrollbar.set)
|
||||||
|
console_scrollbar.config(command = self.text_box.yview)
|
||||||
|
|
||||||
|
# Add button bar at the bottom of the window
|
||||||
|
self.botpane.bbar = ttk.Frame(self.botpane)
|
||||||
|
self.botpane.bbar.pack(side = 'top', fill = 'x')
|
||||||
|
|
||||||
|
# Define the "quit" button and action
|
||||||
|
self.botpane.bbar.quit_button = ttk.Button(self.botpane.bbar, text='Quit', command=self.on_quit,
|
||||||
|
style = 'normal.TButton')
|
||||||
|
self.botpane.bbar.quit_button.grid(column=0, row=0, padx = 5)
|
||||||
|
|
||||||
|
# Define help button
|
||||||
|
if self.help:
|
||||||
|
self.botpane.bbar.help_button = ttk.Button(self.botpane.bbar, text='Help',
|
||||||
|
command=self.help.open, style = 'normal.TButton')
|
||||||
|
self.botpane.bbar.help_button.grid(column = 2, row = 0, padx = 5)
|
||||||
|
tooltip.ToolTip(self.botpane.bbar.help_button, text = "Show help window")
|
||||||
|
|
||||||
|
# Add the panes once the internal geometry is known.
|
||||||
|
pane.add(self.toppane)
|
||||||
|
pane.add(self.botpane)
|
||||||
|
pane.paneconfig(self.toppane, stretch='first')
|
||||||
|
|
||||||
|
# Redirect stdout and stderr to the console as the last thing to do. . .
|
||||||
|
# Otherwise errors in the GUI get sucked into the void.
|
||||||
|
|
||||||
|
self.stdout = sys.stdout
|
||||||
|
self.stderr = sys.stderr
|
||||||
|
sys.stdout = ConsoleText.StdoutRedirector(self.text_box)
|
||||||
|
sys.stderr = ConsoleText.StderrRedirector(self.text_box)
|
||||||
|
|
||||||
|
if message:
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
def logprint(self, message, doflush=False):
|
||||||
|
if self.logfile:
|
||||||
|
self.logfile.buffer.write(message.encode('utf-8'))
|
||||||
|
self.logfile.buffer.write('\n'.encode('utf-8'))
|
||||||
|
if doflush:
|
||||||
|
self.logfile.flush()
|
||||||
|
|
||||||
|
def printout(self, output):
|
||||||
|
# Generate output
|
||||||
|
if not output:
|
||||||
|
return
|
||||||
|
|
||||||
|
outlines = output.splitlines()
|
||||||
|
for line in outlines:
|
||||||
|
try:
|
||||||
|
print(line)
|
||||||
|
except TypeError:
|
||||||
|
line = line.decode('utf-8')
|
||||||
|
pritn(line)
|
||||||
|
|
||||||
|
def printwarn(self, output):
|
||||||
|
# Check output for warning or error
|
||||||
|
if not output:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
warnrex = re.compile('.*warning', re.IGNORECASE)
|
||||||
|
errrex = re.compile('.*error', re.IGNORECASE)
|
||||||
|
|
||||||
|
errors = 0
|
||||||
|
outlines = output.splitlines()
|
||||||
|
for line in outlines:
|
||||||
|
try:
|
||||||
|
wmatch = warnrex.match(line)
|
||||||
|
except TypeError:
|
||||||
|
line = line.decode('utf-8')
|
||||||
|
wmatch = warnrex.match(line)
|
||||||
|
ematch = errrex.match(line)
|
||||||
|
if ematch:
|
||||||
|
errors += 1
|
||||||
|
if ematch or wmatch:
|
||||||
|
print(line)
|
||||||
|
return errors
|
||||||
|
|
||||||
|
def choose_tech(self):
|
||||||
|
try:
|
||||||
|
project_path = self.rootpath
|
||||||
|
initdirname = self.rootpath + '/tech',
|
||||||
|
except:
|
||||||
|
print('Must choose a project first.')
|
||||||
|
return
|
||||||
|
techname = filedialog.askopenfilename(multiple=False,
|
||||||
|
initialdir = initdirname,
|
||||||
|
filetypes = (("Tcl script", "*.tcl"),("All Files","*.*")),
|
||||||
|
title = "Choose a netgen technology setup script.")
|
||||||
|
if techname != '':
|
||||||
|
print("Selected technology setup script " + techname)
|
||||||
|
techbase = os.path.split(techname)[1]
|
||||||
|
self.tech = os.path.splitext(techbase)[0]
|
||||||
|
self.lvs_setup = techname
|
||||||
|
self.toppane.title2_frame.layout_select.config(text = self.tech)
|
||||||
|
|
||||||
|
def choose_layout(self):
|
||||||
|
try:
|
||||||
|
project_path = self.rootpath
|
||||||
|
initdirname = self.rootpath + '/layout',
|
||||||
|
except:
|
||||||
|
print('Must choose a project first.')
|
||||||
|
return
|
||||||
|
cellname = filedialog.askopenfilename(multiple=False,
|
||||||
|
initialdir = initdirname,
|
||||||
|
filetypes = (("Magic layout", "*.mag"),("All Files","*.*")),
|
||||||
|
title = "Choose a layout cell to compare.")
|
||||||
|
if cellname != '':
|
||||||
|
print("Selected compare cell " + cellname)
|
||||||
|
cellbase = os.path.split(cellname)[1]
|
||||||
|
self.layout = os.path.splitext(cellbase)[0]
|
||||||
|
self.toppane.title2_frame.layout_select.config(text = self.layout)
|
||||||
|
|
||||||
|
def choose_netlist(self):
|
||||||
|
try:
|
||||||
|
project_path = self.rootpath
|
||||||
|
initdirname = self.rootpath + '/netlist/' + self.project + '.spi'
|
||||||
|
except:
|
||||||
|
print('Must choose a project first.')
|
||||||
|
return
|
||||||
|
cellname = filedialog.askopenfilename(multiple=False,
|
||||||
|
initialdir = initdirname,
|
||||||
|
filetypes = (("Spice netlist", "*.spi"),("Verilog netlist", "*.v")),
|
||||||
|
title = "Choose a netlist to compare.")
|
||||||
|
if cellname != '':
|
||||||
|
print("Selected compare cell " + cellname)
|
||||||
|
cellbase = os.path.split(cellname)[1]
|
||||||
|
self.schematic = os.path.splitext(cellbase)[0]
|
||||||
|
self.toppane.title2_frame.schem_select.config(text = self.schematic)
|
||||||
|
fileext = os.path.splitext(cellbase)[1]
|
||||||
|
if fileext == '.v':
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
|
||||||
|
elif fileext == '.sp' or fileext == '.spi' or fileext == '.spice' or fileext == '.spc' or fileext == '.ckt':
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'SPICE netlist:')
|
||||||
|
elif fileext == '.cdl':
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'CDL netlist:')
|
||||||
|
else:
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'Unknown netlist:')
|
||||||
|
|
||||||
|
def choose_project(self):
|
||||||
|
project = filedialog.askdirectory(initialdir = os.getcwd(),
|
||||||
|
title = "Find a project.")
|
||||||
|
if project != '':
|
||||||
|
print("Selected project " + str(project))
|
||||||
|
result = self.set_project(project)
|
||||||
|
|
||||||
|
def set_project(self, rootpath, project_name=None):
|
||||||
|
|
||||||
|
# Check if rootpath is valid. For LVS, there should be subdirectories
|
||||||
|
# "layout/" and "netlist/" or "verilog/".
|
||||||
|
|
||||||
|
haslay = os.path.isdir(rootpath + '/layout')
|
||||||
|
hasvlog = os.path.isdir(rootpath + '/verilog')
|
||||||
|
hasnet = os.path.isdir(rootpath + '/netlist')
|
||||||
|
if not haslay or not (hasvlog or hasnet):
|
||||||
|
if not haslay:
|
||||||
|
print("Project path has no layout (/layout) subdirectory.")
|
||||||
|
if not (hasvlog or hasnet):
|
||||||
|
print("Project path has no verilog (/verilog), or netlist (/netlist) subdirectory.")
|
||||||
|
# Continue anyway; assume that netlists will be selected manually
|
||||||
|
|
||||||
|
if self.logfile:
|
||||||
|
self.logfile.close()
|
||||||
|
self.logfile = None
|
||||||
|
|
||||||
|
if not project_name:
|
||||||
|
project = os.path.split(rootpath)[1]
|
||||||
|
else:
|
||||||
|
project = project_name
|
||||||
|
|
||||||
|
if self.project != project:
|
||||||
|
|
||||||
|
self.rootpath = rootpath
|
||||||
|
self.project = project
|
||||||
|
|
||||||
|
# Clear out old project data
|
||||||
|
self.toppane.lvsreport.repopulate([], [])
|
||||||
|
|
||||||
|
# Close any open logfile.
|
||||||
|
if self.logfile:
|
||||||
|
self.logfile.close()
|
||||||
|
self.logfile = None
|
||||||
|
|
||||||
|
# Put new log file called 'lvs.log' in the mag/ subdirectory
|
||||||
|
self.logfile = open(rootpath + '/layout/lvs.log', 'w')
|
||||||
|
# Print some initial information to the logfile.
|
||||||
|
self.logprint('Starting new log file ' + datetime.datetime.now().strftime('%c'),
|
||||||
|
doflush=True)
|
||||||
|
|
||||||
|
# Update project button
|
||||||
|
self.toppane.title2_frame.project_select.config(text = self.project)
|
||||||
|
self.toppane.title2_frame.path_label.config(text = self.rootpath)
|
||||||
|
# Cell name is the same as project name initially
|
||||||
|
self.layout = self.project
|
||||||
|
self.schematic = self.project
|
||||||
|
self.toppane.title2_frame.layout_select.config(text = self.layout)
|
||||||
|
self.toppane.title2_frame.schem_select.config(text = self.schematic)
|
||||||
|
|
||||||
|
# Update schematic button
|
||||||
|
if os.path.isfile(rootpath + '/verilog/' + self.schematic + '.v'):
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
|
||||||
|
else:
|
||||||
|
self.toppane.title2_frame.schem_label.config(text = 'Schematic netlist:')
|
||||||
|
|
||||||
|
# If there is a comparison file that post-dates both netlists, load it.
|
||||||
|
self.check_lvs()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def check_layout_out_of_date(self, spipath, layoutpath):
|
||||||
|
# Check if a netlist (spipath) is out-of-date relative to the layouts
|
||||||
|
# (layoutpath). Need to read the netlist and check all of the subcells.
|
||||||
|
need_capture = False
|
||||||
|
if not os.path.isfile(spipath):
|
||||||
|
return True
|
||||||
|
if os.path.isfile(layoutpath):
|
||||||
|
spi_statbuf = os.stat(spipath)
|
||||||
|
lay_statbuf = os.stat(layoutpath)
|
||||||
|
if spi_statbuf.st_mtime < lay_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
else:
|
||||||
|
# only found that the top-level-layout is older than the
|
||||||
|
# netlist. Now need to read the netlist, find all subcircuits,
|
||||||
|
# and check those dates, too.
|
||||||
|
layoutdir = os.path.split(layoutpath)[0]
|
||||||
|
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
||||||
|
with open(spipath, 'r') as ifile:
|
||||||
|
duttext = ifile.read()
|
||||||
|
|
||||||
|
dutlines = duttext.replace('\n+', ' ').splitlines()
|
||||||
|
for line in dutlines:
|
||||||
|
lmatch = subrex.match(line)
|
||||||
|
if lmatch:
|
||||||
|
subname = lmatch.group(1)
|
||||||
|
sublayout = layoutdir + '/' + subname + '.mag'
|
||||||
|
# subcircuits that cannot be found in the current directory are
|
||||||
|
# assumed to be library components and therefore never out-of-date.
|
||||||
|
if os.path.exists(sublayout):
|
||||||
|
sub_statbuf = os.stat(sublayout)
|
||||||
|
if spi_statbuf.st_mtime < lay_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
break
|
||||||
|
return need_capture
|
||||||
|
|
||||||
|
def check_schematic_out_of_date(self, spipath, schempath):
|
||||||
|
# Check if a netlist (spipath) is out-of-date relative to the schematics
|
||||||
|
# (schempath). Need to read the netlist and check all of the subcells.
|
||||||
|
need_capture = False
|
||||||
|
if not os.path.isfile(spipath):
|
||||||
|
return True
|
||||||
|
if os.path.isfile(schempath):
|
||||||
|
spi_statbuf = os.stat(spipath)
|
||||||
|
sch_statbuf = os.stat(schempath)
|
||||||
|
if spi_statbuf.st_mtime < sch_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
else:
|
||||||
|
# only found that the top-level-schematic is older than the
|
||||||
|
# netlist. Now need to read the netlist, find all subcircuits,
|
||||||
|
# and check those dates, too.
|
||||||
|
schemdir = os.path.split(schempath)[0]
|
||||||
|
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
||||||
|
with open(spipath, 'r') as ifile:
|
||||||
|
duttext = ifile.read()
|
||||||
|
|
||||||
|
dutlines = duttext.replace('\n+', ' ').splitlines()
|
||||||
|
for line in dutlines:
|
||||||
|
lmatch = subrex.match(line)
|
||||||
|
if lmatch:
|
||||||
|
subname = lmatch.group(1)
|
||||||
|
# NOTE: Electric uses library:cell internally to track libraries,
|
||||||
|
# and maps the ":" to "__" in the netlist. Not entirely certain that
|
||||||
|
# the double-underscore uniquely identifies the library:cell. . .
|
||||||
|
librex = re.compile('(.*)__(.*)', re.IGNORECASE)
|
||||||
|
lmatch = librex.match(subname)
|
||||||
|
if lmatch:
|
||||||
|
elecpath = os.path.split(os.path.split(schempath)[0])[0]
|
||||||
|
libname = lmatch.group(1)
|
||||||
|
subschem = elecpath + '/' + libname + '.delib/' + lmatch.group(2) + '.sch'
|
||||||
|
else:
|
||||||
|
libname = {}
|
||||||
|
subschem = schemdir + '/' + subname + '.sch'
|
||||||
|
# subcircuits that cannot be found in the current directory are
|
||||||
|
# assumed to be library components and therefore never out-of-date.
|
||||||
|
if os.path.exists(subschem):
|
||||||
|
sub_statbuf = os.stat(subschem)
|
||||||
|
if spi_statbuf.st_mtime < sub_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
break
|
||||||
|
# mapping of characters to what's allowed in SPICE makes finding
|
||||||
|
# the associated schematic file a bit difficult. Requires wild-card
|
||||||
|
# searching.
|
||||||
|
elif libname:
|
||||||
|
restr = lmatch.group(2) + '.sch'
|
||||||
|
restr = restr.replace('.', '\.')
|
||||||
|
restr = restr.replace('_', '.')
|
||||||
|
schrex = re.compile(restr, re.IGNORECASE)
|
||||||
|
libpath = elecpath + '/' + libname + '.delib'
|
||||||
|
if os.path.exists(libpath):
|
||||||
|
liblist = os.listdir(libpath)
|
||||||
|
for file in liblist:
|
||||||
|
lmatch = schrex.match(file)
|
||||||
|
if lmatch:
|
||||||
|
subschem = libpath + '/' + file
|
||||||
|
sub_statbuf = os.stat(subschem)
|
||||||
|
if spi_statbuf.st_mtime < sch_statbuf.st_mtime:
|
||||||
|
# netlist exists but is out-of-date
|
||||||
|
need_capture = True
|
||||||
|
break
|
||||||
|
return need_capture
|
||||||
|
|
||||||
|
def check_lvs(self):
|
||||||
|
# If both netlists exist, and comp.json is more recent than both, then
|
||||||
|
# load LVS results from comp.json
|
||||||
|
project_path = self.rootpath
|
||||||
|
project_name = self.project
|
||||||
|
layout_path = project_path + '/layout/' + project_name + '.spc'
|
||||||
|
net_path = project_path + '/netlist/' + project_name + '.spi'
|
||||||
|
comp_path = project_path + '/layout/comp.json'
|
||||||
|
|
||||||
|
if os.path.exists(layout_path) and os.path.exists(net_path) and os.path.exists(comp_path):
|
||||||
|
magtime = os.stat(layout_path).st_mtime
|
||||||
|
schemtime = os.stat(net_path).st_mtime
|
||||||
|
comptime = os.stat(comp_path).st_mtime
|
||||||
|
if comptime > magtime and comptime > schemtime:
|
||||||
|
print("Loading LVS results from file.")
|
||||||
|
self.generate(comp_path)
|
||||||
|
|
||||||
|
def generate_layout_netlist(self, layout_path, layout_src, project_path):
|
||||||
|
# Does layout netlist exist and is it current?
|
||||||
|
if self.check_layout_out_of_date(layout_path, layout_src):
|
||||||
|
print('Generating layout netlist.')
|
||||||
|
self.update_idletasks()
|
||||||
|
mproc = subprocess.Popen(['magic', '-dnull', '-noconsole',
|
||||||
|
self.layout], stdin = subprocess.PIPE, stdout = subprocess.PIPE,
|
||||||
|
stderr = subprocess.PIPE, cwd = project_path + '/layout',
|
||||||
|
universal_newlines = True)
|
||||||
|
mproc.stdin.write("select top cell\n")
|
||||||
|
mproc.stdin.write("expand\n")
|
||||||
|
mproc.stdin.write("extract all\n")
|
||||||
|
mproc.stdin.write("ext2spice hierarchy on\n")
|
||||||
|
mproc.stdin.write("ext2spice format ngspice\n")
|
||||||
|
mproc.stdin.write("ext2spice scale off\n")
|
||||||
|
mproc.stdin.write("ext2spice renumber off\n")
|
||||||
|
mproc.stdin.write("ext2spice subcircuit top auto\n")
|
||||||
|
mproc.stdin.write("ext2spice cthresh infinite\n")
|
||||||
|
mproc.stdin.write("ext2spice rthresh infinite\n")
|
||||||
|
mproc.stdin.write("ext2spice blackbox on\n")
|
||||||
|
mproc.stdin.write("ext2spice -o " + self.layout + ".spi\n")
|
||||||
|
mproc.stdin.write("quit -noprompt\n")
|
||||||
|
magicout = mproc.communicate()[0]
|
||||||
|
self.printwarn(magicout)
|
||||||
|
if mproc.returncode != 0:
|
||||||
|
print('Failure to generate new layout netlist.')
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Move .spi netlist to project_dir/netlist/lvs/
|
||||||
|
shutil.move(project_path + '/layout/' + self.layout + '.spi', layout_path)
|
||||||
|
# Remove extraction files
|
||||||
|
for file in os.listdir(project_path + '/layout'):
|
||||||
|
if os.path.splitext(file)[1] == '.ext':
|
||||||
|
os.remove(project_path + '/layout/' + file)
|
||||||
|
else:
|
||||||
|
print('Layout netlist is up-to-date, not regenerating.')
|
||||||
|
return True
|
||||||
|
|
||||||
|
def run_lvs(self, value):
|
||||||
|
# "value" is ignored (?)
|
||||||
|
|
||||||
|
# Check if netlists exist and are current; otherwise create them.
|
||||||
|
# Then run LVS.
|
||||||
|
|
||||||
|
project_path = self.rootpath
|
||||||
|
project_name = self.project
|
||||||
|
comp_path = project_path + '/layout/comp.json'
|
||||||
|
has_vlog = False
|
||||||
|
vlog_path = project_path + '/verilog/' + project_name + '.v'
|
||||||
|
|
||||||
|
layout_path = project_path + '/netlist/lvs/' + self.layout + '.spi'
|
||||||
|
net_path = project_path + '/netlist/schem/' + self.schematic + '.spi'
|
||||||
|
layout_src = project_path + '/layout/' + self.layout + '.mag'
|
||||||
|
|
||||||
|
# Does the setup file exist (this is optional)?
|
||||||
|
if self.lvs_setup != '' and not os.path.isfile('setup.tcl'):
|
||||||
|
print('No technology setup file selected.')
|
||||||
|
|
||||||
|
# Does schematic netlist exist?
|
||||||
|
if not os.path.isfile(vlog_path) and not os.path.isfile(net_path):
|
||||||
|
print('Error: No schematic netlist or verilog netlist.')
|
||||||
|
return
|
||||||
|
|
||||||
|
# Does LVS netlist subdirectory exist?
|
||||||
|
if not os.path.exists(project_path + '/netlist/lvs'):
|
||||||
|
os.makedirs(project_path + '/netlist/lvs')
|
||||||
|
|
||||||
|
# Does layout netlist exist and is it current?
|
||||||
|
if not self.generate_layout_netlist(layout_path, layout_src, project_path):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Final check
|
||||||
|
if not os.path.isfile(layout_path):
|
||||||
|
print('Error: No netlist generated from magic.')
|
||||||
|
return
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Read in netlist and convert commas from [X,Y] arrays to vertical bars
|
||||||
|
# as something that can be converted back as necessary. ngspice treats
|
||||||
|
# commas as special characters for some reason.
|
||||||
|
with open(layout_path) as ifile:
|
||||||
|
spitext = ifile.read()
|
||||||
|
|
||||||
|
# spilines = spitext.replace(',', '|')
|
||||||
|
# with open(layout_path, 'w') as ofile:
|
||||||
|
# ofile.write(spilines)
|
||||||
|
|
||||||
|
# Check the netlist to see if the cell to match is a subcircuit. If
|
||||||
|
# not, then assume it is the top level.
|
||||||
|
|
||||||
|
is_subckt = False
|
||||||
|
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
||||||
|
dutlines = spitext.replace('\n+', ' ').splitlines()
|
||||||
|
for line in dutlines:
|
||||||
|
lmatch = subrex.match(line)
|
||||||
|
if lmatch:
|
||||||
|
subname = lmatch.group(1)
|
||||||
|
if subname == self.layout:
|
||||||
|
is_subckt = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if is_subckt:
|
||||||
|
layout_arg = layout_path + ' ' + self.layout
|
||||||
|
layout_text = '"' + layout_arg + '"'
|
||||||
|
else:
|
||||||
|
layout_arg = layout_path
|
||||||
|
layout_text = layout_arg
|
||||||
|
|
||||||
|
if has_vlog:
|
||||||
|
schem_arg = vlog_path + ' ' + self.schematic
|
||||||
|
else:
|
||||||
|
schem_arg = net_path + ' ' + self.schematic
|
||||||
|
schem_text = '"' + schem_arg + '"'
|
||||||
|
|
||||||
|
# Remove any previous comparison output file
|
||||||
|
comp_out_path = os.path.splitext(comp_path)[0] + '.out'
|
||||||
|
if os.path.exists(comp_out_path):
|
||||||
|
os.remove(comp_out_path)
|
||||||
|
|
||||||
|
# Run netgen as subprocess
|
||||||
|
print('Running: netgen -batch lvs ' + layout_text +
|
||||||
|
' ' + schem_text + ' ' + self.lvs_setup + ' ' + comp_out_path +
|
||||||
|
' -json -blackbox')
|
||||||
|
# Note: Because arguments to subprocess are list items, the {filename cell}
|
||||||
|
# pair does *not* have to be quoted or braced. Doing so causes a parse
|
||||||
|
# error.
|
||||||
|
self.lvsproc = subprocess.Popen(['netgen', '-batch', 'lvs',
|
||||||
|
layout_arg, schem_arg,
|
||||||
|
self.lvs_setup, comp_out_path, '-json', '-blackbox'],
|
||||||
|
cwd=project_path + '/layout',
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0)
|
||||||
|
# This is largely unnecessary as netgen usually runs to completion very quickly.
|
||||||
|
self.watchclock(comp_path)
|
||||||
|
|
||||||
|
def watchclock(self, filename):
|
||||||
|
if self.lvsproc == None:
|
||||||
|
return
|
||||||
|
|
||||||
|
lvs_status = self.lvsproc.poll()
|
||||||
|
sresult = select.select([self.lvsproc.stdout, self.lvsproc.stderr], [], [], 0)[0]
|
||||||
|
if self.lvsproc.stdout in sresult:
|
||||||
|
outstring = self.lvsproc.stdout.readline().decode().strip()
|
||||||
|
self.logprint(outstring, doflush=True)
|
||||||
|
print(outstring)
|
||||||
|
elif self.lvsproc.stderr in sresult:
|
||||||
|
errstring = self.lvsproc.stderr.readline().decode().strip()
|
||||||
|
self.logprint(errstring, doflush = True)
|
||||||
|
print(errstring, file=sys.stderr)
|
||||||
|
|
||||||
|
if lvs_status != None:
|
||||||
|
print("netgen LVS exited with status " + str(lvs_status))
|
||||||
|
self.lvsproc = None
|
||||||
|
if lvs_status != 0:
|
||||||
|
print('Errors encountered in LVS.')
|
||||||
|
self.logprint('Errors in LVS, lvs status = ' + str(lvs_status), doflush=True)
|
||||||
|
# Done; now read comp.json and fill the treeview listbox.
|
||||||
|
self.generate(filename)
|
||||||
|
else:
|
||||||
|
self.after(500, lambda: self.watchclock(filename))
|
||||||
|
|
||||||
|
# Generate display from "comp.out" file (json file now preferred)
|
||||||
|
|
||||||
|
def generate_orig(self, lvspath):
|
||||||
|
lefttext = []
|
||||||
|
righttext = []
|
||||||
|
print("Reading LVS output file " + lvspath)
|
||||||
|
if os.path.exists(lvspath):
|
||||||
|
with open(lvspath, 'r') as ifile:
|
||||||
|
lvslines = ifile.read().splitlines()
|
||||||
|
for line in lvslines:
|
||||||
|
if '|' in line:
|
||||||
|
# parts = line.split('|')
|
||||||
|
# lefttext.append(parts[0])
|
||||||
|
# righttext.append(parts[1])
|
||||||
|
lefttext.append(line[0:42].strip())
|
||||||
|
righttext.append(line[44:].strip())
|
||||||
|
else:
|
||||||
|
lefttext.append(line)
|
||||||
|
righttext.append('')
|
||||||
|
# Populate treeview with text
|
||||||
|
self.toppane.lvsreport.repopulate(lefttext, righttext)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Error: No output file generated from LVS.")
|
||||||
|
|
||||||
|
# Generate output from LVS report JSON file comp.json
|
||||||
|
|
||||||
|
def generate(self, lvspath):
|
||||||
|
lefttext = []
|
||||||
|
righttext = []
|
||||||
|
print("Reading LVS output file " + lvspath)
|
||||||
|
if os.path.exists(lvspath):
|
||||||
|
with open(lvspath, 'r') as ifile:
|
||||||
|
self.lvsdata = json.load(ifile)
|
||||||
|
|
||||||
|
# Populate treeview with text
|
||||||
|
self.toppane.lvsreport.json_repopulate(self.lvsdata)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Error: No output file generated from LVS.")
|
||||||
|
|
||||||
|
def findrecord(self, value):
|
||||||
|
print("Unimplemented function")
|
||||||
|
|
||||||
|
def findrecord_test(self, value):
|
||||||
|
# Check if socket is defined; if not, attempt to open one
|
||||||
|
if not self.msock:
|
||||||
|
try:
|
||||||
|
self.msock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
except:
|
||||||
|
print("No response from layout tool.")
|
||||||
|
|
||||||
|
if self.msock:
|
||||||
|
self.msock.connect(("0.0.0.0", 12946))
|
||||||
|
self.msock.setblocking(False)
|
||||||
|
if self.msock:
|
||||||
|
# Pull name of net or device from 'value'
|
||||||
|
# This is a test:
|
||||||
|
self.msock.sendall(b'box 0 0 100 100\r\n')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
options = []
|
||||||
|
arguments = []
|
||||||
|
for item in sys.argv[1:]:
|
||||||
|
if item.find('-', 0) == 0:
|
||||||
|
options.append(item)
|
||||||
|
else:
|
||||||
|
arguments.append(item)
|
||||||
|
|
||||||
|
root = tkinter.Tk()
|
||||||
|
app = LVSManager(root)
|
||||||
|
if arguments:
|
||||||
|
if len(arguments) >= 2:
|
||||||
|
app.set_project(arguments[0], project_name=arguments[1])
|
||||||
|
else:
|
||||||
|
app.set_project(arguments[0])
|
||||||
|
|
||||||
|
root.mainloop()
|
||||||
|
|
@ -343,7 +343,7 @@ class LVSManager(ttk.Frame):
|
||||||
techbase = os.path.split(techname)[1]
|
techbase = os.path.split(techname)[1]
|
||||||
self.tech = os.path.splitext(techbase)[0]
|
self.tech = os.path.splitext(techbase)[0]
|
||||||
self.lvs_setup = techname
|
self.lvs_setup = techname
|
||||||
self.toppane.title2_frame.tech_select.config(text = self.tech)
|
self.toppane.title2_frame.layout_select.config(text = self.tech)
|
||||||
|
|
||||||
def choose_layout(self):
|
def choose_layout(self):
|
||||||
try:
|
try:
|
||||||
|
|
@ -358,37 +358,30 @@ class LVSManager(ttk.Frame):
|
||||||
title = "Choose a layout cell to compare.")
|
title = "Choose a layout cell to compare.")
|
||||||
if cellname != '':
|
if cellname != '':
|
||||||
print("Selected compare cell " + cellname)
|
print("Selected compare cell " + cellname)
|
||||||
self.layout = cellname
|
|
||||||
cellbase = os.path.split(cellname)[1]
|
cellbase = os.path.split(cellname)[1]
|
||||||
layoutname = os.path.splitext(cellbase)[0]
|
self.layout = os.path.splitext(cellbase)[0]
|
||||||
self.toppane.title2_frame.layout_select.config(text = layoutname)
|
self.toppane.title2_frame.layout_select.config(text = self.layout)
|
||||||
fileext = os.path.splitext(cellbase)[1]
|
|
||||||
if fileext == '.mag':
|
|
||||||
self.toppane.title2_frame.layout_label.config(text = 'Layout:')
|
|
||||||
else:
|
|
||||||
self.toppane.title2_frame.layout_label.config(text = 'Layout netlist:')
|
|
||||||
|
|
||||||
def choose_netlist(self):
|
def choose_netlist(self):
|
||||||
try:
|
try:
|
||||||
project_path = self.rootpath
|
project_path = self.rootpath
|
||||||
initdirname = self.rootpath + '/netlist/' + self.project + '.spice'
|
initdirname = self.rootpath + '/netlist/' + self.project + '.spi'
|
||||||
except:
|
except:
|
||||||
print('Must choose a project first.')
|
print('Must choose a project first.')
|
||||||
return
|
return
|
||||||
cellname = filedialog.askopenfilename(multiple=False,
|
cellname = filedialog.askopenfilename(multiple=False,
|
||||||
initialdir = initdirname,
|
initialdir = initdirname,
|
||||||
filetypes = (("Spice netlist", "*.spice"),("Verilog netlist", "*.v"),("All Files","*.*")),
|
filetypes = (("Spice netlist", "*.spi"),("Verilog netlist", "*.v")),
|
||||||
title = "Choose a netlist to compare.")
|
title = "Choose a netlist to compare.")
|
||||||
if cellname != '':
|
if cellname != '':
|
||||||
print("Selected compare cell " + cellname)
|
print("Selected compare cell " + cellname)
|
||||||
self.schematic = cellname
|
|
||||||
cellbase = os.path.split(cellname)[1]
|
cellbase = os.path.split(cellname)[1]
|
||||||
schematic_name = os.path.splitext(cellbase)[0]
|
self.schematic = os.path.splitext(cellbase)[0]
|
||||||
self.toppane.title2_frame.schem_select.config(text = schematic_name)
|
self.toppane.title2_frame.schem_select.config(text = self.schematic)
|
||||||
fileext = os.path.splitext(cellbase)[1]
|
fileext = os.path.splitext(cellbase)[1]
|
||||||
if fileext == '.v':
|
if fileext == '.v':
|
||||||
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
|
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
|
||||||
elif fileext == '.sp' or fileext == '.spice' or fileext == '.spi' or fileext == '.spc' or fileext == '.ckt':
|
elif fileext == '.sp' or fileext == '.spi' or fileext == '.spice' or fileext == '.spc' or fileext == '.ckt':
|
||||||
self.toppane.title2_frame.schem_label.config(text = 'SPICE netlist:')
|
self.toppane.title2_frame.schem_label.config(text = 'SPICE netlist:')
|
||||||
elif fileext == '.cdl':
|
elif fileext == '.cdl':
|
||||||
self.toppane.title2_frame.schem_label.config(text = 'CDL netlist:')
|
self.toppane.title2_frame.schem_label.config(text = 'CDL netlist:')
|
||||||
|
|
@ -440,10 +433,7 @@ class LVSManager(ttk.Frame):
|
||||||
self.logfile = None
|
self.logfile = None
|
||||||
|
|
||||||
# Put new log file called 'lvs.log' in the mag/ subdirectory
|
# Put new log file called 'lvs.log' in the mag/ subdirectory
|
||||||
if os.path.exists(rootpath + '/layout'):
|
self.logfile = open(rootpath + '/layout/lvs.log', 'w')
|
||||||
self.logfile = open(rootpath + '/layout/lvs.log', 'w')
|
|
||||||
else:
|
|
||||||
self.logfile = open(rootpath + '/lvs.log', 'w')
|
|
||||||
# Print some initial information to the logfile.
|
# Print some initial information to the logfile.
|
||||||
self.logprint('Starting new log file ' + datetime.datetime.now().strftime('%c'),
|
self.logprint('Starting new log file ' + datetime.datetime.now().strftime('%c'),
|
||||||
doflush=True)
|
doflush=True)
|
||||||
|
|
@ -454,23 +444,15 @@ class LVSManager(ttk.Frame):
|
||||||
# Cell name is the same as project name initially
|
# Cell name is the same as project name initially
|
||||||
self.layout = self.project
|
self.layout = self.project
|
||||||
self.schematic = self.project
|
self.schematic = self.project
|
||||||
layname = os.path.splitext(os.path.split(self.layout)[1])[0]
|
self.toppane.title2_frame.layout_select.config(text = self.layout)
|
||||||
self.toppane.title2_frame.layout_select.config(text = layname)
|
self.toppane.title2_frame.schem_select.config(text = self.schematic)
|
||||||
schemname = os.path.splitext(os.path.split(self.schematic)[1])[0]
|
|
||||||
self.toppane.title2_frame.schem_select.config(text = schemname)
|
|
||||||
|
|
||||||
# Update schematic button
|
# Update schematic button
|
||||||
if os.path.splitext(self.schematic)[1] == '.v':
|
if os.path.isfile(rootpath + '/verilog/' + self.schematic + '.v'):
|
||||||
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
|
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
|
||||||
else:
|
else:
|
||||||
self.toppane.title2_frame.schem_label.config(text = 'Schematic netlist:')
|
self.toppane.title2_frame.schem_label.config(text = 'Schematic netlist:')
|
||||||
|
|
||||||
# Update layout button
|
|
||||||
if os.path.splitext(self.layout)[1] == '.mag':
|
|
||||||
self.toppane.title2_frame.schem_label.config(text = 'Layout:')
|
|
||||||
else:
|
|
||||||
self.toppane.title2_frame.schem_label.config(text = 'Layout netlist:')
|
|
||||||
|
|
||||||
# If there is a comparison file that post-dates both netlists, load it.
|
# If there is a comparison file that post-dates both netlists, load it.
|
||||||
self.check_lvs()
|
self.check_lvs()
|
||||||
return True
|
return True
|
||||||
|
|
@ -585,8 +567,8 @@ class LVSManager(ttk.Frame):
|
||||||
# load LVS results from comp.json
|
# load LVS results from comp.json
|
||||||
project_path = self.rootpath
|
project_path = self.rootpath
|
||||||
project_name = self.project
|
project_name = self.project
|
||||||
layout_path = project_path + '/layout/' + project_name + '.spice'
|
layout_path = project_path + '/layout/' + project_name + '.spc'
|
||||||
net_path = project_path + '/netlist/' + project_name + '.spice'
|
net_path = project_path + '/netlist/' + project_name + '.spi'
|
||||||
comp_path = project_path + '/layout/comp.json'
|
comp_path = project_path + '/layout/comp.json'
|
||||||
|
|
||||||
if os.path.exists(layout_path) and os.path.exists(net_path) and os.path.exists(comp_path):
|
if os.path.exists(layout_path) and os.path.exists(net_path) and os.path.exists(comp_path):
|
||||||
|
|
@ -617,7 +599,7 @@ class LVSManager(ttk.Frame):
|
||||||
mproc.stdin.write("ext2spice cthresh infinite\n")
|
mproc.stdin.write("ext2spice cthresh infinite\n")
|
||||||
mproc.stdin.write("ext2spice rthresh infinite\n")
|
mproc.stdin.write("ext2spice rthresh infinite\n")
|
||||||
mproc.stdin.write("ext2spice blackbox on\n")
|
mproc.stdin.write("ext2spice blackbox on\n")
|
||||||
mproc.stdin.write("ext2spice -o " + self.layout + ".spice\n")
|
mproc.stdin.write("ext2spice -o " + self.layout + ".spi\n")
|
||||||
mproc.stdin.write("quit -noprompt\n")
|
mproc.stdin.write("quit -noprompt\n")
|
||||||
magicout = mproc.communicate()[0]
|
magicout = mproc.communicate()[0]
|
||||||
self.printwarn(magicout)
|
self.printwarn(magicout)
|
||||||
|
|
@ -625,8 +607,8 @@ class LVSManager(ttk.Frame):
|
||||||
print('Failure to generate new layout netlist.')
|
print('Failure to generate new layout netlist.')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Move .spice netlist to project_dir/netlist/lvs/
|
# Move .spi netlist to project_dir/netlist/lvs/
|
||||||
shutil.move(project_path + '/layout/' + self.layout + '.spice', layout_path)
|
shutil.move(project_path + '/layout/' + self.layout + '.spi', layout_path)
|
||||||
# Remove extraction files
|
# Remove extraction files
|
||||||
for file in os.listdir(project_path + '/layout'):
|
for file in os.listdir(project_path + '/layout'):
|
||||||
if os.path.splitext(file)[1] == '.ext':
|
if os.path.splitext(file)[1] == '.ext':
|
||||||
|
|
@ -643,37 +625,17 @@ class LVSManager(ttk.Frame):
|
||||||
|
|
||||||
project_path = self.rootpath
|
project_path = self.rootpath
|
||||||
project_name = self.project
|
project_name = self.project
|
||||||
|
comp_path = project_path + '/layout/comp.json'
|
||||||
# Diagnostic:
|
|
||||||
print('project_name is ' + project_name)
|
|
||||||
print('project_path is ' + project_path)
|
|
||||||
print('self.layout is ' + self.layout)
|
|
||||||
print('self.schematic is ' + self.schematic)
|
|
||||||
print('self.lvs_setup is ' + self.lvs_setup)
|
|
||||||
|
|
||||||
has_vlog = False
|
has_vlog = False
|
||||||
vlog_path = project_path + '/verilog/' + project_name + '.v'
|
vlog_path = project_path + '/verilog/' + project_name + '.v'
|
||||||
|
|
||||||
if os.path.isfile(self.layout):
|
layout_path = project_path + '/netlist/lvs/' + self.layout + '.spi'
|
||||||
layout_path = self.layout
|
net_path = project_path + '/netlist/schem/' + self.schematic + '.spi'
|
||||||
layout_src = None
|
layout_src = project_path + '/layout/' + self.layout + '.mag'
|
||||||
else:
|
|
||||||
layout_path = project_path + '/netlist/lvs/' + self.layout + '.spice'
|
|
||||||
layout_src = project_path + '/layout/' + self.layout + '.mag'
|
|
||||||
|
|
||||||
comp_dir = os.path.split(layout_path)[0]
|
|
||||||
comp_path = comp_dir + '/comp.json'
|
|
||||||
|
|
||||||
if os.path.isfile(self.schematic):
|
|
||||||
net_path = self.schematic
|
|
||||||
else:
|
|
||||||
net_path = project_path + '/netlist/schem/' + self.schematic + '.spice'
|
|
||||||
|
|
||||||
# Does the setup file exist (this is optional)?
|
# Does the setup file exist (this is optional)?
|
||||||
if self.lvs_setup == '' and not os.path.isfile('setup.tcl'):
|
if self.lvs_setup != '' and not os.path.isfile('setup.tcl'):
|
||||||
print('No technology setup file selected.')
|
print('No technology setup file selected.')
|
||||||
elif not os.path.isfile(self.lvs_setup):
|
|
||||||
print("Can't find technology setup file " + self.lvs_setup)
|
|
||||||
|
|
||||||
# Does schematic netlist exist?
|
# Does schematic netlist exist?
|
||||||
if not os.path.isfile(vlog_path) and not os.path.isfile(net_path):
|
if not os.path.isfile(vlog_path) and not os.path.isfile(net_path):
|
||||||
|
|
@ -681,16 +643,14 @@ class LVSManager(ttk.Frame):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Does LVS netlist subdirectory exist?
|
# Does LVS netlist subdirectory exist?
|
||||||
if os.path.exists(project_path + '/netlist'):
|
if not os.path.exists(project_path + '/netlist/lvs'):
|
||||||
if not os.path.exists(project_path + '/netlist/lvs'):
|
os.makedirs(project_path + '/netlist/lvs')
|
||||||
os.makedirs(project_path + '/netlist/lvs')
|
|
||||||
|
|
||||||
# Does layout netlist exist and is it current?
|
# Does layout netlist exist and is it current?
|
||||||
if layout_src:
|
if not self.generate_layout_netlist(layout_path, layout_src, project_path):
|
||||||
if not self.generate_layout_netlist(layout_path, layout_src, project_path):
|
return False
|
||||||
return False
|
|
||||||
|
|
||||||
# Final checks
|
# Final check
|
||||||
if not os.path.isfile(layout_path):
|
if not os.path.isfile(layout_path):
|
||||||
print('Error: No netlist generated from magic.')
|
print('Error: No netlist generated from magic.')
|
||||||
return
|
return
|
||||||
|
|
@ -702,27 +662,26 @@ class LVSManager(ttk.Frame):
|
||||||
with open(layout_path) as ifile:
|
with open(layout_path) as ifile:
|
||||||
spitext = ifile.read()
|
spitext = ifile.read()
|
||||||
|
|
||||||
|
# spilines = spitext.replace(',', '|')
|
||||||
|
# with open(layout_path, 'w') as ofile:
|
||||||
|
# ofile.write(spilines)
|
||||||
|
|
||||||
# Check the netlist to see if the cell to match is a subcircuit. If
|
# Check the netlist to see if the cell to match is a subcircuit. If
|
||||||
# not, then assume it is the top level.
|
# not, then assume it is the top level.
|
||||||
|
|
||||||
layoutcell = os.path.splitext(os.path.split(self.layout)[1])[0]
|
|
||||||
is_subckt = False
|
is_subckt = False
|
||||||
subname = None
|
|
||||||
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
||||||
dutlines = spitext.replace('\n+', ' ').splitlines()
|
dutlines = spitext.replace('\n+', ' ').splitlines()
|
||||||
for line in dutlines:
|
for line in dutlines:
|
||||||
lmatch = subrex.match(line)
|
lmatch = subrex.match(line)
|
||||||
if lmatch:
|
if lmatch:
|
||||||
subname = lmatch.group(1)
|
subname = lmatch.group(1)
|
||||||
if subname == layoutcell:
|
if subname == self.layout:
|
||||||
is_subckt = True
|
is_subckt = True
|
||||||
break
|
break
|
||||||
|
|
||||||
if is_subckt:
|
if is_subckt:
|
||||||
layout_arg = self.layout + ' ' + layoutcell
|
layout_arg = layout_path + ' ' + self.layout
|
||||||
layout_text = '"' + layout_arg + '"'
|
|
||||||
elif subname:
|
|
||||||
layout_arg = self.layout + ' ' + subname
|
|
||||||
layout_text = '"' + layout_arg + '"'
|
layout_text = '"' + layout_arg + '"'
|
||||||
else:
|
else:
|
||||||
layout_arg = layout_path
|
layout_arg = layout_path
|
||||||
|
|
@ -731,39 +690,8 @@ class LVSManager(ttk.Frame):
|
||||||
if has_vlog:
|
if has_vlog:
|
||||||
schem_arg = vlog_path + ' ' + self.schematic
|
schem_arg = vlog_path + ' ' + self.schematic
|
||||||
else:
|
else:
|
||||||
# Final checks
|
schem_arg = net_path + ' ' + self.schematic
|
||||||
if not os.path.isfile(net_path):
|
schem_text = '"' + schem_arg + '"'
|
||||||
print('Error: No netlist from schematic.')
|
|
||||||
return
|
|
||||||
|
|
||||||
with open(net_path) as ifile:
|
|
||||||
spitext = ifile.read()
|
|
||||||
|
|
||||||
# Check the netlist to see if the cell to match is a subcircuit. If
|
|
||||||
# not, then assume it is the top level.
|
|
||||||
|
|
||||||
schemcell = os.path.splitext(os.path.split(self.schematic)[1])[0]
|
|
||||||
subname = None
|
|
||||||
is_subckt = False
|
|
||||||
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
|
|
||||||
dutlines = spitext.replace('\n+', ' ').splitlines()
|
|
||||||
for line in dutlines:
|
|
||||||
lmatch = subrex.match(line)
|
|
||||||
if lmatch:
|
|
||||||
subname = lmatch.group(1)
|
|
||||||
if subname == schemcell:
|
|
||||||
is_subckt = True
|
|
||||||
break
|
|
||||||
|
|
||||||
if is_subckt:
|
|
||||||
schem_arg = self.schematic + ' ' + schemcell
|
|
||||||
schem_text = '"' + schem_arg + '"'
|
|
||||||
elif subname:
|
|
||||||
schem_arg = self.schematic + ' ' + subname
|
|
||||||
schem_text = '"' + schem_arg + '"'
|
|
||||||
else:
|
|
||||||
schem_arg = net_path
|
|
||||||
schem_text = schem_arg
|
|
||||||
|
|
||||||
# Remove any previous comparison output file
|
# Remove any previous comparison output file
|
||||||
comp_out_path = os.path.splitext(comp_path)[0] + '.out'
|
comp_out_path = os.path.splitext(comp_path)[0] + '.out'
|
||||||
|
|
@ -780,7 +708,7 @@ class LVSManager(ttk.Frame):
|
||||||
self.lvsproc = subprocess.Popen(['netgen', '-batch', 'lvs',
|
self.lvsproc = subprocess.Popen(['netgen', '-batch', 'lvs',
|
||||||
layout_arg, schem_arg,
|
layout_arg, schem_arg,
|
||||||
self.lvs_setup, comp_out_path, '-json', '-blackbox'],
|
self.lvs_setup, comp_out_path, '-json', '-blackbox'],
|
||||||
cwd=comp_dir,
|
cwd=project_path + '/layout',
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0)
|
||||||
# This is largely unnecessary as netgen usually runs to completion very quickly.
|
# This is largely unnecessary as netgen usually runs to completion very quickly.
|
||||||
self.watchclock(comp_path)
|
self.watchclock(comp_path)
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -668,6 +668,7 @@ XMKMF
|
||||||
HAVE_PYTHON3
|
HAVE_PYTHON3
|
||||||
EGREP
|
EGREP
|
||||||
GREP
|
GREP
|
||||||
|
M4
|
||||||
RANLIB
|
RANLIB
|
||||||
INSTALL_DATA
|
INSTALL_DATA
|
||||||
INSTALL_SCRIPT
|
INSTALL_SCRIPT
|
||||||
|
|
@ -711,7 +712,6 @@ infodir
|
||||||
docdir
|
docdir
|
||||||
oldincludedir
|
oldincludedir
|
||||||
includedir
|
includedir
|
||||||
runstatedir
|
|
||||||
localstatedir
|
localstatedir
|
||||||
sharedstatedir
|
sharedstatedir
|
||||||
sysconfdir
|
sysconfdir
|
||||||
|
|
@ -794,7 +794,6 @@ datadir='${datarootdir}'
|
||||||
sysconfdir='${prefix}/etc'
|
sysconfdir='${prefix}/etc'
|
||||||
sharedstatedir='${prefix}/com'
|
sharedstatedir='${prefix}/com'
|
||||||
localstatedir='${prefix}/var'
|
localstatedir='${prefix}/var'
|
||||||
runstatedir='${localstatedir}/run'
|
|
||||||
includedir='${prefix}/include'
|
includedir='${prefix}/include'
|
||||||
oldincludedir='/usr/include'
|
oldincludedir='/usr/include'
|
||||||
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
|
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
|
||||||
|
|
@ -1047,15 +1046,6 @@ do
|
||||||
| -silent | --silent | --silen | --sile | --sil)
|
| -silent | --silent | --silen | --sile | --sil)
|
||||||
silent=yes ;;
|
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)
|
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
|
||||||
ac_prev=sbindir ;;
|
ac_prev=sbindir ;;
|
||||||
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
|
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
|
||||||
|
|
@ -1193,7 +1183,7 @@ fi
|
||||||
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
|
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
|
||||||
datadir sysconfdir sharedstatedir localstatedir includedir \
|
datadir sysconfdir sharedstatedir localstatedir includedir \
|
||||||
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
|
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
|
||||||
libdir localedir mandir runstatedir
|
libdir localedir mandir
|
||||||
do
|
do
|
||||||
eval ac_val=\$$ac_var
|
eval ac_val=\$$ac_var
|
||||||
# Remove trailing slashes.
|
# Remove trailing slashes.
|
||||||
|
|
@ -1346,7 +1336,6 @@ Fine tuning of the installation directories:
|
||||||
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
|
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
|
||||||
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
|
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
|
||||||
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
|
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
|
||||||
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
|
|
||||||
--libdir=DIR object code libraries [EPREFIX/lib]
|
--libdir=DIR object code libraries [EPREFIX/lib]
|
||||||
--includedir=DIR C header files [PREFIX/include]
|
--includedir=DIR C header files [PREFIX/include]
|
||||||
--oldincludedir=DIR C header files for non-gcc [/usr/include]
|
--oldincludedir=DIR C header files for non-gcc [/usr/include]
|
||||||
|
|
@ -3701,6 +3690,56 @@ else
|
||||||
fi
|
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
|
if test "$CPP" = "$CC -E" ; then
|
||||||
CPP="$CPP -x c"
|
CPP="$CPP -x c"
|
||||||
|
|
@ -6026,6 +6065,7 @@ fi
|
||||||
|
|
||||||
|
|
||||||
if test $usingTcl ; then
|
if test $usingTcl ; then
|
||||||
|
usingX11=1
|
||||||
cadinstall="$cadinstall tcltk"
|
cadinstall="$cadinstall tcltk"
|
||||||
modules="$modules tcltk"
|
modules="$modules tcltk"
|
||||||
programs="$programs tcltk"
|
programs="$programs tcltk"
|
||||||
|
|
@ -6035,11 +6075,7 @@ if test $usingTcl ; then
|
||||||
|
|
||||||
extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o"
|
extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o"
|
||||||
extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\""
|
extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\""
|
||||||
if test $usingX11 ; then
|
stub_defs="$stub_defs -DUSE_TCL_STUBS -DUSE_TK_STUBS"
|
||||||
stub_defs="$stub_defs -DUSE_TCL_STUBS"
|
|
||||||
else
|
|
||||||
stub_defs="$stub_defs -DUSE_TCL_STUBS -DUSE_TK_STUBS"
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
programs="$programs netgen"
|
programs="$programs netgen"
|
||||||
unused="$unused tcltk"
|
unused="$unused tcltk"
|
||||||
|
|
@ -6124,7 +6160,6 @@ if test $usingTcl ; then
|
||||||
# Tk libraries and header files
|
# Tk libraries and header files
|
||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
if test $usingX11 ; then
|
|
||||||
if test "${TK_INC_DIR}" != "/usr/include" ; then
|
if test "${TK_INC_DIR}" != "/usr/include" ; then
|
||||||
INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}"
|
INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}"
|
||||||
fi
|
fi
|
||||||
|
|
@ -6141,7 +6176,6 @@ if test $usingX11 ; then
|
||||||
loader_run_path="${TK_LIB_DIR}:${loader_run_path}"
|
loader_run_path="${TK_LIB_DIR}:${loader_run_path}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
|
|
@ -6251,7 +6285,7 @@ fi
|
||||||
|
|
||||||
*darwin*)
|
*darwin*)
|
||||||
SHDLIB_EXT=".dylib"
|
SHDLIB_EXT=".dylib"
|
||||||
LDDL_FLAGS="-dynamiclib -undefined dynamic_lookup"
|
LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind"
|
||||||
LDFLAGS="${LDFLAGS} ${LIB_SPECS}"
|
LDFLAGS="${LDFLAGS} ${LIB_SPECS}"
|
||||||
CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common"
|
CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common"
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,12 @@ AC_ISC_POSIX
|
||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
AC_PROG_RANLIB
|
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 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 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
|
dnl assert that input files are of type C, or else the preprocessing
|
||||||
|
|
@ -801,6 +807,7 @@ dnl "make" instead of requiring "make tcl"
|
||||||
dnl ----------------------------------------------------------------
|
dnl ----------------------------------------------------------------
|
||||||
|
|
||||||
if test $usingTcl ; then
|
if test $usingTcl ; then
|
||||||
|
usingX11=1
|
||||||
cadinstall="$cadinstall tcltk"
|
cadinstall="$cadinstall tcltk"
|
||||||
modules="$modules tcltk"
|
modules="$modules tcltk"
|
||||||
programs="$programs tcltk"
|
programs="$programs tcltk"
|
||||||
|
|
@ -809,11 +816,7 @@ if test $usingTcl ; then
|
||||||
AC_DEFINE(TCL_NETGEN)
|
AC_DEFINE(TCL_NETGEN)
|
||||||
extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o"
|
extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o"
|
||||||
extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\""
|
extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\""
|
||||||
if test $usingX11 ; then
|
stub_defs="$stub_defs -DUSE_TCL_STUBS -DUSE_TK_STUBS"
|
||||||
stub_defs="$stub_defs -DUSE_TCL_STUBS"
|
|
||||||
else
|
|
||||||
stub_defs="$stub_defs -DUSE_TCL_STUBS -DUSE_TK_STUBS"
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
programs="$programs netgen"
|
programs="$programs netgen"
|
||||||
unused="$unused tcltk"
|
unused="$unused tcltk"
|
||||||
|
|
@ -900,7 +903,6 @@ if test $usingTcl ; then
|
||||||
# Tk libraries and header files
|
# Tk libraries and header files
|
||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
if test $usingX11 ; then
|
|
||||||
if test "${TK_INC_DIR}" != "/usr/include" ; then
|
if test "${TK_INC_DIR}" != "/usr/include" ; then
|
||||||
INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}"
|
INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}"
|
||||||
fi
|
fi
|
||||||
|
|
@ -917,7 +919,6 @@ if test $usingX11 ; then
|
||||||
loader_run_path="${TK_LIB_DIR}:${loader_run_path}"
|
loader_run_path="${TK_LIB_DIR}:${loader_run_path}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
|
|
@ -1027,7 +1028,7 @@ fi
|
||||||
|
|
||||||
*darwin*)
|
*darwin*)
|
||||||
SHDLIB_EXT=".dylib"
|
SHDLIB_EXT=".dylib"
|
||||||
LDDL_FLAGS="-dynamiclib -undefined dynamic_lookup"
|
LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind"
|
||||||
LDFLAGS="${LDFLAGS} ${LIB_SPECS}"
|
LDFLAGS="${LDFLAGS} ${LIB_SPECS}"
|
||||||
CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common"
|
CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common"
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -68,7 +68,6 @@ LIB_SPECS = @LIB_SPECS@
|
||||||
LIB_SPECS_NOSTUB = @LIB_SPECS_NOSTUB@
|
LIB_SPECS_NOSTUB = @LIB_SPECS_NOSTUB@
|
||||||
WISH_EXE = @WISH_EXE@
|
WISH_EXE = @WISH_EXE@
|
||||||
TCL_LIB_DIR = @TCL_LIB_DIR@
|
TCL_LIB_DIR = @TCL_LIB_DIR@
|
||||||
EXTRA_CFLAGS =
|
|
||||||
|
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
CPP = @CPP@
|
CPP = @CPP@
|
||||||
|
|
@ -77,7 +76,7 @@ CXX = @CXX@
|
||||||
CPPFLAGS = -I. -I${NETGENDIR} @CPPFLAGS@
|
CPPFLAGS = -I. -I${NETGENDIR} @CPPFLAGS@
|
||||||
DFLAGS = @extra_defs@ @stub_defs@ @DEFS@ -DSHDLIB_EXT=\"@SHDLIB_EXT@\" -DNDEBUG
|
DFLAGS = @extra_defs@ @stub_defs@ @DEFS@ -DSHDLIB_EXT=\"@SHDLIB_EXT@\" -DNDEBUG
|
||||||
DFLAGS_NOSTUB = @extra_defs@ @DEFS@ -DSHDLIB_EXT=\"@SHDLIB_EXT@\" -DNDEBUG
|
DFLAGS_NOSTUB = @extra_defs@ @DEFS@ -DSHDLIB_EXT=\"@SHDLIB_EXT@\" -DNDEBUG
|
||||||
CFLAGS = @CFLAGS@ @SHLIB_CFLAGS@ @INC_SPECS@ ${EXTRA_CFLAGS}
|
CFLAGS = @CFLAGS@ @SHLIB_CFLAGS@ @INC_SPECS@
|
||||||
|
|
||||||
DEPEND_FILE = Depend
|
DEPEND_FILE = Depend
|
||||||
DEPEND_FLAG = @DEPEND_FLAG@
|
DEPEND_FLAG = @DEPEND_FLAG@
|
||||||
|
|
|
||||||
|
|
@ -62,18 +62,16 @@ proc netgen::convert_to_json {filename lvs_final} {
|
||||||
puts $fjson " \["
|
puts $fjson " \["
|
||||||
set cktval [lindex $value 0]
|
set cktval [lindex $value 0]
|
||||||
foreach pin [lrange $cktval 0 end-1] {
|
foreach pin [lrange $cktval 0 end-1] {
|
||||||
set pinstr [string map {"\\" "\\\\"} $pin]
|
puts $fjson " \"$pin\","
|
||||||
puts $fjson " \"$pinstr\","
|
|
||||||
}
|
}
|
||||||
set pin [string map {"\\" "\\\\"} [lindex $cktval end]]
|
set pin [lindex $cktval end]
|
||||||
puts $fjson " \"$pin\""
|
puts $fjson " \"$pin\""
|
||||||
puts $fjson " \], \["
|
puts $fjson " \], \["
|
||||||
set cktval [lindex $value 1]
|
set cktval [lindex $value 1]
|
||||||
foreach pin [lrange $cktval 0 end-1] {
|
foreach pin [lrange $cktval 0 end-1] {
|
||||||
set pinstr [string map {"\\" "\\\\"} $pin]
|
puts $fjson " \"$pin\","
|
||||||
puts $fjson " \"$pinstr\","
|
|
||||||
}
|
}
|
||||||
set pin [string map {"\\" "\\\\"} [lindex $cktval end]]
|
set pin [lindex $cktval end]
|
||||||
puts $fjson " \"$pin\""
|
puts $fjson " \"$pin\""
|
||||||
puts $fjson " \]"
|
puts $fjson " \]"
|
||||||
if {$kidx == $nkeys} {
|
if {$kidx == $nkeys} {
|
||||||
|
|
@ -354,7 +352,7 @@ proc netgen::convert_to_json {filename lvs_final} {
|
||||||
close $fjson
|
close $fjson
|
||||||
}
|
}
|
||||||
|
|
||||||
#-----------------------------------------------------------------------
|
#----------------------------------------------------------------
|
||||||
# Define the "lvs" command as a way of calling the netgen options
|
# Define the "lvs" command as a way of calling the netgen options
|
||||||
# for standard compare, essentially the same as the old "netcomp"
|
# for standard compare, essentially the same as the old "netcomp"
|
||||||
# standalone program.
|
# standalone program.
|
||||||
|
|
@ -363,20 +361,14 @@ proc netgen::convert_to_json {filename lvs_final} {
|
||||||
# although if the cells have not been read in yet, then the
|
# although if the cells have not been read in yet, then the
|
||||||
# original syntax of filename or {filename cellname} is required.
|
# original syntax of filename or {filename cellname} is required.
|
||||||
#
|
#
|
||||||
# "args" may be "-list", "-json", or "-blackbox".
|
# "args" is passed to verify and may therefore contain only the
|
||||||
# "-list" returns output as a nested list.
|
# value "-list" or nothing. If "-list", then output is returned
|
||||||
# "-json" creates a .json-format output file in addition to stdout.
|
# as a nested list.
|
||||||
# "-blackbox" treats empty cells as black-box entries.
|
#----------------------------------------------------------------
|
||||||
# "-noflatten={list}" is a list of cells not to flatten if mismatched.
|
|
||||||
# i.e., the cells are expected to match and any mismatch cannot be
|
|
||||||
# expected to be resolved by flattening the contents of the mismatched
|
|
||||||
# cells.
|
|
||||||
#-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
set dolist 0
|
set dolist 0
|
||||||
set dojson 0
|
set dojson 0
|
||||||
set noflat {}
|
|
||||||
foreach arg $args {
|
foreach arg $args {
|
||||||
if {$arg == "-list"} {
|
if {$arg == "-list"} {
|
||||||
puts stdout "Generating list result"
|
puts stdout "Generating list result"
|
||||||
|
|
@ -390,30 +382,6 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
} elseif {$arg == "-blackbox"} {
|
} elseif {$arg == "-blackbox"} {
|
||||||
puts stdout "Treating empty subcircuits as black-box cells"
|
puts stdout "Treating empty subcircuits as black-box cells"
|
||||||
netgen::model blackbox on
|
netgen::model blackbox on
|
||||||
} elseif {[string first "-noflatten=" $arg] == 0} {
|
|
||||||
set value [string range $arg 11 end]
|
|
||||||
# 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 {[file exists $value]} {
|
|
||||||
if {![catch {open $value r} fnf]} {
|
|
||||||
while {[gets $fnf line] >= 0} {
|
|
||||||
if {[lindex $line 0] != "#"} {
|
|
||||||
foreach cell $line {
|
|
||||||
lappend noflat $cell
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close $fnf
|
|
||||||
} else {
|
|
||||||
puts stderr "Cannot open file $value for reading cell list."
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
set noflat [string trim $value \"\{\}]
|
|
||||||
}
|
|
||||||
if {[llength $noflat] > 0} {
|
|
||||||
puts stdout "Will not flatten these subcells: $noflat"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -429,7 +397,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
set file1 $name1
|
set file1 $name1
|
||||||
set cell1 $name1
|
set cell1 $name1
|
||||||
}
|
}
|
||||||
puts stdout "Reading netlist file $file1 for $name1"
|
puts stdout "Reading netlist file $file1"
|
||||||
set fnum1 [netgen::readnet $file1]
|
set fnum1 [netgen::readnet $file1]
|
||||||
} else {
|
} else {
|
||||||
set cell1 [lindex $flist1 0]
|
set cell1 [lindex $flist1 0]
|
||||||
|
|
@ -446,7 +414,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
set file2 $name2
|
set file2 $name2
|
||||||
set cell2 $name2
|
set cell2 $name2
|
||||||
}
|
}
|
||||||
puts stdout "Reading netlist file $file2 for $name2"
|
puts stdout "Reading netlist file $file2"
|
||||||
set fnum2 [netgen::readnet $file2]
|
set fnum2 [netgen::readnet $file2]
|
||||||
} else {
|
} else {
|
||||||
set cell2 [lindex $flist2 0]
|
set cell2 [lindex $flist2 0]
|
||||||
|
|
@ -461,7 +429,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
}
|
}
|
||||||
|
|
||||||
set clist1 [cells list $fnum1]
|
set clist1 [cells list $fnum1]
|
||||||
set cidx [lsearch -exact $clist1 $cell1]
|
set cidx [lsearch -regexp $clist1 ^$cell1$]
|
||||||
if {$cidx < 0} {
|
if {$cidx < 0} {
|
||||||
puts stderr "Cannot find cell $cell1 in file $file1"
|
puts stderr "Cannot find cell $cell1 in file $file1"
|
||||||
return
|
return
|
||||||
|
|
@ -469,7 +437,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
set cell1 [lindex $clist1 $cidx]
|
set cell1 [lindex $clist1 $cidx]
|
||||||
}
|
}
|
||||||
set clist2 [cells list $fnum2]
|
set clist2 [cells list $fnum2]
|
||||||
set cidx [lsearch -exact $clist2 $cell2]
|
set cidx [lsearch -regexp $clist2 ^$cell2$]
|
||||||
if {$cidx < 0} {
|
if {$cidx < 0} {
|
||||||
puts stderr "Cannot find cell $cell2 in file $file2"
|
puts stderr "Cannot find cell $cell2 in file $file2"
|
||||||
return
|
return
|
||||||
|
|
@ -477,26 +445,10 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
set cell2 [lindex $clist2 $cidx]
|
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"
|
netgen::compare assign "$fnum1 $cell1" "$fnum2 $cell2"
|
||||||
|
|
||||||
if {$setupfile == ""} {
|
if {[file exists $setupfile]} {
|
||||||
puts stdout "\nNo setup file specified. Using trivial default setup.\n"
|
puts stdout "Reading setup file $setupfile"
|
||||||
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
|
# Instead of sourcing the setup file, run each line so we can
|
||||||
# catch individual errors and not let them halt the LVS process
|
# catch individual errors and not let them halt the LVS process
|
||||||
set perrors 0
|
set perrors 0
|
||||||
|
|
@ -516,14 +468,6 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close $fsetup
|
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 {
|
} else {
|
||||||
puts stdout "Error: Cannot read the setup file $setupfile"
|
puts stdout "Error: Cannot read the setup file $setupfile"
|
||||||
}
|
}
|
||||||
|
|
@ -532,10 +476,8 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
puts stdout "Warning: There were errors reading the setup file"
|
puts stdout "Warning: There were errors reading the setup file"
|
||||||
}
|
}
|
||||||
} elseif {[string first nosetup $setupfile] < 0} {
|
} elseif {[string first nosetup $setupfile] < 0} {
|
||||||
puts stderr "\nError: Setup file $setupfile does not exist.\n"
|
netgen::permute default ;# transistors and resistors
|
||||||
return
|
netgen::property default
|
||||||
} else {
|
|
||||||
puts stderr "\nNo setup file specified. Continuing without a setup.\n"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if {[string first nolog $logfile] < 0} {
|
if {[string first nolog $logfile] < 0} {
|
||||||
|
|
@ -559,25 +501,14 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
set properr {}
|
set properr {}
|
||||||
set matcherr {}
|
set pinsgood 0
|
||||||
set childMismatch 0 ;# 1 indicates black-box child subcircuit mismatch
|
|
||||||
while {$endval != {}} {
|
while {$endval != {}} {
|
||||||
if {$dolist == 1} {
|
if {$dolist == 1} {
|
||||||
netgen::run -list converge
|
netgen::run -list converge
|
||||||
} else {
|
} else {
|
||||||
netgen::run converge
|
netgen::run converge
|
||||||
}
|
}
|
||||||
set pinMismatch 0 ;# indicates pin mismatch in top cell
|
netgen::log echo on
|
||||||
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]} {
|
if {[verify equivalent]} {
|
||||||
# Resolve automorphisms by pin and property
|
# Resolve automorphisms by pin and property
|
||||||
if {$dolist == 1} {
|
if {$dolist == 1} {
|
||||||
|
|
@ -586,113 +517,49 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
netgen::run resolve
|
netgen::run resolve
|
||||||
}
|
}
|
||||||
set uresult [verify unique]
|
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} {
|
if {$uresult == 0} {
|
||||||
netgen::log echo on
|
|
||||||
netgen::log put " Networks match locally but not globally.\n"
|
netgen::log put " Networks match locally but not globally.\n"
|
||||||
netgen::log put " Probably connections are swapped.\n"
|
netgen::log put " Probably connections are swapped.\n"
|
||||||
netgen::log put " Check the end of logfile ${logfile} for implicated nodes.\n"
|
netgen::log put " Check the end of logfile ${logfile} for implicated nodes.\n"
|
||||||
netgen::log echo off
|
|
||||||
if {$dolist == 1} {
|
if {$dolist == 1} {
|
||||||
verify -list nodes
|
verify -list nodes
|
||||||
} else {
|
} else {
|
||||||
verify nodes
|
verify nodes
|
||||||
}
|
}
|
||||||
set doCheckFlatten 1
|
|
||||||
} else {
|
|
||||||
# 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
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
# 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)} {
|
|
||||||
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 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
# Flatten the non-matching subcircuit (but not the top-level cells)
|
||||||
|
if {[netgen::print queue] != {}} {
|
||||||
|
netgen::log put " Flattening non-matched subcircuits $endval"
|
||||||
|
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||||
|
netgen::flatten class "[lindex $endval 1] $fnum2"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# Match pins
|
||||||
|
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]"
|
||||||
|
}
|
||||||
|
set pinsgood $result
|
||||||
|
netgen::log echo on
|
||||||
|
}
|
||||||
|
if {$uresult == 2} {lappend properr [lindex $endval 0]}
|
||||||
|
} else {
|
||||||
|
# Flatten the non-matching subcircuit (but not the top-level cells)
|
||||||
|
if {[netgen::print queue] != {}} {
|
||||||
|
netgen::log put " Flattening non-matched subcircuits $endval"
|
||||||
|
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||||
|
netgen::flatten class "[lindex $endval 1] $fnum2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
netgen::log echo off
|
||||||
if {$dolist == 1} {
|
if {$dolist == 1} {
|
||||||
catch {lappend lvs_final $lvs_out}
|
catch {lappend lvs_final $lvs_out}
|
||||||
set lvs_out {}
|
set lvs_out {}
|
||||||
|
|
@ -701,23 +568,16 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||||
set endval [netgen::compare hierarchical]
|
set endval [netgen::compare hierarchical]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
netgen::log echo off
|
||||||
|
puts stdout "Result: " nonewline
|
||||||
netgen::log echo on
|
netgen::log echo on
|
||||||
netgen::log put "\nFinal result: "
|
if {$pinsgood == 0} {
|
||||||
if {$pinMismatch || $childMismatch} {
|
netgen::log put "The top level cell failed pin matching.\n"
|
||||||
if {$childMismatch} {
|
|
||||||
netgen::log put "Subcell(s) failed matching.\n"
|
|
||||||
}
|
|
||||||
if {$pinMismatch} {
|
|
||||||
netgen::log put "Top level cell failed pin matching.\n"
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
verify only
|
verify only
|
||||||
}
|
}
|
||||||
if {$properr != {}} {
|
if {$properr != {}} {
|
||||||
netgen::log put "\nThe following cells had property errors:\n " [regsub -all { } $properr "\n "] "\n"
|
netgen::log put "The following cells had property errors: $properr\n"
|
||||||
}
|
|
||||||
if {$matcherr != {}} {
|
|
||||||
netgen::log put "\nThe following subcells failed to match:\n " [regsub -all { } $matcherr "\n "] "\n"
|
|
||||||
}
|
}
|
||||||
if {$dolog} {
|
if {$dolog} {
|
||||||
netgen::log end
|
netgen::log end
|
||||||
|
|
@ -769,19 +629,6 @@ set auto_noexec 1 ;# don't EVER call UNIX commands w/o "shell" in front
|
||||||
# Cross-Application section
|
# 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.
|
# Setup IRSIM assuming that the Tcl version is installed.
|
||||||
# We do not need to rename procedure irsim to NULL because it is
|
# We do not need to rename procedure irsim to NULL because it is
|
||||||
# redefined in a script, which simply overwrites the original.
|
# 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,8 +44,6 @@ exec ${NETGEN_WISH:=wish} "$0" ${1+"$@"}
|
||||||
if {$tcl_version < 8.0} {
|
if {$tcl_version < 8.0} {
|
||||||
return -code error "tkcon requires at least Tcl/Tk8"
|
return -code error "tkcon requires at least Tcl/Tk8"
|
||||||
} else {
|
} else {
|
||||||
# Prevent breaking on version 8.5.2
|
|
||||||
# package require -exact Tk $tcl_version
|
|
||||||
package require Tk $tcl_version
|
package require Tk $tcl_version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,6 +59,18 @@ foreach pkg [info loaded {}] {
|
||||||
}
|
}
|
||||||
catch {unset pkg file name version}
|
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
|
# Initialize the ::tkcon namespace
|
||||||
#
|
#
|
||||||
namespace eval ::tkcon {
|
namespace eval ::tkcon {
|
||||||
|
|
@ -186,7 +196,7 @@ proc ::tkcon::Init {} {
|
||||||
tkcon_puts tkcon_gets observe observe_var unalias which what
|
tkcon_puts tkcon_gets observe observe_var unalias which what
|
||||||
}
|
}
|
||||||
version 2.3
|
version 2.3
|
||||||
RCS {RCS: @(#) $Id: tkcon.tcl,v 1.2 2008/04/18 16:28:13 tim Exp $}
|
RCS {RCS: @(#) $Id: tkcon.tcl,v 1.2 2008/05/23 00:20:17 tim Exp $}
|
||||||
HEADURL {http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/tkcon/tkcon/tkcon.tcl?rev=HEAD}
|
HEADURL {http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/tkcon/tkcon/tkcon.tcl?rev=HEAD}
|
||||||
docs "http://tkcon.sourceforge.net/"
|
docs "http://tkcon.sourceforge.net/"
|
||||||
email {jeff@hobbs.org}
|
email {jeff@hobbs.org}
|
||||||
|
|
@ -735,7 +745,7 @@ proc ::tkcon::EvalCmd {w cmd} {
|
||||||
$w tag bind $tag <Leave> \
|
$w tag bind $tag <Leave> \
|
||||||
[list $w tag configure $tag -underline 0]
|
[list $w tag configure $tag -underline 0]
|
||||||
$w tag bind $tag <ButtonRelease-1> \
|
$w tag bind $tag <ButtonRelease-1> \
|
||||||
"if {!\[info exists ::tk::Priv(mouseMoved)\] || !\$::tk::Priv(mouseMoved)} \
|
"if {!\[info exists tkPriv(mouseMoved)\] || !\$tkPriv(mouseMoved)} \
|
||||||
{[list edit -attach [Attach] -type error -- $PRIV(errorInfo)]}"
|
{[list edit -attach [Attach] -type error -- $PRIV(errorInfo)]}"
|
||||||
} else {
|
} else {
|
||||||
$w insert output $res\n stderr
|
$w insert output $res\n stderr
|
||||||
|
|
@ -2464,7 +2474,7 @@ proc ::tkcon::ErrorHighlight w {
|
||||||
$w tag configure $tag -foreground $COLOR(stdout)
|
$w tag configure $tag -foreground $COLOR(stdout)
|
||||||
$w tag bind $tag <Enter> [list $w tag configure $tag -underline 1]
|
$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 <Leave> [list $w tag configure $tag -underline 0]
|
||||||
$w tag bind $tag <ButtonRelease-1> "if {!\$::tk::Priv(mouseMoved)} \
|
$w tag bind $tag <ButtonRelease-1> "if {!\$tkPriv(mouseMoved)} \
|
||||||
{[list edit -attach $app -type proc -find $what -- $cmd]}"
|
{[list edit -attach $app -type proc -find $what -- $cmd]}"
|
||||||
}
|
}
|
||||||
set info [string range $info $c1 end]
|
set info [string range $info $c1 end]
|
||||||
|
|
@ -2493,7 +2503,7 @@ proc ::tkcon::ErrorHighlight w {
|
||||||
$w tag configure $tag -foreground $COLOR(proc)
|
$w tag configure $tag -foreground $COLOR(proc)
|
||||||
$w tag bind $tag <Enter> [list $w tag configure $tag -underline 1]
|
$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 <Leave> [list $w tag configure $tag -underline 0]
|
||||||
$w tag bind $tag <ButtonRelease-1> "if {!\$::tk::Priv(mouseMoved)} \
|
$w tag bind $tag <ButtonRelease-1> "if {!\$tkPriv(mouseMoved)} \
|
||||||
{[list edit -attach $app -type proc -- $cmd]}"
|
{[list edit -attach $app -type proc -- $cmd]}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2542,8 +2552,8 @@ proc tkcon {cmd args} {
|
||||||
## 'congets' a replacement for [gets stdin]
|
## 'congets' a replacement for [gets stdin]
|
||||||
# Use the 'gets' alias of 'tkcon_gets' command instead of
|
# Use the 'gets' alias of 'tkcon_gets' command instead of
|
||||||
# calling the *get* methods directly for best compatability
|
# calling the *get* methods directly for best compatability
|
||||||
if {[llength $args] > 1} {
|
if {[llength $args]} {
|
||||||
return -code error "wrong # args: must be \"tkcon congets [pfix]\""
|
return -code error "wrong # args: must be \"tkcon congets\""
|
||||||
}
|
}
|
||||||
tkcon show
|
tkcon show
|
||||||
set old [bind TkConsole <<TkCon_Eval>>]
|
set old [bind TkConsole <<TkCon_Eval>>]
|
||||||
|
|
@ -2551,12 +2561,7 @@ proc tkcon {cmd args} {
|
||||||
set w $::tkcon::PRIV(console)
|
set w $::tkcon::PRIV(console)
|
||||||
# Make sure to move the limit to get the right data
|
# Make sure to move the limit to get the right data
|
||||||
$w mark set insert end
|
$w mark set insert end
|
||||||
if {[llength $args]} {
|
$w mark set limit insert
|
||||||
$w mark set limit insert
|
|
||||||
$w insert end $args
|
|
||||||
} else {
|
|
||||||
$w mark set limit insert
|
|
||||||
}
|
|
||||||
$w see end
|
$w see end
|
||||||
vwait ::tkcon::PRIV(wait)
|
vwait ::tkcon::PRIV(wait)
|
||||||
set line [::tkcon::CmdGet $w]
|
set line [::tkcon::CmdGet $w]
|
||||||
|
|
@ -2793,19 +2798,13 @@ proc tkcon_puts args {
|
||||||
foreach {arg1 arg2 arg3} $args { break }
|
foreach {arg1 arg2 arg3} $args { break }
|
||||||
|
|
||||||
if {$len == 1} {
|
if {$len == 1} {
|
||||||
set sarg $arg1
|
tkcon console insert output "$arg1\n" stdout
|
||||||
set nl 1
|
|
||||||
set farg stdout
|
|
||||||
} elseif {$len == 2} {
|
} elseif {$len == 2} {
|
||||||
if {![string compare $arg1 -nonewline]} {
|
if {![string compare $arg1 -nonewline]} {
|
||||||
set sarg $arg2
|
tkcon console insert output $arg2 stdout
|
||||||
set farg stdout
|
|
||||||
set nl 0
|
|
||||||
} elseif {![string compare $arg1 stdout] \
|
} elseif {![string compare $arg1 stdout] \
|
||||||
|| ![string compare $arg1 stderr]} {
|
|| ![string compare $arg1 stderr]} {
|
||||||
set sarg $arg2
|
tkcon console insert output "$arg2\n" $arg1
|
||||||
set farg $arg1
|
|
||||||
set nl 1
|
|
||||||
} else {
|
} else {
|
||||||
set len 0
|
set len 0
|
||||||
}
|
}
|
||||||
|
|
@ -2813,15 +2812,11 @@ proc tkcon_puts args {
|
||||||
if {![string compare $arg1 -nonewline] \
|
if {![string compare $arg1 -nonewline] \
|
||||||
&& (![string compare $arg2 stdout] \
|
&& (![string compare $arg2 stdout] \
|
||||||
|| ![string compare $arg2 stderr])} {
|
|| ![string compare $arg2 stderr])} {
|
||||||
set sarg $arg3
|
tkcon console insert output $arg3 $arg2
|
||||||
set farg $arg2
|
|
||||||
set nl 0
|
|
||||||
} elseif {(![string compare $arg1 stdout] \
|
} elseif {(![string compare $arg1 stdout] \
|
||||||
|| ![string compare $arg1 stderr]) \
|
|| ![string compare $arg1 stderr]) \
|
||||||
&& ![string compare $arg3 nonewline]} {
|
&& ![string compare $arg3 nonewline]} {
|
||||||
set sarg $arg2
|
tkcon console insert output $arg2 $arg1
|
||||||
set farg $arg1
|
|
||||||
set nl 0
|
|
||||||
} else {
|
} else {
|
||||||
set len 0
|
set len 0
|
||||||
}
|
}
|
||||||
|
|
@ -2831,42 +2826,7 @@ proc tkcon_puts args {
|
||||||
|
|
||||||
## $len == 0 means it wasn't handled by tkcon above.
|
## $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
|
global errorCode errorInfo
|
||||||
if {[catch "tkcon_tcl_puts $args" msg]} {
|
if {[catch "tkcon_tcl_puts $args" msg]} {
|
||||||
regsub tkcon_tcl_puts $msg puts msg
|
regsub tkcon_tcl_puts $msg puts msg
|
||||||
|
|
@ -4146,7 +4106,7 @@ proc ::tkcon::Bindings {} {
|
||||||
global tcl_platform tk_version
|
global tcl_platform tk_version
|
||||||
|
|
||||||
#-----------------------------------------------------------------------
|
#-----------------------------------------------------------------------
|
||||||
# Elements of ::tk::Priv that are used in this file:
|
# Elements of tkPriv that are used in this file:
|
||||||
#
|
#
|
||||||
# char - Character position on the line; kept in order
|
# char - Character position on the line; kept in order
|
||||||
# to allow moving up or down past short lines while
|
# to allow moving up or down past short lines while
|
||||||
|
|
@ -4174,9 +4134,6 @@ proc ::tkcon::Bindings {} {
|
||||||
foreach ev [bind Text] { bind TkConsole $ev [bind Text $ev] }
|
foreach ev [bind Text] { bind TkConsole $ev [bind Text $ev] }
|
||||||
## We really didn't want the newline insertion
|
## We really didn't want the newline insertion
|
||||||
bind TkConsole <Control-Key-o> {}
|
bind TkConsole <Control-Key-o> {}
|
||||||
|
|
||||||
## in 8.6b3, the virtual events <<NextLine>> and <<PrevLine>>
|
|
||||||
# mess up our history feature
|
|
||||||
bind TkConsole <<NextLine>> {}
|
bind TkConsole <<NextLine>> {}
|
||||||
bind TkConsole <<PrevLine>> {}
|
bind TkConsole <<PrevLine>> {}
|
||||||
|
|
||||||
|
|
@ -4385,9 +4342,9 @@ proc ::tkcon::Bindings {} {
|
||||||
|
|
||||||
bind TkConsole <Control-a> {
|
bind TkConsole <Control-a> {
|
||||||
if {[%W compare {limit linestart} == {insert linestart}]} {
|
if {[%W compare {limit linestart} == {insert linestart}]} {
|
||||||
::tk::TextSetCursor %W limit
|
tkTextSetCursor %W limit
|
||||||
} else {
|
} else {
|
||||||
::tk::TextSetCursor %W {insert linestart}
|
tkTextSetCursor %W {insert linestart}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bind TkConsole <Key-Home> [bind TkConsole <Control-a>]
|
bind TkConsole <Key-Home> [bind TkConsole <Control-a>]
|
||||||
|
|
@ -4411,14 +4368,14 @@ proc ::tkcon::Bindings {} {
|
||||||
}
|
}
|
||||||
bind TkConsole <<TkCon_Previous>> {
|
bind TkConsole <<TkCon_Previous>> {
|
||||||
if {[%W compare {insert linestart} != {limit linestart}]} {
|
if {[%W compare {insert linestart} != {limit linestart}]} {
|
||||||
::tk::TextSetCursor %W [::tk::TextUpDownLine %W -1]
|
tkTextSetCursor %W [tkTextUpDownLine %W -1]
|
||||||
} else {
|
} else {
|
||||||
::tkcon::Event -1
|
::tkcon::Event -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bind TkConsole <<TkCon_Next>> {
|
bind TkConsole <<TkCon_Next>> {
|
||||||
if {[%W compare {insert linestart} != {end-1c linestart}]} {
|
if {[%W compare {insert linestart} != {end-1c linestart}]} {
|
||||||
::tk::TextSetCursor %W [::tk::TextUpDownLine %W 1]
|
tkTextSetCursor %W [tkTextUpDownLine %W 1]
|
||||||
} else {
|
} else {
|
||||||
::tkcon::Event 1
|
::tkcon::Event 1
|
||||||
}
|
}
|
||||||
|
|
@ -4433,7 +4390,7 @@ proc ::tkcon::Bindings {} {
|
||||||
}
|
}
|
||||||
bind TkConsole <<TkCon_Transpose>> {
|
bind TkConsole <<TkCon_Transpose>> {
|
||||||
## Transpose current and previous chars
|
## Transpose current and previous chars
|
||||||
if {[%W compare insert > "limit+1c"]} { ::tk::TextTranspose %W }
|
if {[%W compare insert > "limit+1c"]} { tkTextTranspose %W }
|
||||||
}
|
}
|
||||||
bind TkConsole <<TkCon_ClearLine>> {
|
bind TkConsole <<TkCon_ClearLine>> {
|
||||||
## Clear command line (Unix shell staple)
|
## Clear command line (Unix shell staple)
|
||||||
|
|
@ -4451,10 +4408,10 @@ proc ::tkcon::Bindings {} {
|
||||||
::tkcon::Insert %W $::tkcon::PRIV(tmp)
|
::tkcon::Insert %W $::tkcon::PRIV(tmp)
|
||||||
%W see end
|
%W see end
|
||||||
}
|
}
|
||||||
catch {bind TkConsole <Key-Page_Up> { ::tk::TextScrollPages %W -1 }}
|
catch {bind TkConsole <Key-Page_Up> { tkTextScrollPages %W -1 }}
|
||||||
catch {bind TkConsole <Key-Prior> { ::tk::TextScrollPages %W -1 }}
|
catch {bind TkConsole <Key-Prior> { tkTextScrollPages %W -1 }}
|
||||||
catch {bind TkConsole <Key-Page_Down> { ::tk::TextScrollPages %W 1 }}
|
catch {bind TkConsole <Key-Page_Down> { tkTextScrollPages %W 1 }}
|
||||||
catch {bind TkConsole <Key-Next> { ::tk::TextScrollPages %W 1 }}
|
catch {bind TkConsole <Key-Next> { tkTextScrollPages %W 1 }}
|
||||||
bind TkConsole <$PRIV(meta)-d> {
|
bind TkConsole <$PRIV(meta)-d> {
|
||||||
if {[%W compare insert >= limit]} {
|
if {[%W compare insert >= limit]} {
|
||||||
%W delete insert {insert wordend}
|
%W delete insert {insert wordend}
|
||||||
|
|
@ -4472,7 +4429,7 @@ proc ::tkcon::Bindings {} {
|
||||||
}
|
}
|
||||||
bind TkConsole <ButtonRelease-2> {
|
bind TkConsole <ButtonRelease-2> {
|
||||||
if {
|
if {
|
||||||
(!$::tk::Priv(mouseMoved) || $tk_strictMotif) &&
|
(!$tkPriv(mouseMoved) || $tk_strictMotif) &&
|
||||||
![catch {::tkcon::GetSelection %W} ::tkcon::PRIV(tmp)]
|
![catch {::tkcon::GetSelection %W} ::tkcon::PRIV(tmp)]
|
||||||
} {
|
} {
|
||||||
if {[%W compare @%x,%y < limit]} {
|
if {[%W compare @%x,%y < limit]} {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue