mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-22 14:07:07 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49ccf1949a | ||
|
|
db457c562b | ||
|
|
9b84776374 | ||
|
|
06386bee1b | ||
|
|
2af3f2a3f7 | ||
|
|
7cd8d82964 | ||
|
|
738abbdad9 | ||
|
|
3aeea9d164 | ||
|
|
12e1ff295f | ||
|
|
8d7569e9a3 | ||
|
|
2f9e898ec6 | ||
|
|
9663579dd0 | ||
|
|
d9425163e1 | ||
|
|
f02e2b1ee0 | ||
|
|
9ba1dfe814 | ||
|
|
cc5f6d929f | ||
|
|
fadd0ae2fc | ||
|
|
4fa4d046c8 | ||
|
|
153ce0e2b3 | ||
|
|
9297090dc1 | ||
|
|
bfdacab28c | ||
|
|
79e193e0c9 | ||
|
|
7e9bd9f2a0 | ||
|
|
2056b37c95 | ||
|
|
ee92d880d7 | ||
|
|
7550ef9258 | ||
|
|
a795981eff | ||
|
|
d3407b3e56 | ||
|
|
1b6e4e2b36 | ||
|
|
0a94bec191 | ||
|
|
edbe5d6e86 | ||
|
|
4a7b6bf22a | ||
|
|
f8ed4e42e2 | ||
|
|
661c9ee854 | ||
|
|
89ef83c597 | ||
|
|
4e96c84ec6 | ||
|
|
5b21c1be3a | ||
|
|
592c16706e | ||
|
|
e11dbac384 | ||
|
|
bfb01e032f | ||
|
|
d0ec17e442 | ||
|
|
0535128421 | ||
|
|
6195745b45 | ||
|
|
afe0e9f758 | ||
|
|
68ec2b2a7c | ||
|
|
ca49a90ed6 | ||
|
|
e487890641 | ||
|
|
e07a5b416a | ||
|
|
bb44d3f827 | ||
|
|
8094740048 | ||
|
|
c25c4e1160 | ||
|
|
a026d37f11 | ||
|
|
8ed4e3cf38 | ||
|
|
ab614b63f7 | ||
|
|
83dce151d8 | ||
|
|
69838d79e4 | ||
|
|
de18ae85a4 | ||
|
|
fc7c9371e8 | ||
|
|
9908349fdd | ||
|
|
964bb0e91a | ||
|
|
0d19868145 | ||
|
|
cfdc60104b | ||
|
|
879711def3 | ||
|
|
5def9e0ffc | ||
|
|
b5c70decbd | ||
|
|
6b4eb01ee8 | ||
|
|
20f6d76926 | ||
|
|
737b2a73bf | ||
|
|
e4a15f12fb | ||
|
|
c6fb204f0c | ||
|
|
6b8c6d1718 | ||
|
|
c7dfff4bb9 | ||
|
|
12fa080212 | ||
|
|
610eebb758 | ||
|
|
4c4bad08f2 | ||
|
|
23ff2f00a3 | ||
|
|
d09f0dd53b | ||
|
|
56d4d581e7 | ||
|
|
1bb4866226 | ||
|
|
97058c5017 | ||
|
|
625e043eff | ||
|
|
aa120460d0 | ||
|
|
6ceeddf096 | ||
|
|
42b1acc564 | ||
|
|
6d6da9cf5c | ||
|
|
ea5cbacf1c | ||
|
|
bbcc79fc72 | ||
|
|
6d5946eaf2 | ||
|
|
cdd768addc | ||
|
|
18dcac73bc | ||
|
|
1338e3beb5 | ||
|
|
df1c4c5153 | ||
|
|
a05ede99db | ||
|
|
2d6f1f71b5 | ||
|
|
66cf2b82d9 | ||
|
|
d7355cea95 | ||
|
|
bc4192496b | ||
|
|
32585a572c | ||
|
|
168e5502a1 | ||
|
|
e773739e7d | ||
|
|
8d4b621b7d | ||
|
|
583cc3a151 | ||
|
|
bdd7d25943 | ||
|
|
903b813821 | ||
|
|
1f9d4317e3 | ||
|
|
7b8086fc3a | ||
|
|
e80f70e67b | ||
|
|
6cc898b34b | ||
|
|
30bbc28c17 | ||
|
|
5ec0db678a | ||
|
|
e643563d4e | ||
|
|
67f2801aa1 | ||
|
|
f76f2e002a | ||
|
|
9ec613b0cb | ||
|
|
9128eeda60 | ||
|
|
aeedf5fae9 | ||
|
|
f50dfd9261 | ||
|
|
409ce224ad | ||
|
|
f50093e6c6 | ||
|
|
a27ac8c679 | ||
|
|
883755eed3 | ||
|
|
484cb26eee | ||
|
|
7cc6996017 | ||
|
|
7f9acf6a1a | ||
|
|
e1a3ae5619 | ||
|
|
4e75889605 | ||
|
|
e017811239 | ||
|
|
4468d36462 | ||
|
|
b99fb96259 | ||
|
|
ec8299ea14 | ||
|
|
376296eda5 | ||
|
|
30acb8be63 | ||
|
|
7e15a26417 | ||
|
|
ba3e862552 | ||
|
|
21750da6c4 | ||
|
|
cf6dd2a638 | ||
|
|
a332c23524 | ||
|
|
b6d896e73f | ||
|
|
064195ecc9 | ||
|
|
88d53fab15 | ||
|
|
c287b6cd28 | ||
|
|
9251ce2a48 | ||
|
|
0a0a6bcf63 | ||
|
|
72ef2f2637 | ||
|
|
aa82164c08 | ||
|
|
287f5963d1 | ||
|
|
fb7876c7a6 | ||
|
|
a984ac1a4d | ||
|
|
e31caa3500 | ||
|
|
738c1f7b37 | ||
|
|
c3cf6c3765 | ||
|
|
99dcc20c0a | ||
|
|
c1355bee45 | ||
|
|
4bbc496749 |
@@ -0,0 +1,40 @@
|
||||
# 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 "[email protected],[email protected]" ${{ secrets.MAILING_KEY }}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ config.log
|
||||
scripts/config.log
|
||||
config.status
|
||||
scripts/config.status
|
||||
python/lvs_manager.py
|
||||
*.o
|
||||
*.so
|
||||
*~
|
||||
|
||||
+48
-1
@@ -1,4 +1,8 @@
|
||||
NETGEN: VERSION 1.5
|
||||

|
||||
|
||||
# NETGEN
|
||||
|
||||
### VERSION 1.5
|
||||
|
||||
NETGEN is a general-purpose netlist management system. It can read
|
||||
and write several netlist formats, including NTK (Caltech, CMU),
|
||||
@@ -87,6 +91,49 @@ and IRSIM version 9.7:
|
||||
|
||||
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
|
||||
-------------------
|
||||
Please contact me (tim@opencircuitdesign.com) to report compile-time and
|
||||
+4
-3
@@ -23,12 +23,13 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for strtod() */
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "netgen.h"
|
||||
#include "hash.h"
|
||||
#include "objlist.h"
|
||||
#include "netfile.h"
|
||||
#include "print.h"
|
||||
#include "hash.h"
|
||||
|
||||
void extCell(char *name, int filenum)
|
||||
{
|
||||
@@ -186,7 +187,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
|
||||
/* Make sure all .ext file reading is case sensitive */
|
||||
matchfunc = match;
|
||||
matchintfunc = matchfile;
|
||||
hashfunc = hash;
|
||||
hashfunc = hashcase;
|
||||
|
||||
if (LookupCellFile(fname, filenum) != NULL) {
|
||||
Printf("Error: Duplicate cell name \"%s\"!\n", fname);
|
||||
@@ -652,7 +653,7 @@ char *ReadSim(char *fname, int *fnum)
|
||||
/* Make sure all .sim file reading is case sensitive */
|
||||
matchfunc = match;
|
||||
matchintfunc = matchfile;
|
||||
hashfunc = hash;
|
||||
hashfunc = hashcase;
|
||||
|
||||
CellDef(fname, filenum);
|
||||
|
||||
|
||||
+165
-60
@@ -66,9 +66,13 @@ void flattenCell(char *name, int file)
|
||||
else
|
||||
ThisCell = LookupCellFile(name, file);
|
||||
if (ThisCell == NULL) {
|
||||
Printf("No cell %s found.\n", name);
|
||||
Printf("No cell %s (%d) found.\n", name, file);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Placeholder cells must not be flattened */
|
||||
if (ThisCell->flags & CELL_PLACEHOLDER) return;
|
||||
|
||||
FreeNodeNames(ThisCell);
|
||||
|
||||
ParentParams = ThisCell->cell;
|
||||
@@ -239,6 +243,13 @@ void flattenCell(char *name, int file)
|
||||
ThisCell->dumped = 1; /* indicate cell has been flattened */
|
||||
}
|
||||
|
||||
/* Structure used to keep track of nodes needing checking */
|
||||
|
||||
struct linkednode {
|
||||
int node;
|
||||
struct linkednode *next;
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* flattenInstancesOf -- */
|
||||
/* */
|
||||
@@ -261,6 +272,7 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
struct nlist *ThisCell;
|
||||
struct nlist *ChildCell;
|
||||
struct objlist *tmp, *ob2, *ob3;
|
||||
struct linkednode *checknodes = NULL, *newlnode, *chknode;
|
||||
int notdone, rnodenum;
|
||||
char tmpstr[1024];
|
||||
int nextnode, oldmax, numflat = 0;
|
||||
@@ -278,16 +290,20 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
}
|
||||
else {
|
||||
if (Debug)
|
||||
Printf("Flattening instances of %s within cell: %s\n", instance, name);
|
||||
Printf("Flattening instances of %s within cell: %s (%d)\n", instance,
|
||||
name, fnum);
|
||||
if (fnum == -1)
|
||||
ThisCell = LookupCell(name);
|
||||
else
|
||||
ThisCell = LookupCellFile(name, fnum);
|
||||
if (ThisCell == NULL) {
|
||||
Printf("No cell %s found.\n", name);
|
||||
Printf("No cell %s (%d) found.\n", name, fnum);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Placeholder cells must not be flattened */
|
||||
if (ThisCell->flags & CELL_PLACEHOLDER) return 0;
|
||||
|
||||
FreeNodeNames(ThisCell);
|
||||
|
||||
ParentParams = ThisCell->cell;
|
||||
@@ -344,7 +360,10 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
|
||||
/* Find the end record of the parent cell and save it */
|
||||
for (ParentEnd = (ParentProps) ? ParentProps : ParentParams;
|
||||
ParentEnd && ParentEnd->next && ParentEnd->next->type != FIRSTPIN;
|
||||
ParentEnd && ParentEnd->next &&
|
||||
/* Stop on a node or the next instance */
|
||||
((ParentEnd->next->type > FIRSTPIN) ||
|
||||
(ParentEnd->next->type == PROPERTY));
|
||||
ParentEnd = ParentEnd->next);
|
||||
|
||||
/* Not primitive, so need to flatten this instance */
|
||||
@@ -369,22 +388,16 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
|
||||
/* update node numbers in child to unique numbers */
|
||||
oldmax = 0;
|
||||
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next)
|
||||
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) {
|
||||
if (tmp->node > oldmax) oldmax = tmp->node;
|
||||
if (nextnode <= oldmax) nextnode = oldmax + 1;
|
||||
|
||||
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next)
|
||||
if (tmp->node <= oldmax && tmp->node > 0) {
|
||||
if (Debug) Printf("Update node %d --> %d\n", tmp->node, nextnode);
|
||||
UpdateNodeNumbers(ChildStart, tmp->node, nextnode);
|
||||
nextnode++;
|
||||
}
|
||||
if (tmp->node > 0) tmp->node += (nextnode - 1);
|
||||
}
|
||||
nextnode += oldmax;
|
||||
|
||||
/* copy nodenumbers of ports from parent */
|
||||
ob2 = ParentParams;
|
||||
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) {
|
||||
if (IsPort(tmp)) {
|
||||
if (tmp->node > 0) {
|
||||
for (tmp = ChildStart; tmp && IsPort(tmp); tmp = tmp->next) {
|
||||
if (tmp->node > 0) {
|
||||
if (ob2->node == -1) {
|
||||
|
||||
// Before commiting to attaching to a unconnected node, see
|
||||
@@ -410,17 +423,26 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
Printf("Update node %d --> %d\n", tmp->node, ob2->node);
|
||||
}
|
||||
UpdateNodeNumbers(ChildStart, tmp->node, ob2->node);
|
||||
}
|
||||
}
|
||||
else if (tmp->node == -1) {
|
||||
/* Opposite case: If child port is an unconnected node, then */
|
||||
/* removing the instance may make the parent node become */
|
||||
/* unconnected. For now, just record the node number. At the */
|
||||
/* end we'll check if these nodes are actually disconnected. */
|
||||
newlnode = (struct linkednode *)MALLOC(sizeof(struct linkednode));
|
||||
newlnode->node = ob2->node;
|
||||
newlnode->next = checknodes;
|
||||
checknodes = newlnode;
|
||||
}
|
||||
|
||||
/* in pathological cases, the lengths of the port lists may
|
||||
* change. This is an error, but that is no reason to allow
|
||||
* the code to core dump. We avoid this by placing a
|
||||
* superfluous check on ob2->type
|
||||
*/
|
||||
if (ob2 != NULL) ob2 = ob2->next;
|
||||
/* in pathological cases, the lengths of the port lists may
|
||||
* change. This is an error, but that is no reason to allow
|
||||
* the code to core dump. We avoid this by placing a
|
||||
* superfluous check on ob2->type
|
||||
*/
|
||||
if (ob2 != NULL) ob2 = ob2->next;
|
||||
|
||||
if (ob2 == NULL) break;
|
||||
}
|
||||
if (ob2 == NULL) break;
|
||||
}
|
||||
|
||||
/* Using name == NULL to indicate that a .ext file is being */
|
||||
@@ -594,6 +616,29 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
NextObj = ParentParams;
|
||||
} /* repeat until no more instances found */
|
||||
}
|
||||
|
||||
/* Check nodes that may have become disconnected after child flattening */
|
||||
while (checknodes != NULL) {
|
||||
struct objlist *portnode = NULL;
|
||||
|
||||
chknode = checknodes;
|
||||
checknodes = checknodes->next;
|
||||
|
||||
for (ob3 = ThisCell->cell; ob3; ob3 = ob3->next) {
|
||||
if ((ob3->type != PORT) && (portnode == NULL))
|
||||
break;
|
||||
else if ((ob3->type == PORT) && (ob3->node == chknode->node))
|
||||
portnode = ob3;
|
||||
else if ((ob3->type >= FIRSTPIN) && (ob3->node == chknode->node))
|
||||
break;
|
||||
}
|
||||
if ((ob3 == NULL) && (portnode != NULL)) {
|
||||
/* Port became disconnected when child was flattened */
|
||||
portnode->node = -1;
|
||||
}
|
||||
FREE(chknode);
|
||||
}
|
||||
|
||||
CacheNodeNames(ThisCell);
|
||||
ThisCell->dumped = 1; /* indicate cell has been flattened */
|
||||
return numflat;
|
||||
@@ -685,7 +730,7 @@ void convertGlobalsOf(char *name, int fnum, char *instance)
|
||||
else
|
||||
ThisCell = LookupCellFile(name, fnum);
|
||||
if (ThisCell == NULL) {
|
||||
Printf("No cell %s found.\n", name);
|
||||
Printf("No cell %s (%d) found.\n", name, fnum);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1115,7 +1160,7 @@ int UniquePins(char *name, int filenum)
|
||||
ThisCell = LookupCellFile(name, filenum);
|
||||
|
||||
if (ThisCell == NULL) {
|
||||
Printf("No cell %s found.\n", name);
|
||||
Printf("No cell %s (%d) found.\n", name, filenum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1132,12 +1177,33 @@ int UniquePins(char *name, int filenum)
|
||||
firstport = (struct objlist **)CALLOC(maxnode + 1, sizeof(struct objlist *));
|
||||
|
||||
portcount = FIRSTPIN;
|
||||
lob = NULL;
|
||||
for (ob = ThisCell->cell; ob != NULL; ob = ob->next) {
|
||||
if (ob->type != PORT) break;
|
||||
if (ob->node > 0) {
|
||||
nodecount[ob->node]++;
|
||||
if (nodecount[ob->node] == 2) {
|
||||
Printf("Duplicate pin %s in cell %s\n", ob->name, ThisCell->name);
|
||||
if (!(*matchfunc)(firstport[ob->node]->name, ob->name)) {
|
||||
Printf("Pins %s and %s are shorted in cell %s (%d)\n", ob->name,
|
||||
firstport[ob->node]->name, ThisCell->name, ThisCell->file);
|
||||
/* Do not count this as a duplicate pin. */
|
||||
nodecount[ob->node]--;
|
||||
/* Move the pin adjacent to the one it is shorted to (if it
|
||||
* isn't already); this will make the work of MatchPins() easier.
|
||||
*/
|
||||
if (firstport[ob->node]->next != ob) {
|
||||
lob->next = ob->next;
|
||||
ob->next = firstport[ob->node]->next;
|
||||
firstport[ob->node]->next = ob;
|
||||
ob = lob;
|
||||
}
|
||||
lob = ob;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
Printf("Duplicate pin %s in cell %s (%d)\n", ob->name,
|
||||
ThisCell->name, filenum);
|
||||
}
|
||||
}
|
||||
if (nodecount[ob->node] > 1) {
|
||||
/* Remove this node; prep for removal by marking with UNKNOWN */
|
||||
@@ -1152,6 +1218,7 @@ int UniquePins(char *name, int filenum)
|
||||
}
|
||||
}
|
||||
portcount++;
|
||||
lob = ob;
|
||||
}
|
||||
|
||||
if (needscleanup)
|
||||
@@ -1336,7 +1403,7 @@ int CleanupPins(char *name, int filenum)
|
||||
ThisCell = LookupCellFile(name, filenum);
|
||||
|
||||
if (ThisCell == NULL) {
|
||||
Printf("No cell %s found.\n", name);
|
||||
Printf("No cell %s (%d) found.\n", name, filenum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1418,6 +1485,22 @@ typedef struct ecomplist {
|
||||
ECompListPtr next;
|
||||
} ECompList;
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Determine if a cell contains at least one device or subcircuit */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
HasContents(struct nlist *tc)
|
||||
{
|
||||
struct objlist *ob;
|
||||
|
||||
for (ob = tc->cell; ob; ob = ob->next)
|
||||
if (ob->type == FIRSTPIN)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Survey the contents of a cell and sort into a hash */
|
||||
/*------------------------------------------------------*/
|
||||
@@ -1515,6 +1598,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
struct hashdict compdict;
|
||||
ECompare *ecomp, *ncomp;
|
||||
ECompList *list0X, *listX0;
|
||||
int hascontents1, hascontents2;
|
||||
int match, modified = 0;
|
||||
|
||||
if (file1 == -1)
|
||||
@@ -1530,6 +1614,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
if (tc1 == NULL || tc2 == NULL) return 0;
|
||||
|
||||
InitializeHashTable(&compdict, OBJHASHSIZE);
|
||||
listX0 = list0X = NULL;
|
||||
|
||||
// Gather information about instances of cell "name1"
|
||||
SurveyCell(tc1, &compdict, file1, file2, 0);
|
||||
@@ -1542,7 +1627,6 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
// in the hierarchy of each instance contain devices
|
||||
// or subcircuits that have more in the compared circuit.
|
||||
|
||||
listX0 = list0X = NULL;
|
||||
ecomp = (ECompare *)HashFirst(&compdict);
|
||||
while (ecomp != NULL) {
|
||||
|
||||
@@ -1579,25 +1663,29 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
}
|
||||
else {
|
||||
match = 0;
|
||||
// cell exists in one circuit but not the other, so flatten it.
|
||||
// match = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
if (ecomp->cell1 && (ecomp->num1 > 0)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
if (ecomp->cell1 && (ecomp->num1 > 0) &&
|
||||
(!(ecomp->cell1->flags & CELL_PLACEHOLDER))) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" makes a better match\n", ecomp->cell1->name,
|
||||
name1);
|
||||
name1, file1);
|
||||
flattenInstancesOf(name1, file1, ecomp->cell1->name);
|
||||
modified++;
|
||||
}
|
||||
if (ecomp->cell2 && (ecomp->num2 > 0)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
if (ecomp->cell2 && (ecomp->num2 > 0) &&
|
||||
(!(ecomp->cell2->flags & CELL_PLACEHOLDER))) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" makes a better match\n", ecomp->cell2->name,
|
||||
name2);
|
||||
name2, file2);
|
||||
flattenInstancesOf(name2, file2, ecomp->cell2->name);
|
||||
modified++;
|
||||
}
|
||||
modified++;
|
||||
}
|
||||
|
||||
/* Reset or apply the count adjustments */
|
||||
@@ -1646,7 +1734,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
|
||||
/* Case 2: Cell2 class is a subcircuit, and flattening */
|
||||
/* (it without regard to cell1) improves the matching. */
|
||||
/* it (without regard to cell1) improves the matching. */
|
||||
|
||||
else if ((ecomp->num1 != ecomp->num2) && (ecomp->cell2 != NULL) &&
|
||||
(ecomp->num2 != 0) && (ecomp->cell2->class == CLASS_SUBCKT)) {
|
||||
@@ -1674,13 +1762,21 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
if (ecomp->cell2) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
|
||||
/* Don't flatten if cell1 is a black box, because it */
|
||||
/* can't also be flattened. */
|
||||
|
||||
if ((ecomp->num1 == 0) || (ecomp->cell1->class !=
|
||||
CLASS_MODULE)) {
|
||||
|
||||
if (ecomp->cell2 && !(ecomp->cell2->flags & CELL_PLACEHOLDER)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" makes a better match\n", ecomp->cell2->name,
|
||||
name2);
|
||||
flattenInstancesOf(name2, file2, ecomp->cell2->name);
|
||||
name2, file2);
|
||||
flattenInstancesOf(name2, file2, ecomp->cell2->name);
|
||||
modified++;
|
||||
}
|
||||
}
|
||||
modified++;
|
||||
}
|
||||
|
||||
/* Reset or apply the count adjustments */
|
||||
@@ -1704,7 +1800,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
|
||||
/* Case 3: Cell1 class is a subcircuit, and flattening */
|
||||
/* (it without regard to cell1) improves the matching. */
|
||||
/* it (without regard to cell2) improves the matching. */
|
||||
|
||||
else if ((ecomp->num1 != ecomp->num2) && (ecomp->cell1 != NULL) &&
|
||||
(ecomp->num1 != 0) && (ecomp->cell1->class == CLASS_SUBCKT)) {
|
||||
@@ -1732,13 +1828,21 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
if (ecomp->cell1) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
|
||||
/* Don't flatten if cell2 is a black box, because it */
|
||||
/* can't also be flattened. */
|
||||
|
||||
if ((ecomp->num2 == 0) || (ecomp->cell2->class !=
|
||||
CLASS_MODULE)) {
|
||||
|
||||
if (ecomp->cell1 && !(ecomp->cell1->flags & CELL_PLACEHOLDER)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" makes a better match\n", ecomp->cell1->name,
|
||||
name1);
|
||||
flattenInstancesOf(name1, file1, ecomp->cell1->name);
|
||||
name1, file1);
|
||||
flattenInstancesOf(name1, file1, ecomp->cell1->name);
|
||||
modified++;
|
||||
}
|
||||
}
|
||||
modified++;
|
||||
}
|
||||
|
||||
/* Reset or apply the count adjustments */
|
||||
@@ -1816,9 +1920,9 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
if (found) {
|
||||
Fprintf(stdout, "Removing zero-valued device "
|
||||
"%s from cell %s makes a better match\n",
|
||||
tsub1->name,
|
||||
tc1->name);
|
||||
"%s from cell %s (%d) makes a better "
|
||||
"match\n",
|
||||
tsub1->name, tc1->name, tc1->file);
|
||||
|
||||
/* A current source is an open, while a */
|
||||
/* resistor or voltage source is a short. */
|
||||
@@ -1927,9 +2031,9 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
if (found) {
|
||||
Fprintf(stdout, "Removing zero-valued device "
|
||||
"%s from cell %s makes a better match\n",
|
||||
tsub2->name,
|
||||
tc2->name);
|
||||
"%s from cell %s (%d) makes a better "
|
||||
"match\n",
|
||||
tsub2->name, tc2->name, tc2->file);
|
||||
|
||||
/* merge node of endpoints */
|
||||
if (ecomp->cell2->class != CLASS_ISOURCE) {
|
||||
@@ -2020,8 +2124,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
if (dstr) *dstr = '[';
|
||||
if ((ncomp == ecomp0X) && (ecomp0X->num2 <= ecompX0->num1)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
" makes a better match\n", ecompX0->cell1->name,
|
||||
name1);
|
||||
"(%d) makes a better match\n",
|
||||
ecompX0->cell1->name, name1, file1);
|
||||
flattenInstancesOf(name1, file1, ecompX0->cell1->name);
|
||||
ecompX0->num1 = 0;
|
||||
ecomp0X->num1 += ecompX0->num1;
|
||||
@@ -2046,8 +2150,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
if (dstr) *dstr = '[';
|
||||
if ((ncomp == ecompX0) && (ecompX0->num1 <= ecomp0X->num2)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
" makes a better match\n", ecomp0X->cell2->name,
|
||||
name2);
|
||||
" (%d) makes a better match\n",
|
||||
ecomp0X->cell2->name, name2, file2);
|
||||
flattenInstancesOf(name2, file2, ecomp0X->cell2->name);
|
||||
ecomp0X->num2 = 0;
|
||||
ecompX0->num2 += ecomp0X->num2;
|
||||
@@ -2061,6 +2165,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
// Free the hash table and its contents.
|
||||
|
||||
ecomp = (ECompare *)HashFirst(&compdict);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#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 */
|
||||
+2
-2
@@ -30,8 +30,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#endif
|
||||
|
||||
#include "netgen.h"
|
||||
#include "hash.h"
|
||||
#include "objlist.h"
|
||||
#include "hash.h"
|
||||
|
||||
unsigned long (*hashfunc)(char *, int) = NULL;
|
||||
int (*matchfunc)(char *, char *) = NULL;
|
||||
@@ -148,7 +148,7 @@ unsigned long hashnocase(char *s, int hashsize)
|
||||
return (hashsize == 0) ? hashval : (hashval % hashsize);
|
||||
}
|
||||
|
||||
unsigned long hash(char *s, int hashsize)
|
||||
unsigned long hashcase(char *s, int hashsize)
|
||||
{
|
||||
unsigned long hashval;
|
||||
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ extern void *HashFirst(struct hashdict *dict);
|
||||
extern void *HashNext(struct hashdict *dict);
|
||||
|
||||
extern unsigned long hashnocase(char *s, int hashsize);
|
||||
extern unsigned long hash(char *s, int hashsize);
|
||||
extern unsigned long hashcase(char *s, int hashsize);
|
||||
|
||||
extern int (*matchfunc)(char *, char *);
|
||||
/* matchintfunc() compares based on the name and the first */
|
||||
|
||||
+366
-148
@@ -21,11 +21,13 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for rand(), abs(), etc */
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <time.h> /* for time() as a seed for random number generator */
|
||||
#include <limits.h>
|
||||
#include <math.h> /* for fabs() */
|
||||
#include <ctype.h> /* for toupper() */
|
||||
|
||||
#ifdef IBMPC
|
||||
#include <alloc.h>
|
||||
@@ -45,11 +47,13 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "netfile.h"
|
||||
#include "print.h"
|
||||
#include "dbug.h"
|
||||
#include "hash.h"
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
int InterruptPending = 0;
|
||||
void (*oldinthandler)() = SIG_DFL;
|
||||
extern Tcl_Interp *netgeninterp;
|
||||
extern int check_interrupt();
|
||||
#endif
|
||||
|
||||
/* define the following to debug core allocation */
|
||||
@@ -620,15 +624,15 @@ struct FormattedList *FormatBadElementFragment(struct Element *E)
|
||||
for (elems = nodes[i]->node->elementlist; elems != NULL;
|
||||
elems = elems->next)
|
||||
count++;
|
||||
|
||||
elemlist->flist[k].count = count;
|
||||
if (*ob->name != *ob->instance.name) // e.g., "port_match_error"
|
||||
elemlist->flist[k].name = ob->name;
|
||||
else
|
||||
elemlist->flist[k].name = ob->name + strlen(ob->instance.name) + 1;
|
||||
elemlist->flist[k].permute = (char)1;
|
||||
k++;
|
||||
}
|
||||
|
||||
elemlist->flist[k].count = count;
|
||||
if (*ob->name != *ob->instance.name) // e.g., "port_match_error"
|
||||
elemlist->flist[k].name = ob->name;
|
||||
else
|
||||
elemlist->flist[k].name = ob->name + strlen(ob->instance.name) + 1;
|
||||
elemlist->flist[k].permute = (char)1;
|
||||
k++;
|
||||
}
|
||||
else { /* handle multiple permutable pins */
|
||||
struct objlist *ob2;
|
||||
@@ -665,13 +669,16 @@ struct FormattedList *FormatBadElementFragment(struct Element *E)
|
||||
struct ElementList *elems;
|
||||
|
||||
count = 0;
|
||||
if (nodes[j]->node == NULL) continue; // ?
|
||||
for (elems = nodes[j]->node->elementlist; elems != NULL;
|
||||
elems = elems->next)
|
||||
count++;
|
||||
if (nodes[j]->node == NULL) /* Under what condition is the node NULL? */
|
||||
count++;
|
||||
else {
|
||||
for (elems = nodes[j]->node->elementlist; elems != NULL;
|
||||
elems = elems->next)
|
||||
count++;
|
||||
}
|
||||
if (count >= maxcount) {
|
||||
maxcount = count;
|
||||
maxindex = j;
|
||||
maxcount = count;
|
||||
maxindex = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -868,7 +875,11 @@ struct FormattedList *FormatBadNodeFragment(struct Node *N)
|
||||
for (n = pins[i]->subelement->element->nodelist; n != NULL; n = n->next){
|
||||
if (n->pin_magic == pins[i]->subelement->pin_magic) {
|
||||
if ((permute == 0) && (ob->instance.name != NULL)) {
|
||||
pinname = ob->name + strlen(ob->instance.name) + 1;
|
||||
/* Handle "port_match_error" */
|
||||
if ((ob->name[0] == 'p') && !strcmp(ob->name, "port_match_error"))
|
||||
pinname = ob->name;
|
||||
else
|
||||
pinname = ob->name + strlen(ob->instance.name) + 1;
|
||||
}
|
||||
else if (ob->instance.name != NULL) {
|
||||
char *pinsave = pinname;
|
||||
@@ -886,9 +897,8 @@ struct FormattedList *FormatBadNodeFragment(struct Node *N)
|
||||
WITH THE SAME HASH NUMBER, are on this node */
|
||||
for (j = i+1; j < fanout; j++) {
|
||||
if (pins[j] != NULL &&
|
||||
(*matchfunc) (model,
|
||||
pins[j]->subelement->element->object->model.class) &&
|
||||
pins[i]->subelement->pin_magic == pins[j]->subelement->pin_magic) {
|
||||
(*matchfunc)(model, pins[j]->subelement->element->object->model.class) &&
|
||||
pins[i]->subelement->pin_magic == pins[j]->subelement->pin_magic) {
|
||||
count++;
|
||||
nodelist->fanout--;
|
||||
pins[j] = NULL;
|
||||
@@ -968,16 +978,36 @@ void PrintBadNodeFragment(struct Node *N)
|
||||
WITH THE SAME HASH NUMBER, are on this node */
|
||||
for (j = i+1; j < fanout; j++) {
|
||||
if (pins[j] != NULL &&
|
||||
(*matchfunc)(model,
|
||||
pins[j]->subelement->element->object->model.class) &&
|
||||
pins[i]->subelement->pin_magic == pins[j]->subelement->pin_magic) {
|
||||
count++;
|
||||
pins[j] = NULL;
|
||||
}
|
||||
(*matchfunc)(model, pins[j]->subelement->element->object->model.class) &&
|
||||
pins[i]->subelement->pin_magic == pins[j]->subelement->pin_magic) {
|
||||
count++;
|
||||
/* pins[j] = NULL; */ /* Done in diagnostic output, below */
|
||||
}
|
||||
}
|
||||
|
||||
if (i != 0) Fprintf(stdout, ";");
|
||||
if (i != 0) {
|
||||
/* Fprintf(stdout, ";"); */
|
||||
Fprintf(stdout, "\n");
|
||||
Ftab(stdout, 32);
|
||||
}
|
||||
Fprintf(stdout, " %s:%s = %d", model, pinname, count);
|
||||
|
||||
/* Diagnostic */
|
||||
Fprintf(stdout, "\n");
|
||||
Ftab(stdout, 25);
|
||||
Fprintf(stdout, ">>> %s", pins[i]->subelement->element->object->instance);
|
||||
for (j = i+1; j < fanout; j++) {
|
||||
if (pins[j] != NULL &&
|
||||
(*matchfunc)(model, pins[j]->subelement->element->object->model.class) &&
|
||||
pins[i]->subelement->pin_magic == pins[j]->subelement->pin_magic) {
|
||||
/* Diagnostic */
|
||||
Fprintf(stdout, "\n");
|
||||
Ftab(stdout, 25);
|
||||
Fprintf(stdout, ">>> %s", pins[j]->subelement->element->object->instance);
|
||||
pins[j] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pins[i] = NULL; /* not really necessary */
|
||||
}
|
||||
Fprintf(stdout, "\n");
|
||||
@@ -1360,8 +1390,8 @@ void SortUnmatchedLists(nlists1, nlists2, n1max, n2max)
|
||||
nlists2[n1] = temp;
|
||||
HashPtrInstall(nlists2[n1]->name, (void *)((long)n1 + 1), &n2hash);
|
||||
HashPtrInstall(nlists2[n2]->name, (void *)((long)n2 + 1), &n2hash);
|
||||
SortFanoutLists(nlists1[n1], nlists2[n1]);
|
||||
}
|
||||
SortFanoutLists(nlists1[n1], nlists2[n1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1416,8 +1446,13 @@ void SortUnmatchedLists(nlists1, nlists2, n1max, n2max)
|
||||
nlists1[n2] = temp;
|
||||
HashPtrInstall(nlists1[n1]->name, (void *)((long)n1 + 1), &n1hash);
|
||||
HashPtrInstall(nlists1[n2]->name, (void *)((long)n2 + 1), &n1hash);
|
||||
SortFanoutLists(nlists2[n2], nlists1[n2]);
|
||||
}
|
||||
SortFanoutLists(nlists2[n2], nlists1[n2]);
|
||||
}
|
||||
else if ((n1max == 1) && (n2max == 1)) {
|
||||
/* Names didn't match but there's only one entry on each side, */
|
||||
/* so do a sort anyway. */
|
||||
SortFanoutLists(nlists2[n2], nlists1[n2]);
|
||||
}
|
||||
}
|
||||
/* For all nets that didn't match by name, match by content */
|
||||
@@ -3091,6 +3126,47 @@ struct nlist *LookupPrematchedClass(struct nlist *tc1, int file2)
|
||||
return tc2;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Scan the property list of a device to find the number of devices */
|
||||
/* implied by the total of M records. If the device does not have a */
|
||||
/* property list, then return 1. If any property list does not have an */
|
||||
/* "M" record, treat it as 1. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
int GetNumDevices(struct objlist *ob)
|
||||
{
|
||||
int p, found, M = 0;
|
||||
struct objlist *obs;
|
||||
struct valuelist *vl;
|
||||
|
||||
obs = ob;
|
||||
if (obs->type != PROPERTY)
|
||||
for (obs = ob->next; obs && (obs->type != FIRSTPIN) &&
|
||||
(obs->type != PROPERTY); obs = obs->next);
|
||||
|
||||
if ((obs == NULL) || (obs->type != PROPERTY)) return 1;
|
||||
|
||||
while (obs && (obs->type == PROPERTY)) {
|
||||
found = FALSE;
|
||||
for (p = 0; ; p++) {
|
||||
vl = &obs->instance.props[p];
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
if (vl->key == NULL) continue;
|
||||
if ((*matchfunc)(vl->key, "M")) {
|
||||
if (vl->type == PROP_DOUBLE)
|
||||
M += (int)vl->value.dval;
|
||||
else
|
||||
M += vl->value.ival;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == FALSE) M++;
|
||||
obs = obs->next;
|
||||
}
|
||||
return M;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Attempt to define FirstElementPass that will generate element */
|
||||
/* classes by names of pins, which will allow elements with different */
|
||||
@@ -3112,7 +3188,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
|
||||
struct Element *Esrch, *Ecorr;
|
||||
struct NodeList *n;
|
||||
struct nlist *tp1, *tp2, *tp;
|
||||
int C1, C2, i;
|
||||
int C1, C2, M1, M2, i;
|
||||
char *ostr;
|
||||
int needflat = 0;
|
||||
#ifdef TCL_NETGEN
|
||||
@@ -3122,7 +3198,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
|
||||
ostr = CALLOC(right_col_end + 2, sizeof(char));
|
||||
|
||||
if (Debug == 0) {
|
||||
Fprintf(stdout, "\nSubcircuit summary:\n");
|
||||
Fprintf(stdout, "Subcircuit summary:\n");
|
||||
*(ostr + left_col_end) = '|';
|
||||
*(ostr + right_col_end) = '\n';
|
||||
*(ostr + right_col_end + 1) = '\0';
|
||||
@@ -3153,6 +3229,8 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
|
||||
Esrch->hashval = 1;
|
||||
C1 = 1;
|
||||
C2 = 0;
|
||||
M2 = 0;
|
||||
M1 = GetNumDevices(Esrch->object);
|
||||
tp1 = LookupCellFile(Esrch->object->model.class, Circuit1->file);
|
||||
tp2 = LookupClassEquivalent(Esrch->object->model.class, Circuit1->file,
|
||||
Circuit2->file);
|
||||
@@ -3164,6 +3242,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
|
||||
if (tp && tp2 && (tp->classhash == tp2->classhash)) {
|
||||
Ecorr->hashval = 1;
|
||||
C2++;
|
||||
M2 += GetNumDevices(Ecorr->object);
|
||||
}
|
||||
}
|
||||
else if (Ecorr->graph == Circuit1->file) {
|
||||
@@ -3172,6 +3251,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
|
||||
if (tp && tp1 && (tp->classhash == tp1->classhash)) {
|
||||
Ecorr->hashval = 1;
|
||||
C1++;
|
||||
M1 += GetNumDevices(Ecorr->object);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3188,10 +3268,19 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
|
||||
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
snprintf(ostr, left_col_end, "%s (%d)", Esrch->object->model.class, C1);
|
||||
if (C2 > 0)
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)%s", tp2->name, C2,
|
||||
(C2 == C1) ? "" : " **Mismatch**");
|
||||
if (M1 == C1)
|
||||
snprintf(ostr, left_col_end, "%s (%d)", Esrch->object->model.class, C1);
|
||||
else
|
||||
snprintf(ostr, left_col_end, "%s (%d->%d)", Esrch->object->model.class,
|
||||
M1, C1);
|
||||
if (C2 > 0) {
|
||||
if (M2 == C2)
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)%s", tp2->name,
|
||||
C2, (C2 == C1) ? "" : " **Mismatch**");
|
||||
else
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d->%d)%s",
|
||||
tp2->name, M2, C2, (C2 == C1) ? "" : " **Mismatch**");
|
||||
}
|
||||
else {
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching element)");
|
||||
}
|
||||
@@ -3230,6 +3319,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
|
||||
if (Esrch->graph == Circuit2->file && Esrch->hashval == 0) {
|
||||
Esrch->hashval = 1;
|
||||
C2 = 1;
|
||||
M2 = GetNumDevices(Esrch->object);
|
||||
tp2 = LookupCellFile(Esrch->object->model.class, Circuit2->file);
|
||||
tp1 = LookupClassEquivalent(Esrch->object->model.class, Circuit2->file,
|
||||
Circuit1->file);
|
||||
@@ -3241,6 +3331,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
|
||||
if (tp->classhash == tp2->classhash) {
|
||||
Ecorr->hashval = 1;
|
||||
C2++;
|
||||
M2 += GetNumDevices(Ecorr->object);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3256,7 +3347,12 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
|
||||
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
|
||||
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
|
||||
snprintf(ostr, left_col_end, "(no matching element)");
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)", Esrch->object->model.class, C2);
|
||||
if (C2 == M2)
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)",
|
||||
Esrch->object->model.class, C2);
|
||||
else
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d->%d)",
|
||||
Esrch->object->model.class, M2, C2);
|
||||
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
}
|
||||
@@ -3636,12 +3732,19 @@ int CreateCompareQueue(char *name1, int file1, char *name2, int file2)
|
||||
Fprintf(stdout, "Descend level %d circuit 2\n", level);
|
||||
DescendCompareQueue(tc2, tc1, level, 0, 1);
|
||||
|
||||
/* NOTE: Preemptive flattening is inefficient and can cause
|
||||
* unnecessary flattening of cells that will never be compared.
|
||||
* let the prematch stage take care of this.
|
||||
*/
|
||||
/*--------------------------------------
|
||||
if (Debug == TRUE)
|
||||
Fprintf(stdout, "Flatten level %d circuit 1\n", level);
|
||||
FlattenUnmatched(tc1, name1, level, 0);
|
||||
if (Debug == TRUE)
|
||||
Fprintf(stdout, "Flatten level %d circuit 2\n", level);
|
||||
FlattenUnmatched(tc2, name2, level, 0);
|
||||
---------------------------------------*/
|
||||
|
||||
level--;
|
||||
}
|
||||
|
||||
@@ -3720,8 +3823,23 @@ void RemoveCompareQueue()
|
||||
CompareQueue = NULL;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Output a summary of the contents of the two circuits being compared */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void DescribeContents(char *name1, int file1, char *name2, int file2)
|
||||
{
|
||||
Fprintf(stdout, "\n"); // blank line before new circuit diagnostics in log file
|
||||
/* print preliminary statistics */
|
||||
Printf("\nContents of circuit 1: ");
|
||||
DescribeInstance(name1, file1);
|
||||
Printf("Contents of circuit 2: ");
|
||||
DescribeInstance(name2, file2);
|
||||
Printf("\n");
|
||||
}
|
||||
|
||||
/*----------------------------------*/
|
||||
/* create an initial data structure */
|
||||
/* Create an initial data structure */
|
||||
/*----------------------------------*/
|
||||
|
||||
void CreateTwoLists(char *name1, int file1, char *name2, int file2, int dolist)
|
||||
@@ -3733,13 +3851,6 @@ void CreateTwoLists(char *name1, int file1, char *name2, int file2, int dolist)
|
||||
|
||||
ResetState();
|
||||
|
||||
/* print preliminary statistics */
|
||||
Printf("Contents of circuit 1: ");
|
||||
DescribeInstance(name1, file1);
|
||||
Printf("Contents of circuit 2: ");
|
||||
DescribeInstance(name2, file2);
|
||||
Printf("\n");
|
||||
|
||||
if (file1 == -1)
|
||||
tc1 = LookupCell(name1);
|
||||
else
|
||||
@@ -3753,7 +3864,7 @@ void CreateTwoLists(char *name1, int file1, char *name2, int file2, int dolist)
|
||||
/* determine if matching will be case sensitive or case insensitive */
|
||||
matchfunc = match;
|
||||
matchintfunc = matchfile;
|
||||
hashfunc = hash;
|
||||
hashfunc = hashcase;
|
||||
if (tc1 != NULL && tc2 != NULL) {
|
||||
if ((tc1->flags & CELL_NOCASE) && (tc2->flags & CELL_NOCASE)) {
|
||||
matchfunc = matchnocase;
|
||||
@@ -4118,6 +4229,7 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
sval = 1;
|
||||
cval = slop = 0.0;
|
||||
for (i = 0; i < run; i++) {
|
||||
sl = NULL;
|
||||
merge_type = MERGE_NONE;
|
||||
for (p = 0;; p++) {
|
||||
vl = &(obp->instance.props[p]);
|
||||
@@ -4146,13 +4258,13 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
proplist[i].value = cval * (double)sval;
|
||||
proplist[i].slop = slop;
|
||||
proplist[i].avalue = 0;
|
||||
sl->value.ival = 1;
|
||||
if (sl) sl->value.ival = 1;
|
||||
}
|
||||
else if (merge_type == MERGE_S_PAR) {
|
||||
proplist[i].value = cval / (double)sval;
|
||||
proplist[i].slop = slop;
|
||||
proplist[i].avalue = 0;
|
||||
sl->value.ival = 1;
|
||||
if (sl) sl->value.ival = 1;
|
||||
}
|
||||
else {
|
||||
/* Components which declare no series addition method stay unsorted */
|
||||
@@ -4813,6 +4925,7 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
// Now combine records with same properties by summing M (S).
|
||||
if (comb == FALSE) {
|
||||
for (i = 0; i < run - 1; i++) {
|
||||
int nr_empty = 0;
|
||||
for (j = i + 1; j < run; j++) {
|
||||
pmatch = 0;
|
||||
for (p = 1; p < pcount; p++) {
|
||||
@@ -4892,6 +5005,11 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
// find ith record in ob
|
||||
p = 0;
|
||||
for (ob2 = ob; p != i; ob2 = ob2->next, p++);
|
||||
/* Sanity check */
|
||||
if (ob2->type != PROPERTY) {
|
||||
Fprintf(stderr, "Incorrect property run count!\n");
|
||||
continue;
|
||||
}
|
||||
// Count entries, add one, reallocate
|
||||
for (p = 0;; p++) {
|
||||
vl = &ob2->instance.props[p];
|
||||
@@ -4936,8 +5054,14 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
vlist[0][i]->value.ival += vlist[0][j]->value.ival;
|
||||
vlist[0][j]->value.ival = 0;
|
||||
}
|
||||
else
|
||||
nr_empty++;
|
||||
}
|
||||
}
|
||||
// If everything from i to the end of the run has been matched
|
||||
// and zeroed out, then nothing more can be merged.
|
||||
if (nr_empty == (run - (i + 1)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5017,11 +5141,8 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
for (p = 1; p < pcount; p++) {
|
||||
vl = vlist[p][i];
|
||||
ctype = clist[p][i];
|
||||
|
||||
if (ctype & (MERGE_S_ADD | MERGE_P_ADD)) {
|
||||
if (vl->type == PROP_INTEGER)
|
||||
vl->value.ival *= mult;
|
||||
else if (vl->type == PROP_DOUBLE)
|
||||
vl->value.dval *= (double)mult;
|
||||
vlist[0][i]->value.ival = 0; /* set M to 0 */
|
||||
if (cvl && (cvl->type == PROP_INTEGER))
|
||||
{
|
||||
@@ -5039,26 +5160,25 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
else
|
||||
cvl->value.dval += vl->value.dval;
|
||||
}
|
||||
changed += mult;
|
||||
}
|
||||
else if (ctype & (MERGE_S_PAR | MERGE_P_PAR)) {
|
||||
vlist[0][i]->value.ival = 0; /* set M to 0 */
|
||||
/* To do parallel combination, both types need to
|
||||
* be double, so recast them if they are integer.
|
||||
*/
|
||||
if (vl->type == PROP_INTEGER) {
|
||||
vl->type = PROP_DOUBLE;
|
||||
vl->value.dval = (double)(vl->value.ival);
|
||||
}
|
||||
if (vl->type == PROP_DOUBLE)
|
||||
vl->value.dval /= (double)mult;
|
||||
vlist[0][i]->value.ival = 0; /* set M to 0 */
|
||||
if (cvl && (cvl->type == PROP_INTEGER)) {
|
||||
cvl->type = PROP_DOUBLE;
|
||||
cvl->value.dval = (double)cvl->value.ival;
|
||||
}
|
||||
if ((cvl && vl->type == PROP_DOUBLE)) {
|
||||
if ((cvl && (vl->type == PROP_DOUBLE))) {
|
||||
cvl->value.dval =
|
||||
sqrt(cvl->value.dval * cvl->value.dval
|
||||
+ vl->value.dval * vl->value.dval);
|
||||
}
|
||||
changed += mult;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6070,7 +6190,8 @@ void PrintPropertyResults(int do_list)
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Return 0 if perfect matching found, else return number of */
|
||||
/* automorphisms, and return -1 if invalid matching found. */
|
||||
/* automorphisms, and return -1 if invalid matching found, */
|
||||
/* and return -2 if there is a port count mismatch. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
int VerifyMatching(void)
|
||||
@@ -6081,6 +6202,9 @@ int VerifyMatching(void)
|
||||
struct Element *E;
|
||||
struct Node *N;
|
||||
int C1, C2, result;
|
||||
int P1, P2;
|
||||
struct objlist *ob1, *ob2;
|
||||
int portMismatch = 0;
|
||||
|
||||
if (BadMatchDetected) return(-1);
|
||||
|
||||
@@ -6101,14 +6225,40 @@ int VerifyMatching(void)
|
||||
}
|
||||
}
|
||||
|
||||
P1 = P2 = 0;
|
||||
for (NC = NodeClasses; NC != NULL; NC = NC->next) {
|
||||
C1 = C2 = 0;
|
||||
for (N = NC->nodes; N != NULL; N = N->next) {
|
||||
(N->graph == Circuit1->file) ? C1++ : C2++;
|
||||
if (IsPort(N->object)) (N->graph == Circuit1->file) ? P1++ : P2++;
|
||||
}
|
||||
if (C1 != C2) return(-1);
|
||||
if (P1 != P2) portMismatch = 1;
|
||||
if (C1 != 1) ret++;
|
||||
}
|
||||
|
||||
P1 = P2 = 0;
|
||||
if (ret == 0) { /* automorphisms have precedence over port count mismatch */
|
||||
if (portMismatch) return -2;
|
||||
|
||||
/* Count ports in each subcircuit including disconnected ports */
|
||||
for (ob1 = Circuit1->cell; ob1 && IsPort(ob1); ob1 = ob1->next, P1++);
|
||||
for (ob2 = Circuit2->cell; ob2 && IsPort(ob2); ob2 = ob2->next, P2++);
|
||||
if (P1 == P2) { // pin counts match. Make sure disconnected pins match, too.
|
||||
for (ob1 = Circuit1->cell; ob1 && IsPort(ob1); ob1 = ob1->next) {
|
||||
if (ob1->node == -1) { // disconnected pin
|
||||
for (ob2 = Circuit2->cell; ob2 && IsPort(ob2); ob2 = ob2->next) {
|
||||
if (ob2->node == -1 && (*matchfunc)(ob1->name, ob2->name))
|
||||
break; // disconnected pin match
|
||||
}
|
||||
if (ob2 == NULL) return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // pin count mismatch
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
@@ -6207,7 +6357,7 @@ int ResolveAutomorphsByPin()
|
||||
FractureElementClass(&ElementClasses);
|
||||
FractureNodeClass(&NodeClasses);
|
||||
ExhaustiveSubdivision = 1;
|
||||
while (!Iterate() && VerifyMatching() != -1);
|
||||
while (!Iterate() && VerifyMatching() >= 0);
|
||||
return(VerifyMatching());
|
||||
}
|
||||
|
||||
@@ -6310,7 +6460,7 @@ int ResolveAutomorphsByProperty()
|
||||
FractureElementClass(&ElementClasses);
|
||||
FractureNodeClass(&NodeClasses);
|
||||
ExhaustiveSubdivision = 1;
|
||||
while (!Iterate() && VerifyMatching() != -1);
|
||||
while (!Iterate() && VerifyMatching() >= 0);
|
||||
return(VerifyMatching());
|
||||
}
|
||||
|
||||
@@ -6387,7 +6537,7 @@ int ResolveAutomorphisms()
|
||||
FractureElementClass(&ElementClasses);
|
||||
FractureNodeClass(&NodeClasses);
|
||||
ExhaustiveSubdivision = 1;
|
||||
while (!Iterate() && VerifyMatching() != -1);
|
||||
while (!Iterate() && VerifyMatching() >= 0);
|
||||
return(VerifyMatching());
|
||||
}
|
||||
|
||||
@@ -6892,11 +7042,6 @@ int reorderpins(struct hashlist *p, int file)
|
||||
"Ordering will be arbitrary.\n", tc2->name);
|
||||
|
||||
for (ob = ptr->cell; ob != NULL; ) {
|
||||
/* Catch badness */
|
||||
if (ob->next && (ob->next->node > 100000)) {
|
||||
Fprintf(stdout, "Bad.\n");
|
||||
}
|
||||
|
||||
if (ob->type == FIRSTPIN) {
|
||||
if ((*matchfunc)(ob->model.class, tc2->name)) {
|
||||
char *sptr = ob->instance.name;
|
||||
@@ -7087,37 +7232,36 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata)
|
||||
return NULL; /* Keep the search going */
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Declare that the device class "name1" is equivalent */
|
||||
/* to class "name2". This is the same as the above */
|
||||
/* routine, except that the cells must be at the top */
|
||||
/* of the compare queue, and must already be proven */
|
||||
/* equivalent by LVS. Determine a pin correspondence, */
|
||||
/* then modify all instances of "name2" to match all */
|
||||
/* instances of "name1" by pin reordering. If either */
|
||||
/* cell has disconnected pins, they are shuffled to the */
|
||||
/* end of the pin list. If two or more pins correspond */
|
||||
/* to net automorphisms, then they are added to the */
|
||||
/* list of permuted pins. */
|
||||
/* */
|
||||
/* NOTE: This routine must not be called on any */
|
||||
/* circuit pair that has not been matched. If a */
|
||||
/* circuit pair has been matched with automorphisms, */
|
||||
/* then some pins may be matched arbitrarily. */
|
||||
/* */
|
||||
/* If "dolist" is 1, append the list representing the */
|
||||
/* output (if any) to variable tcl_out, if it exists. */
|
||||
/* */
|
||||
/* Return codes: */
|
||||
/* 2: Neither cell had pins, so matching is unnecessary */
|
||||
/* 1: Exact match */
|
||||
/* 0: Inexact match resolved by proxy pin insertion */
|
||||
/*------------------------------------------------------*/
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Declare that the device class "name1" is equivalent to class */
|
||||
/* "name2". This is the same as the above routine, except that */
|
||||
/* the cells must be at the top of the compare queue, and must */
|
||||
/* already be proven equivalent by LVS. Determine a pin */
|
||||
/* correspondence, then modify all instances of "name2" to */
|
||||
/* match all instances of "name1" by pin reordering. If either */
|
||||
/* cell has disconnected pins, they are shuffled to the end of */
|
||||
/* the pin list. If two or more pins correspond to net */
|
||||
/* automorphisms, then they are added to the list of permuted */
|
||||
/* pins. */
|
||||
/* */
|
||||
/* NOTE: This routine must not be called on any circuit pair */
|
||||
/* that has not been matched. If a circuit pair has been */
|
||||
/* matched with automorphisms, then some pins may be matched */
|
||||
/* arbitrarily. */
|
||||
/* */
|
||||
/* If "dolist" is 1, append the list representing the output */
|
||||
/* (if any) to variable tcl_out, if it exists. */
|
||||
/* */
|
||||
/* Return codes: */
|
||||
/* 2: Neither cell had pins, so matching is unnecessary */
|
||||
/* 1: Exact match */
|
||||
/* 0: Inexact match resolved by proxy pin insertion. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
{
|
||||
char *cover, *ctemp;
|
||||
char *bangptr1, *bangptr2;
|
||||
char *bangptr1, *bangptr2, *backslashptr1, *backslashptr2;
|
||||
struct objlist *ob1, *ob2, *obn, *obp, *ob1s, *ob2s, *obt;
|
||||
struct NodeClass *NC;
|
||||
struct Node *N1, *N2;
|
||||
@@ -7191,8 +7335,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (IsPort(obn)) {
|
||||
i = 0;
|
||||
for (ob1 = tc1->cell; ob1 != NULL; ob1 = ob1->next, i++) {
|
||||
if ((IsPort(ob1))
|
||||
&& (*matchfunc)(ob1->name, obn->name)) {
|
||||
if ((IsPort(ob1)) && (ob1->node == obn->node)) {
|
||||
b = 0;
|
||||
for (N2 = NC->nodes; N2 != NULL; N2 = N2->next) {
|
||||
if (N2->graph != Circuit1->file) {
|
||||
@@ -7217,16 +7360,42 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
obp = N2->object;
|
||||
j = 0;
|
||||
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next, j++) {
|
||||
if ((IsPort(ob2))
|
||||
&& (*matchfunc)(ob2->name, obp->name)) {
|
||||
if ((IsPort(ob2)) && (ob2->node == obp->node)) {
|
||||
if (Debug == 0) {
|
||||
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
|
||||
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
|
||||
snprintf(ostr, left_col_end, "%s", obn->name);
|
||||
if ((*matchfunc)(obn->name, obp->name))
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", obp->name);
|
||||
else
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s **Mismatch**", obp->name);
|
||||
snprintf(ostr, left_col_end, "%s", ob1->name);
|
||||
if ((*matchfunc)(ob1->name, ob2->name))
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
|
||||
else {
|
||||
/* Check remainder of ports to see if there is a name match on the
|
||||
* same net number (multiple ports tied to the same net)
|
||||
*/
|
||||
struct objlist *ob3;
|
||||
for (ob3 = ob2->next, ++j; ob3 != NULL; ob3 = ob3->next, j++) {
|
||||
if ((IsPort(ob3)) && (ob3->node == ob2->node)) {
|
||||
if ((*matchfunc)(ob3->name, ob1->name)) {
|
||||
ob2 = ob3;
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ob3 = NULL;
|
||||
break; /* All pins w/the same node should be together */
|
||||
}
|
||||
}
|
||||
if (ob3 == NULL) {
|
||||
if (ob2->model.port == -1)
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s **Mismatch**", ob2->name);
|
||||
else
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
|
||||
/* Pins with different names are on different nets,
|
||||
* so this should trigger an error return code.
|
||||
*/
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
@@ -7247,7 +7416,16 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
#endif
|
||||
ob2->model.port = i; /* save order */
|
||||
*(cover + i) = (char)1;
|
||||
break;
|
||||
|
||||
/* If there are multiple pins on the same net, cycle through them; */
|
||||
/* otherwise, move to the next entry in the partition. */
|
||||
if (ob1->next && (ob1->next->type == PORT) && (ob1->next->node == ob1->node)) {
|
||||
ob1 = ob1->next;
|
||||
ob2 = tc2->cell; /* Restart search for matching pin */
|
||||
i++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ob2 == NULL) {
|
||||
@@ -7338,36 +7516,54 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
/* This should not happen if unconnected pins are eliminated */
|
||||
/* so apply only to black-box (CELL_PLACEHOLDER) entries. */
|
||||
/* (Semi-hack: Allow "!" global flag) */
|
||||
/* (Another semi-hack: Ignore the leading backslash in */
|
||||
/* backslash-escaped verilog names. Removing the backslash */
|
||||
/* and ending space character is a common way to convert to */
|
||||
/* legal SPICE. */
|
||||
|
||||
if (((tc1->flags & CELL_PLACEHOLDER) && (tc2->flags & CELL_PLACEHOLDER)) ||
|
||||
(NodeClasses == NULL)) {
|
||||
ob1 = tc1->cell;
|
||||
ob1 = tc1->cell;
|
||||
|
||||
for (i = 0; i < numorig; i++) {
|
||||
bangptr1 = strrchr(ob1->name, '!');
|
||||
if (bangptr1 && (*(bangptr1 + 1) == '\0'))
|
||||
*bangptr1 = '\0';
|
||||
else bangptr1 = NULL;
|
||||
|
||||
for (i = 0; i < numorig; i++) {
|
||||
if (*(cover + i) == (char)0) {
|
||||
j = 0;
|
||||
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
|
||||
char *name1, *name2;
|
||||
backslashptr1 = (*(ob1->name) == '\\') ? ob1->name + 1 : ob1->name;
|
||||
|
||||
if (!IsPort(ob2)) break;
|
||||
if (*(cover + i) == (char)0) {
|
||||
j = 0;
|
||||
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
|
||||
char *name1, *name2;
|
||||
|
||||
bangptr2 = strrchr(ob2->name, '!');
|
||||
if (bangptr2 && (*(bangptr2 + 1) == '\0'))
|
||||
*bangptr2 = '\0';
|
||||
else bangptr2 = NULL;
|
||||
if (!IsPort(ob2)) break;
|
||||
|
||||
name1 = ob1->name;
|
||||
name2 = ob2->name;
|
||||
bangptr2 = strrchr(ob2->name, '!');
|
||||
if (bangptr2 && (*(bangptr2 + 1) == '\0'))
|
||||
*bangptr2 = '\0';
|
||||
else bangptr2 = NULL;
|
||||
|
||||
/* Recognize proxy pins as matching */
|
||||
if (!strncmp(name1, "proxy", 5)) name1 +=5;
|
||||
if (!strncmp(name2, "proxy", 5)) name2 +=5;
|
||||
backslashptr2 = (*(ob2->name) == '\\') ? ob2->name + 1 : ob2->name;
|
||||
|
||||
name1 = backslashptr1;
|
||||
name2 = backslashptr2;
|
||||
|
||||
/* Recognize proxy pins as matching unconnected pins */
|
||||
if (!strncmp(name1, "proxy", 5) && (ob2->node == -1)) name1 +=5;
|
||||
if (!strncmp(name2, "proxy", 5) && (ob1->node == -1)) name2 +=5;
|
||||
|
||||
if ((*matchfunc)(name1, name2)) {
|
||||
|
||||
/* If both sides have unconnected nodes, then pins with */
|
||||
/* matching names are an automatic match. Otherwise, if */
|
||||
/* matching black-box entries, then pins are always */
|
||||
/* matched by name. */
|
||||
|
||||
if (((ob1->node == -1) && (ob2->node == -1)) ||
|
||||
(((tc1->flags & CELL_PLACEHOLDER) &&
|
||||
(tc2->flags & CELL_PLACEHOLDER)) ||
|
||||
(NodeClasses == NULL))) {
|
||||
|
||||
if ((*matchfunc)(name1, name2)) {
|
||||
ob2->model.port = i; /* save order */
|
||||
*(cover + i) = (char)1;
|
||||
|
||||
@@ -7394,13 +7590,15 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
Tcl_NewStringObj(ob2->name, -1));
|
||||
}
|
||||
#endif
|
||||
if (bangptr2) *bangptr2 = '!';
|
||||
break;
|
||||
}
|
||||
if (bangptr2) *bangptr2 = '!';
|
||||
j++;
|
||||
}
|
||||
if (bangptr2) *bangptr2 = '!';
|
||||
j++;
|
||||
}
|
||||
ob1 = ob1->next;
|
||||
}
|
||||
ob1 = ob1->next;
|
||||
if (bangptr1) *bangptr1 = '!';
|
||||
}
|
||||
|
||||
@@ -7452,6 +7650,12 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if ((obt == NULL) && (notempty == 1)) {
|
||||
ob2->node = -2; // Will run this through cleanuppins
|
||||
needclean2 = 1;
|
||||
|
||||
/* On the top level, missing pins are an error, even if */
|
||||
/* they appear to match unconnected pins on the other side. */
|
||||
if (CompareQueue == NULL)
|
||||
result = 0;
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
if (dolist) {
|
||||
Tcl_ListObjAppendElement(netgeninterp, plist1,
|
||||
@@ -7539,7 +7743,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
}
|
||||
|
||||
if (ob1 == NULL || ob1->type != PORT || ob1->node >= 0
|
||||
|| (ob1->node < 0 && tc1->class == CLASS_MODULE)) {
|
||||
|| (ob1->node < 0 && tc1->class == CLASS_MODULE)
|
||||
|| (ob1->node < 0 && ob1->model.port == -1)) {
|
||||
|
||||
/* Add a proxy pin to tc2 */
|
||||
obn = (struct objlist *)CALLOC(1, sizeof(struct objlist));
|
||||
@@ -7556,8 +7761,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
obn->instance.name = NULL;
|
||||
obn->node = -1;
|
||||
|
||||
#if 0
|
||||
/* Note: This pin has already been accounted for */
|
||||
/* Note: Has this pin already been accounted for? */
|
||||
if (Debug == 0) {
|
||||
if (strcmp(ob1->name, "(no pins)")) {
|
||||
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
|
||||
@@ -7573,7 +7777,6 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
Fprintf(stderr, "No netlist match for cell %s pin %s\n",
|
||||
tc1->name, ob1->name);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ob2 == tc2->cell) {
|
||||
obn->next = ob2;
|
||||
@@ -7648,7 +7851,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
}
|
||||
|
||||
/* Check for ports that did not get ordered */
|
||||
for (obn = tc2->cell; obn && (obn->type == PORT); obn = obn->next) {
|
||||
for (obn = tc2->cell; obn && IsPort(obn); obn = obn->next) {
|
||||
if (obn->model.port == -1) {
|
||||
if (obn->node == -1) {
|
||||
// This only happens when pins have become separated from any net.
|
||||
@@ -7826,10 +8029,12 @@ int EquivalentElement(char *name, struct nlist *circuit, struct objlist **retobj
|
||||
void FlattenCurrent()
|
||||
{
|
||||
if (Circuit1 != NULL && Circuit2 != NULL) {
|
||||
Fprintf(stdout, "Flattening subcell %s\n", Circuit1->name);
|
||||
Fprintf(stdout, "Flattening subcell %s (%d)\n", Circuit1->name,
|
||||
Circuit1->file);
|
||||
FlattenInstancesOf(Circuit1->name, Circuit1->file);
|
||||
|
||||
Fprintf(stdout, "Flattening subcell %s\n", Circuit2->name);
|
||||
Fprintf(stdout, "Flattening subcell %s (%d)\n", Circuit2->name,
|
||||
Circuit2->file);
|
||||
FlattenInstancesOf(Circuit2->name, Circuit2->file);
|
||||
}
|
||||
}
|
||||
@@ -7886,6 +8091,7 @@ int Compare(char *cell1, char *cell2)
|
||||
{
|
||||
int automorphisms;
|
||||
|
||||
DescribeContents(cell1, -1, cell2, -1);
|
||||
CreateTwoLists(cell1, -1, cell2, -1, 0);
|
||||
Permute();
|
||||
while (!Iterate());
|
||||
@@ -7899,7 +8105,25 @@ int Compare(char *cell1, char *cell2)
|
||||
PrintIllegalClasses();
|
||||
return(0);
|
||||
}
|
||||
if (automorphisms == 0) Fprintf(stdout, "Circuits match correctly.\n");
|
||||
|
||||
if (automorphisms > 0) {
|
||||
Fprintf(stdout, "Circuits match with %d symmetries.\n", automorphisms);
|
||||
if (VerboseOutput) PrintAutomorphisms();
|
||||
|
||||
/* arbitrarily resolve automorphisms */
|
||||
Fprintf(stdout, "\n");
|
||||
Fprintf(stdout, "Resolving automorphisms by arbitrary symmetry breaking:\n");
|
||||
while ((automorphisms = ResolveAutomorphisms()) > 0) ;
|
||||
if (automorphisms == -1) {
|
||||
MatchFail(cell1, cell2);
|
||||
Fprintf(stdout, "Circuits do not match.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (automorphisms == -2) { // Port count mismatch
|
||||
Fprintf(stderr, "Port counts do not match.\n");
|
||||
return 0;
|
||||
}
|
||||
if (PropertyErrorDetected == 1) {
|
||||
Fprintf(stdout, "There were property errors.\n");
|
||||
PrintPropertyResults(0);
|
||||
@@ -7908,22 +8132,10 @@ int Compare(char *cell1, char *cell2)
|
||||
Fprintf(stdout, "There were missing properties.\n");
|
||||
PrintPropertyResults(0);
|
||||
}
|
||||
if (automorphisms == 0) return(1);
|
||||
else
|
||||
Fprintf(stdout, "Circuits match correctly.\n");
|
||||
|
||||
Fprintf(stdout, "Circuits match with %d automorphisms.\n", automorphisms);
|
||||
if (VerboseOutput) PrintAutomorphisms();
|
||||
|
||||
/* arbitrarily resolve automorphisms */
|
||||
Fprintf(stdout, "\n");
|
||||
Fprintf(stdout, "Resolving automorphisms by arbitrary symmetry breaking:\n");
|
||||
while ((automorphisms = ResolveAutomorphisms()) > 0) ;
|
||||
if (automorphisms == -1) {
|
||||
MatchFail(cell1, cell2);
|
||||
Fprintf(stdout, "Circuits do not match.\n");
|
||||
return(0);
|
||||
}
|
||||
Fprintf(stdout, "Circuits match correctly.\n");
|
||||
return(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -7946,6 +8158,7 @@ void NETCOMP(void)
|
||||
case 'c':
|
||||
promptstring("Enter cell 1: ",name);
|
||||
promptstring("Enter cell 2: ",name2);
|
||||
DescribeContents(name, -1, name2, -1);
|
||||
CreateTwoLists(name, -1, name2, -1, 0);
|
||||
#ifdef DEBUG_ALLOC
|
||||
PrintCoreStats();
|
||||
@@ -7976,9 +8189,12 @@ void NETCOMP(void)
|
||||
PrintIllegalClasses();
|
||||
Fprintf(stdout, "Netlists do not match.\n");
|
||||
}
|
||||
else if (automorphisms == -2) { // port count mismatch
|
||||
Fprintf(stdout, "Port counts do not match.\n");
|
||||
}
|
||||
else {
|
||||
if (automorphisms)
|
||||
Printf("Circuits match with %d automorphisms.\n", automorphisms);
|
||||
Printf("Circuits match with %d symmetries.\n", automorphisms);
|
||||
else Printf("Circuits match correctly.\n");
|
||||
}
|
||||
}
|
||||
@@ -7991,11 +8207,13 @@ void NETCOMP(void)
|
||||
while (!Iterate()) ;
|
||||
automorphisms = VerifyMatching();
|
||||
if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n");
|
||||
else if (automorphisms == -2) Fprintf(stdout, "Port counts do not match.\n");
|
||||
else {
|
||||
Printf("Netlists match with %d automorphisms.\n", automorphisms);
|
||||
Printf("Netlists match with %d symmetries.\n", automorphisms);
|
||||
while ((automorphisms = ResolveAutomorphisms()) > 0)
|
||||
Printf(" automorphisms = %d.\n", automorphisms);
|
||||
if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n");
|
||||
else if (automorphisms == -2) Fprintf(stdout, "Port counts do not match.\n");
|
||||
else Printf("Circuits match correctly.\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ extern void PrintCoreStats(void);
|
||||
extern void ResetState(void);
|
||||
extern void CreateTwoLists(char *name1, int file1, char *name2, int file2,
|
||||
int dolist);
|
||||
extern void DescribeContents(char *name1, int file1, char *name2, int file2);
|
||||
extern int Iterate(void);
|
||||
extern int VerifyMatching(void);
|
||||
extern void PrintAutomorphisms(void);
|
||||
@@ -46,6 +47,7 @@ extern int CreateCompareQueue(char *, int, char *, int);
|
||||
extern int GetCompareQueueTop(char **, int *, char **, int *);
|
||||
extern int PeekCompareQueueTop(char **, int *, char **, int *);
|
||||
extern void RemoveCompareQueue();
|
||||
extern int FlattenUnmatched(struct nlist *, char *, int, int);
|
||||
|
||||
extern void PrintIllegalClasses();
|
||||
extern void PrintIllegalNodeClasses();
|
||||
@@ -54,6 +56,15 @@ extern void PrintIllegalElementClasses();
|
||||
extern void DumpNetwork(struct objlist *ob, int cidx);
|
||||
extern void DumpNetworkAll(char *name, int file);
|
||||
|
||||
extern void RegroupDataStructures();
|
||||
extern void FormatIllegalElementClasses();
|
||||
extern void FormatIllegalNodeClasses();
|
||||
extern int ResolveAutomorphsByProperty();
|
||||
extern int ResolveAutomorphsByPin();
|
||||
extern void SummarizeElementClasses(struct ElementClass *EC);
|
||||
extern int remove_group_tags(struct objlist *ob);
|
||||
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
extern int EquivalentNode();
|
||||
extern int EquivalentElement();
|
||||
|
||||
+73
-63
@@ -331,77 +331,87 @@ int GetNextLineNoNewline(char *delimiter)
|
||||
linetok = (char *)MALLOC(linesize + 1);
|
||||
}
|
||||
|
||||
/* Check for substitutions (verilog only). Make sure linetok is */
|
||||
/* large enough to hold the entire line after substitutions. */
|
||||
|
||||
if (definitions != NULL) {
|
||||
char *s, *w, e;
|
||||
struct property *kl;
|
||||
int len, dlen, vlen, addin = 0;
|
||||
unsigned char found = FALSE;
|
||||
|
||||
for (s = line; *s != '\0'; s++) {
|
||||
if (*s == '`') {
|
||||
w = s + 1;
|
||||
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
|
||||
e = *w;
|
||||
*w = '\0';
|
||||
kl = (struct property *)HashLookup(s + 1, definitions);
|
||||
if (kl != NULL) {
|
||||
dlen = strlen(s);
|
||||
if (kl->type == PROP_STRING) {
|
||||
vlen = strlen(kl->pdefault.string);
|
||||
}
|
||||
else vlen = 12; /* Leave room for numeric conversion */
|
||||
addin += vlen - dlen + 1;
|
||||
found = TRUE;
|
||||
}
|
||||
*w = e;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
len = strlen(line);
|
||||
if (len + addin > linesize) {
|
||||
while (len + addin > linesize) linesize += 500;
|
||||
FREE(linetok);
|
||||
linetok = (char *)MALLOC(linesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Make definition substitutions (verilog only) */
|
||||
|
||||
if (definitions != NULL) {
|
||||
if (definitions == NULL)
|
||||
strcpy(linetok, line);
|
||||
else {
|
||||
char *s, *t, *w, e;
|
||||
struct property *kl;
|
||||
int len, dlen, vlen, addin = 0;
|
||||
int oldlinesize = linesize;
|
||||
unsigned char found = TRUE;
|
||||
|
||||
t = linetok;
|
||||
for (s = line; *s != '\0'; s++) {
|
||||
if (*s == '`') {
|
||||
w = s + 1;
|
||||
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
|
||||
e = *w;
|
||||
*w = '\0';
|
||||
kl = (struct property *)HashLookup(s + 1, definitions);
|
||||
if (kl != NULL) {
|
||||
if (kl->type == PROP_STRING)
|
||||
strcpy(t, kl->pdefault.string);
|
||||
else if (kl->type == PROP_INTEGER)
|
||||
sprintf(t, "%d", kl->pdefault.ival);
|
||||
else if (kl->type == PROP_DOUBLE)
|
||||
sprintf(t, "%g", kl->pdefault.dval);
|
||||
t += strlen(t);
|
||||
s = w - 1;
|
||||
/* Check for substitutions (verilog only). Make sure linetok is */
|
||||
/* large enough to hold the entire line after substitutions. */
|
||||
|
||||
while (found) { /* Do this recursively, for nested definitions */
|
||||
found = FALSE;
|
||||
|
||||
for (s = line; *s != '\0'; s++) {
|
||||
if (*s == '`') {
|
||||
w = s + 1;
|
||||
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
|
||||
e = *w;
|
||||
*w = '\0';
|
||||
kl = (struct property *)HashLookup(s + 1, definitions);
|
||||
if (kl != NULL) {
|
||||
dlen = strlen(s);
|
||||
if (kl->type == PROP_STRING) {
|
||||
vlen = strlen(kl->pdefault.string);
|
||||
}
|
||||
else vlen = 12; /* Leave room for numeric conversion */
|
||||
addin += vlen - dlen + 1;
|
||||
found = TRUE;
|
||||
}
|
||||
*w = e;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
len = strlen(line);
|
||||
if (len + addin > linesize) {
|
||||
while (len + addin > linesize) linesize += 500;
|
||||
FREE(linetok);
|
||||
linetok = (char *)MALLOC(linesize);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make definition substitutions (verilog only) */
|
||||
|
||||
t = linetok;
|
||||
for (s = line; *s != '\0'; s++) {
|
||||
if (*s == '`') {
|
||||
w = s + 1;
|
||||
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
|
||||
e = *w;
|
||||
*w = '\0';
|
||||
kl = (struct property *)HashLookup(s + 1, definitions);
|
||||
if (kl != NULL) {
|
||||
if (kl->type == PROP_STRING)
|
||||
strcpy(t, kl->pdefault.string);
|
||||
else if (kl->type == PROP_INTEGER)
|
||||
sprintf(t, "%d", kl->pdefault.ival);
|
||||
else if (kl->type == PROP_DOUBLE)
|
||||
sprintf(t, "%g", kl->pdefault.dval);
|
||||
t += strlen(t);
|
||||
s = w - 1;
|
||||
}
|
||||
else *t++ = *s;
|
||||
*w = e;
|
||||
}
|
||||
else *t++ = *s;
|
||||
*w = e;
|
||||
}
|
||||
*t = '\0';
|
||||
|
||||
/* Copy substituted linetok back to line and repeat until */
|
||||
/* there are no more substitutions to be made. */
|
||||
|
||||
if (oldlinesize != linesize) {
|
||||
FREE(line);
|
||||
line = (char *)MALLOC(linesize + 501);
|
||||
oldlinesize = linesize;
|
||||
}
|
||||
else *t++ = *s;
|
||||
strcpy(line, linetok);
|
||||
}
|
||||
*t = '\0';
|
||||
}
|
||||
else
|
||||
strcpy(linetok, line);
|
||||
|
||||
TrimQuoted(linetok);
|
||||
linenum++;
|
||||
|
||||
+26
-25
@@ -3337,16 +3337,13 @@ int CombineParallel(char *model, int file)
|
||||
/* "sob" to it. If "ob" does not have properties, then */
|
||||
/* create a property record and set property "M" to 1. */
|
||||
|
||||
/* Find last non-property record of sob ( = pob) */
|
||||
/* Find first property record of sob ( = spropfirst) */
|
||||
/* Find last property record of sob ( = sproplast) */
|
||||
/* Find last non-property record of sob ( = pob) */
|
||||
/* Find first property record of sob ( = spropfirst) */
|
||||
|
||||
spropfirst = sproplast = NULL;
|
||||
spropfirst = NULL;
|
||||
for (ob2 = sob; ob2->type > FIRSTPIN || ob2 == sob; ob2 = ob2->next)
|
||||
pob = ob2;
|
||||
if (ob2->type == PROPERTY) spropfirst = ob2;
|
||||
for (; ob2->type == PROPERTY; ob2 = ob2->next)
|
||||
sproplast = ob2;
|
||||
|
||||
if (spropfirst == NULL) {
|
||||
/* Create new property instance record if one doesn't exist */
|
||||
@@ -3372,8 +3369,9 @@ int CombineParallel(char *model, int file)
|
||||
nob->next = pob->next;
|
||||
pob->next = nob;
|
||||
|
||||
/* Handle case of contiguous entries */
|
||||
if (lob == pob) lob = nob;
|
||||
spropfirst = sproplast = nob;
|
||||
spropfirst = nob;
|
||||
}
|
||||
if (propfirst == NULL) {
|
||||
/* Create new property instance record if one doesn't exist */
|
||||
@@ -3396,27 +3394,26 @@ int CombineParallel(char *model, int file)
|
||||
kv->type = PROP_ENDLIST;
|
||||
kv->value.ival = 0;
|
||||
|
||||
/* Append to sob's property list */
|
||||
nob->next = sproplast->next;
|
||||
sproplast->next = nob;
|
||||
if (lob == sproplast) lob = nob;
|
||||
/* Prepend to sob's property list */
|
||||
nob->next = pob->next;
|
||||
pob->next = nob;
|
||||
/* Handle case of contiguous entries */
|
||||
if (lob == pob) lob = nob;
|
||||
}
|
||||
|
||||
if (propfirst != NULL) {
|
||||
else {
|
||||
|
||||
// Series/Parallel logic:
|
||||
// If propfirst has _tag in properties,
|
||||
// then add an "open" tag at propfirst
|
||||
add_prop_tag(propfirst, '(');
|
||||
// If spropfirst has _tag in properties,
|
||||
// then add an "open" tag at spropfirst
|
||||
add_prop_tag(spropfirst, '(');
|
||||
|
||||
// if spropfirst has _tag in properties then add an "open" tag
|
||||
// to spropfirst and a "close" tag to propfirst
|
||||
if (add_prop_tag(spropfirst, '(')) add_prop_tag(propfirst, ')');
|
||||
// if propfirst has _tag in properties then add an "open" tag
|
||||
// to propfirst and a "close" tag to spropfirst
|
||||
if (add_prop_tag(propfirst, '(')) add_prop_tag(spropfirst, ')');
|
||||
|
||||
/* Append ob's property list to sob */
|
||||
proplast->next = sproplast->next;
|
||||
sproplast->next = propfirst;
|
||||
if (lob == sproplast) lob = proplast;
|
||||
/* Prepend ob's property list to sob */
|
||||
proplast->next = pob->next;
|
||||
pob->next = propfirst;
|
||||
}
|
||||
|
||||
/* Link up around object to be removed */
|
||||
@@ -3429,7 +3426,6 @@ int CombineParallel(char *model, int file)
|
||||
obr = nob;
|
||||
}
|
||||
dcnt++;
|
||||
|
||||
}
|
||||
FREE((char *)pstr);
|
||||
}
|
||||
@@ -3441,7 +3437,8 @@ int CombineParallel(char *model, int file)
|
||||
}
|
||||
HashKill(&devdict);
|
||||
if (dcnt > 0) {
|
||||
Fprintf(stdout, "Class %s: Merged %d devices.\n", model, dcnt);
|
||||
Fprintf(stdout, "Class %s (%d): Merged %d parallel devices.\n",
|
||||
model, file, dcnt);
|
||||
}
|
||||
FREE(nodecount);
|
||||
return dcnt;
|
||||
@@ -3738,6 +3735,10 @@ int CombineSeries(char *model, int file)
|
||||
}
|
||||
}
|
||||
FREE(instlist);
|
||||
if (scnt > 0) {
|
||||
Fprintf(stdout, "Class %s (%d): Merged %d series devices.\n",
|
||||
model, file, scnt);
|
||||
}
|
||||
return scnt;
|
||||
}
|
||||
|
||||
|
||||
+45
-2
@@ -22,6 +22,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#ifdef IBMPC
|
||||
#include <alloc.h>
|
||||
#endif
|
||||
@@ -31,13 +32,13 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#endif
|
||||
|
||||
#include "netgen.h"
|
||||
#include "hash.h"
|
||||
#include "objlist.h"
|
||||
#include "regexp.h"
|
||||
#include "dbug.h"
|
||||
#include "print.h"
|
||||
#include "netfile.h"
|
||||
#include "netcmp.h"
|
||||
#include "hash.h"
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
extern Tcl_Interp *netgeninterp;
|
||||
@@ -288,7 +289,7 @@ static struct hashdict cell_dict;
|
||||
|
||||
void InitCellHashTable(void)
|
||||
{
|
||||
hashfunc = hash;
|
||||
hashfunc = hashcase;
|
||||
matchfunc = NULL;
|
||||
matchintfunc = matchfile;
|
||||
InitializeHashTable(&cell_dict, CELLHASHSIZE);
|
||||
@@ -439,10 +440,25 @@ void RemoveShorted(char *class, int file)
|
||||
RecurseCellFileHashTable(removeshorted, file);
|
||||
}
|
||||
|
||||
/* Structure used to keep track of nodes needing checking */
|
||||
|
||||
struct linkednode {
|
||||
int node;
|
||||
struct linkednode *next;
|
||||
};
|
||||
|
||||
/* Remove instances of a deleted class from the database. */
|
||||
/* NOTE: This treats deleted classes as not existing, so it */
|
||||
/* needs to take care of disconnected ports in the same manner */
|
||||
/* as flattenInstancesOf() in disconnecting the port of a */
|
||||
/* parent cell if it connected to nothing other than the */
|
||||
/* deleted instance. */
|
||||
|
||||
int deleteclass(struct hashlist *p, int file)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
struct objlist *ob, *lob, *nob;
|
||||
struct linkednode *checknodes = NULL, *newlnode, *chknode;
|
||||
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
|
||||
@@ -455,6 +471,12 @@ int deleteclass(struct hashlist *p, int file)
|
||||
if ((*matchfunc)(ob->model.class, OldCell->name)) {
|
||||
HashDelete(ob->instance.name, &(ptr->instdict));
|
||||
while (1) {
|
||||
if (ob->type >= FIRSTPIN) {
|
||||
newlnode = (struct linkednode *)MALLOC(sizeof(struct linkednode));
|
||||
newlnode->node = ob->node;
|
||||
newlnode->next = checknodes;
|
||||
checknodes = newlnode;
|
||||
}
|
||||
FreeObjectAndHash(ob, ptr);
|
||||
ob = nob;
|
||||
if (ob == NULL) break;
|
||||
@@ -476,6 +498,27 @@ int deleteclass(struct hashlist *p, int file)
|
||||
ob = nob;
|
||||
}
|
||||
}
|
||||
|
||||
while (checknodes != NULL) {
|
||||
struct objlist *portnode = NULL;
|
||||
|
||||
chknode = checknodes;
|
||||
checknodes = checknodes->next;
|
||||
|
||||
for (ob = ptr->cell; ob != NULL; ob = ob->next) {
|
||||
if ((ob->type != PORT) && (portnode == NULL))
|
||||
break;
|
||||
else if ((ob->type == PORT) && (ob->node == chknode->node))
|
||||
portnode = ob;
|
||||
else if ((ob->type >= FIRSTPIN) && (ob->node == chknode->node))
|
||||
break;
|
||||
}
|
||||
if ((ob == NULL) && (portnode != NULL)) {
|
||||
/* Port became disconnected when child was deleted */
|
||||
portnode->node = -1;
|
||||
}
|
||||
FREE(chknode);
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove all instances of class "class" from the database */
|
||||
|
||||
@@ -312,6 +312,19 @@ extern void GarbageCollect(void);
|
||||
extern void InitGarbageCollection(void);
|
||||
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
|
||||
void PrintMemoryStats(void);
|
||||
#endif
|
||||
|
||||
+8
-5
@@ -805,11 +805,14 @@ void DescribeInstance(char *name, int file)
|
||||
/* All black-box modules and placeholders by definition have all */
|
||||
/* disconnected pins, so don't report those. */
|
||||
|
||||
if (!(tp->flags & CELL_PLACEHOLDER) && (tp->class != CLASS_MODULE))
|
||||
{
|
||||
if (disconnectednodes == 0) Fprintf(stderr, "\n");
|
||||
if ((!(tp->flags & CELL_PLACEHOLDER)) && (tp->class != CLASS_MODULE)) {
|
||||
// if (disconnectednodes == 0) Fprintf(stderr, "\n");
|
||||
disconnectednodes++;
|
||||
Fprintf(stderr, "Cell %s disconnected node: %s\n", tp->name, ob->name);
|
||||
/* Don't report on ports marked "port_match_error", which is just confusing. */
|
||||
if (strcmp(ob->name, "port_match_error")) {
|
||||
Fprintf(stderr, "Cell %s (%d) disconnected node: %s\n",
|
||||
tp->name, tp->file, ob->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1033,7 +1036,7 @@ void Query(void)
|
||||
break;
|
||||
case 'v':
|
||||
promptstring("Write Verilog: circuit name: ", repstr);
|
||||
VerilogModule(repstr, filenum, "");
|
||||
VerilogTop(repstr, filenum, "");
|
||||
break;
|
||||
case 'E':
|
||||
promptstring("Write ESACAP: circuit name: ", repstr);
|
||||
|
||||
+26
-10
@@ -26,6 +26,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#endif
|
||||
|
||||
#include <stdlib.h> /* for calloc(), free(), getenv() */
|
||||
#include <ctype.h> /* for toupper(), isascii() */
|
||||
#ifndef IBMPC
|
||||
#include <sys/types.h> /* for getpwnam() tilde expansion */
|
||||
#include <pwd.h>
|
||||
@@ -40,6 +41,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "objlist.h"
|
||||
#include "netfile.h"
|
||||
#include "print.h"
|
||||
#include "query.h"
|
||||
#include "objlist.h"
|
||||
|
||||
// Global storage for parameters from .PARAM
|
||||
struct hashdict spiceparams;
|
||||
@@ -937,7 +940,7 @@ skip_ends:
|
||||
goto baddevice;
|
||||
}
|
||||
|
||||
snprintf(instname, 255, "%s%s", model, inst);
|
||||
snprintf(instname, 255, "%s:%s", model, inst);
|
||||
Cell(instname, model, collector, base, emitter);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
@@ -1010,7 +1013,7 @@ skip_ends:
|
||||
goto baddevice;
|
||||
}
|
||||
|
||||
snprintf(instname, 255, "%s%s", model, inst);
|
||||
snprintf(instname, 255, "%s:%s", model, inst);
|
||||
Cell(instname, model, drain, gate, source, bulk);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
@@ -1101,7 +1104,7 @@ skip_ends:
|
||||
usemodel = 1;
|
||||
}
|
||||
|
||||
snprintf(instname, 255, "%s%s", model, inst);
|
||||
snprintf(instname, 255, "%s:%s", model, inst);
|
||||
if (usemodel)
|
||||
Cell(instname, model, ctop, cbot);
|
||||
else
|
||||
@@ -1194,7 +1197,7 @@ skip_ends:
|
||||
else
|
||||
strcpy(model, "r"); /* Use default resistor model */
|
||||
|
||||
snprintf(instname, 255, "%s%s", model, inst);
|
||||
snprintf(instname, 255, "%s:%s", model, inst);
|
||||
if (usemodel)
|
||||
Cell(instname, model, rtop, rbot);
|
||||
else
|
||||
@@ -1252,7 +1255,7 @@ skip_ends:
|
||||
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a diode.\n");
|
||||
goto baddevice;
|
||||
}
|
||||
snprintf(instname, 255, "%s%s", model, inst);
|
||||
snprintf(instname, 255, "%s:%s", model, inst);
|
||||
Cell(instname, model, anode, cathode);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
@@ -1331,7 +1334,7 @@ skip_ends:
|
||||
else
|
||||
strcpy(model, "t"); /* Use default xline model */
|
||||
|
||||
snprintf(instname, 255, "%s%s", model, inst);
|
||||
snprintf(instname, 255, "%s:%s", model, inst);
|
||||
|
||||
if (usemodel)
|
||||
Cell(instname, model, node1, node2, node3, node4);
|
||||
@@ -1414,7 +1417,7 @@ skip_ends:
|
||||
else
|
||||
strcpy(model, "l"); /* Use default inductor model */
|
||||
|
||||
snprintf(instname, 255, "%s%s", model, inst);
|
||||
snprintf(instname, 255, "%s:%s", model, inst);
|
||||
if (usemodel)
|
||||
Cell(instname, model, end_a, end_b);
|
||||
else
|
||||
@@ -1446,7 +1449,20 @@ skip_ends:
|
||||
if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
|
||||
if (LookupObject(neg, CurrentCell) == NULL) Node(neg);
|
||||
|
||||
/* Any device properties? */
|
||||
/* Get voltage value (if present); save as property "value" */
|
||||
|
||||
if (nexttok != NULL) {
|
||||
if (matchnocase(nexttok, "DC")) {
|
||||
SpiceTokNoNewline();
|
||||
}
|
||||
}
|
||||
if (nexttok != NULL) {
|
||||
if (StringIsValueOrExpression(nexttok)) {
|
||||
AddProperty(&kvlist, "value", nexttok);
|
||||
}
|
||||
}
|
||||
|
||||
/* Any other device properties? */
|
||||
while (nexttok != NULL)
|
||||
{
|
||||
SpiceTokNoNewline();
|
||||
@@ -1474,7 +1490,7 @@ skip_ends:
|
||||
else if (CountPorts(model, filenum) != 2) {
|
||||
/* Modeled device: Make sure it has the right number of ports */
|
||||
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a "
|
||||
"voltage source.\n");
|
||||
"voltage source.\n", inst);
|
||||
goto baddevice;
|
||||
}
|
||||
Cell(instname, model, pos, neg);
|
||||
@@ -1726,7 +1742,7 @@ skip_ends:
|
||||
/* names. */
|
||||
|
||||
if (strncmp(instancename, scan->name, strlen(scan->name))) {
|
||||
snprintf(subcktname, 99, "%s%s", scan->name, instancename);
|
||||
snprintf(subcktname, 99, "%s:%s", scan->name, instancename);
|
||||
strcpy(instancename, subcktname);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#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 */
|
||||
+316
-172
@@ -52,14 +52,15 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#endif
|
||||
|
||||
#include "netgen.h"
|
||||
#include "hash.h"
|
||||
#include "objlist.h"
|
||||
#include "netfile.h"
|
||||
#include "print.h"
|
||||
#include "hash.h"
|
||||
|
||||
// See netfile.c for explanation of delimiters. 'X'
|
||||
// separates single-character delimiters from two-character delimiters.
|
||||
#define VLOG_DELIMITERS "X///**/#((**)X,;:(){}[]="
|
||||
#define VLOG_EQUATION_DELIMITERS "X///**/#((**)X,;:(){}[]=+-*/"
|
||||
#define VLOG_PIN_NAME_DELIMITERS "X///**/(**)X()"
|
||||
#define VLOG_PIN_CHECK_DELIMITERS "X///**/(**)X,;(){}"
|
||||
|
||||
@@ -71,6 +72,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
struct hashdict verilogparams;
|
||||
// Global storage for verilog definitions
|
||||
struct hashdict verilogdefs;
|
||||
// Record file pointer that is associated with the hash tables
|
||||
int hashfile = -1;
|
||||
|
||||
// Global storage for wire buses
|
||||
struct hashdict buses;
|
||||
@@ -127,6 +130,187 @@ char *strvchr(char *string, char c)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Linked list, much like tokstack in netgen.c, but much simpler. */
|
||||
/* contents are either a value, if oper = 0, or an operator. */
|
||||
|
||||
struct expr_stack {
|
||||
int value;
|
||||
char oper;
|
||||
struct expr_stack *next;
|
||||
struct expr_stack *last;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Evaluate an expression for an array bound. This is much like
|
||||
// ReduceOneExpression() in netgen.c, but only handles basic integer
|
||||
// arithmetic (+,-,*,/) and grouping by parentheses.
|
||||
//
|
||||
// Returns 1 if successful, 0 on error.
|
||||
// Evaluated result is placed in the integer pointed to by "valptr".
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
int EvalExpr(struct expr_stack **stackptr, int *valptr)
|
||||
{
|
||||
struct expr_stack *texp, *start, *tmp, *stack;
|
||||
int modified, value;
|
||||
|
||||
stack = *stackptr;
|
||||
|
||||
/* Most expressions are going to be just one number, so treat
|
||||
* that as a special case.
|
||||
*/
|
||||
if ((stack->oper == '\0') && (stack->last == NULL)) {
|
||||
*valptr = stack->value;
|
||||
FREE(stack);
|
||||
*stackptr = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Move to the end of the stack, which is the beginning of the
|
||||
* expression.
|
||||
*/
|
||||
for (start = stack; start->last; start = start->last);
|
||||
|
||||
/* Run passes until no more modifications can be made */
|
||||
modified = TRUE;
|
||||
|
||||
while (modified == TRUE) {
|
||||
modified = FALSE;
|
||||
|
||||
/* Find any + or - that is used as a sign of a value */
|
||||
|
||||
for (texp = start; texp; texp = texp->next) {
|
||||
if ((texp->oper == '+') || (texp->oper == '-') || (texp->oper == '*') ||
|
||||
(texp->oper == '/') || (texp->oper == '(')) {
|
||||
|
||||
if ((texp->next != NULL) && (texp->next->next != NULL) &&
|
||||
(texp->next->next->oper == '\0')) {
|
||||
|
||||
if (texp->next->oper == '+') {
|
||||
/* Remove the unnecessary sign */
|
||||
tmp = texp->next;
|
||||
texp->next = tmp->next;
|
||||
tmp->next->last = texp;
|
||||
FREE(tmp);
|
||||
modified = TRUE;
|
||||
}
|
||||
else if (texp->next->oper == '-') {
|
||||
/* Remove the sign and negate the value */
|
||||
tmp = texp->next;
|
||||
texp->next->next->value = -texp->next->next->value;
|
||||
texp->next = tmp->next;
|
||||
tmp->next->last = texp;
|
||||
FREE(tmp);
|
||||
modified = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reduce (a * b) and (a / b) */
|
||||
|
||||
for (texp = start; texp; texp = texp->next) {
|
||||
if ((texp->last != NULL) && (texp->next != NULL) && (texp->oper != '\0')) {
|
||||
if ((texp->last->oper == '\0') && (texp->next->oper == '\0')) {
|
||||
if (texp->oper == '*') {
|
||||
/* Multiply */
|
||||
texp->last->value *= texp->next->value;
|
||||
/* Remove two items from the stack */
|
||||
tmp = texp;
|
||||
texp = texp->last;
|
||||
texp->next = tmp->next->next;
|
||||
if (tmp->next->next) tmp->next->next->last = texp;
|
||||
FREE(tmp->next);
|
||||
FREE(tmp);
|
||||
modified = TRUE;
|
||||
}
|
||||
if (texp->oper == '/') {
|
||||
/* Divide */
|
||||
texp->last->value /= texp->next->value;
|
||||
/* Remove two items from the stack */
|
||||
tmp = texp;
|
||||
texp = texp->last;
|
||||
texp->next = tmp->next->next;
|
||||
if (tmp->next->next) tmp->next->next->last = texp;
|
||||
FREE(tmp->next);
|
||||
FREE(tmp);
|
||||
modified = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reduce (a + b) and (a - b) */
|
||||
|
||||
for (texp = start; texp; texp = texp->next) {
|
||||
if ((texp->last != NULL) && (texp->next != NULL) && (texp->oper != '\0')) {
|
||||
if ((texp->last->oper == '\0') && (texp->next->oper == '\0')) {
|
||||
if (texp->oper == '-') {
|
||||
/* Subtract */
|
||||
texp->last->value -= texp->next->value;
|
||||
/* Remove two items from the stack */
|
||||
tmp = texp;
|
||||
texp = texp->last;
|
||||
texp->next = tmp->next->next;
|
||||
if (tmp->next->next) tmp->next->next->last = texp;
|
||||
FREE(tmp->next);
|
||||
FREE(tmp);
|
||||
modified = TRUE;
|
||||
}
|
||||
if (texp->oper == '+') {
|
||||
/* Add */
|
||||
texp->last->value += texp->next->value;
|
||||
/* Remove two items from the stack */
|
||||
tmp = texp;
|
||||
texp = texp->last;
|
||||
texp->next = tmp->next->next;
|
||||
if (tmp->next->next) tmp->next->next->last = texp;
|
||||
FREE(tmp->next);
|
||||
FREE(tmp);
|
||||
modified = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reduce (a) */
|
||||
|
||||
for (texp = start; texp; texp = texp->next) {
|
||||
if ((texp->last != NULL) && (texp->next != NULL) && (texp->oper == '\0')) {
|
||||
if ((texp->last->oper == '(') && (texp->next->oper == ')')) {
|
||||
tmp = texp->last;
|
||||
texp->last->oper = '\0';
|
||||
texp->last->value = texp->value;
|
||||
texp->last->next = texp->next->next;
|
||||
if (texp->next->next) texp->next->next->last = texp->last;
|
||||
FREE(texp->next);
|
||||
FREE(texp);
|
||||
texp = tmp;
|
||||
modified = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If only one numerical item remains, then place it in valptr and return 1 */
|
||||
texp = start;
|
||||
if ((texp->oper == '\0') && (texp->next == NULL)) {
|
||||
*valptr = texp->value;
|
||||
FREE(texp);
|
||||
*stackptr = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Clean up the stack before returning error status */
|
||||
while (texp) {
|
||||
tmp = texp;
|
||||
texp = texp->next;
|
||||
FREE(tmp);
|
||||
}
|
||||
*stackptr = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Get bus indexes from the notation name[a:b]. If there is only "name"
|
||||
// then look up the name in the bus hash list and return the index bounds.
|
||||
@@ -138,147 +322,123 @@ char *strvchr(char *string, char c)
|
||||
|
||||
int GetBusTok(struct bus *wb)
|
||||
{
|
||||
int result, start, end;
|
||||
int result, start, end, value;
|
||||
char oper;
|
||||
struct property *kl = NULL;
|
||||
struct expr_stack *stack, *newexp;
|
||||
|
||||
if (wb == NULL) return 0;
|
||||
else {
|
||||
wb->start = -1;
|
||||
wb->end = -1;
|
||||
}
|
||||
|
||||
wb->start = -1;
|
||||
wb->end = -1;
|
||||
stack = NULL;
|
||||
|
||||
/* Parse a value for array bounds [a : b], including possible use */
|
||||
/* of parameters, definitions, and basic arithmetic. */
|
||||
|
||||
if (match(nexttok, "[")) {
|
||||
SkipTokComments(VLOG_DELIMITERS);
|
||||
|
||||
result = sscanf(nexttok, "%d", &start);
|
||||
if (result != 1) {
|
||||
char *aptr = NULL;
|
||||
char addin;
|
||||
|
||||
// Check for "+/-(n)" at end of a parameter name
|
||||
aptr = strrchr(nexttok, '+');
|
||||
if (aptr == NULL) aptr = strrchr(nexttok, '-');
|
||||
if (aptr != NULL) {
|
||||
addin = *aptr;
|
||||
*aptr = '\0';
|
||||
}
|
||||
|
||||
// Is name in the parameter list?
|
||||
kl = (struct property *)HashLookup(nexttok, &verilogparams);
|
||||
if (kl == NULL) {
|
||||
Printf("Array value %s is not a number or a parameter.\n",
|
||||
nexttok);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
if (kl->type == PROP_STRING) {
|
||||
result = sscanf(kl->pdefault.string, "%d", &start);
|
||||
if (result != 1) {
|
||||
Printf("Parameter %s has value %s that cannot be parsed"
|
||||
" as an integer.\n", nexttok, kl->pdefault.string);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (kl->type == PROP_INTEGER) {
|
||||
start = kl->pdefault.ival;
|
||||
}
|
||||
else if (kl->type == PROP_DOUBLE) {
|
||||
start = (int)kl->pdefault.dval;
|
||||
if ((double)start != kl->pdefault.dval) {
|
||||
Printf("Parameter %s has value %g that cannot be parsed"
|
||||
" as an integer.\n", nexttok, kl->pdefault.dval);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Printf("Parameter %s has unknown type; don't know how"
|
||||
" to parse.\n", nexttok);
|
||||
start = end = -1;
|
||||
oper = '\0';
|
||||
while (nexttok) {
|
||||
SkipTokComments(VLOG_EQUATION_DELIMITERS);
|
||||
if (match(nexttok, "]")) {
|
||||
result = 1;
|
||||
if (stack == NULL) {
|
||||
Printf("Empty array found.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (aptr != NULL) {
|
||||
int addval;
|
||||
*aptr = addin;
|
||||
if (sscanf(aptr + 1, "%d", &addval) != 1) {
|
||||
Printf("Unable to parse parameter increment '%s'\n", aptr);
|
||||
if (EvalExpr(&stack, &end) != 1) {
|
||||
Printf("Bad expression found in array.\n");
|
||||
return 1;
|
||||
}
|
||||
start += (addin == '+') ? addval : -addval;
|
||||
if (start == -1) start = end; // Single bit
|
||||
break;
|
||||
}
|
||||
}
|
||||
SkipTokComments(VLOG_DELIMITERS);
|
||||
if (match(nexttok, "]")) {
|
||||
result = 1;
|
||||
end = start; // Single bit
|
||||
}
|
||||
else if (!match(nexttok, ":")) {
|
||||
Printf("Badly formed array notation: Expected colon, found %s\n", nexttok);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
SkipTokComments(VLOG_DELIMITERS);
|
||||
|
||||
result = sscanf(nexttok, "%d", &end);
|
||||
if (result != 1) {
|
||||
char *aptr = NULL;
|
||||
char addin;
|
||||
|
||||
// Check for "+/-(n)" at end of a parameter name
|
||||
aptr = strrchr(nexttok, '+');
|
||||
if (aptr == NULL) aptr = strrchr(nexttok, '-');
|
||||
if (aptr != NULL) {
|
||||
addin = *aptr;
|
||||
*aptr = '\0';
|
||||
if (match(nexttok, ":")) {
|
||||
if (stack == NULL) {
|
||||
Printf("Empty array start found.\n");
|
||||
return 1;
|
||||
}
|
||||
if (EvalExpr(&stack, &start) != 1) {
|
||||
Printf("Bad expression found in array.\n");
|
||||
return 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (match(nexttok, "+") || match(nexttok, "-")
|
||||
|| match(nexttok, "*") || match(nexttok, "/")
|
||||
|| match(nexttok, "(") || match(nexttok, ")")) {
|
||||
newexp = (struct expr_stack *)MALLOC(sizeof(struct expr_stack));
|
||||
newexp->oper = *nexttok;
|
||||
newexp->value = 0;
|
||||
newexp->next = NULL;
|
||||
newexp->last = stack;
|
||||
if (stack) stack->next = newexp;
|
||||
stack = newexp;
|
||||
continue;
|
||||
}
|
||||
if ((result = sscanf(nexttok, "%d", &value)) != 1) {
|
||||
|
||||
// Is name in the parameter list?
|
||||
kl = (struct property *)HashLookup(nexttok, &verilogparams);
|
||||
kl = (struct property *)HashLookup(nexttok, &verilogparams);
|
||||
if (kl == NULL) {
|
||||
Printf("Array value %s is not a number or a parameter.\n",
|
||||
nexttok);
|
||||
return 1;
|
||||
nexttok);
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (kl->type == PROP_STRING) {
|
||||
result = sscanf(kl->pdefault.string, "%d", &end);
|
||||
result = sscanf(kl->pdefault.string, "%d", &value);
|
||||
if (result != 1) {
|
||||
Printf("Parameter %s has value %s that cannot be parsed"
|
||||
" as an integer.\n", nexttok,
|
||||
kl->pdefault.string);
|
||||
return 1;
|
||||
" as an integer.\n",
|
||||
nexttok, kl->pdefault.string);
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (kl->type == PROP_INTEGER) {
|
||||
end = kl->pdefault.ival;
|
||||
value = kl->pdefault.ival;
|
||||
}
|
||||
else if (kl->type == PROP_DOUBLE) {
|
||||
end = (int)kl->pdefault.dval;
|
||||
if ((double)end != kl->pdefault.dval) {
|
||||
Printf("Cannot parse second digit from parameter "
|
||||
"%s value %g\n", nexttok, kl->pdefault.dval);
|
||||
return 1;
|
||||
value = (int)kl->pdefault.dval;
|
||||
if ((double)value != kl->pdefault.dval) {
|
||||
Printf("Parameter %s has value %g that cannot be parsed"
|
||||
" as an integer.\n",
|
||||
nexttok, kl->pdefault.dval);
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Printf("Parameter %s has unknown type; don't know how"
|
||||
" to parse.\n", nexttok);
|
||||
return 1;
|
||||
Printf("Parameter %s has unknown type; don't know how"
|
||||
" to parse.\n", nexttok);
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (aptr != NULL) {
|
||||
int addval;
|
||||
*aptr = addin;
|
||||
if (sscanf(aptr + 1, "%d", &addval) != 1) {
|
||||
Printf("Unable to parse parameter increment '%s'\n", aptr);
|
||||
return 1;
|
||||
}
|
||||
end += (addin == '+') ? addval : -addval;
|
||||
}
|
||||
}
|
||||
|
||||
newexp = (struct expr_stack *)MALLOC(sizeof(struct expr_stack));
|
||||
newexp->oper = '\0';
|
||||
newexp->value = value;
|
||||
newexp->next = NULL;
|
||||
newexp->last = stack;
|
||||
if (stack) stack->next = newexp;
|
||||
stack = newexp;
|
||||
}
|
||||
|
||||
wb->start = start;
|
||||
wb->end = end;
|
||||
|
||||
/* In case of error, stack may need cleaning up */
|
||||
while (stack != NULL) {
|
||||
newexp = stack;
|
||||
stack = stack->last;
|
||||
FREE(newexp);
|
||||
}
|
||||
|
||||
while (!match(nexttok, "]")) {
|
||||
SkipTokComments(VLOG_DELIMITERS);
|
||||
if (nexttok == NULL) {
|
||||
@@ -1128,13 +1288,6 @@ skip_endmodule:
|
||||
kl->pdefault.ival = 1;
|
||||
kl->slop.ival = 0;
|
||||
}
|
||||
else if (nexttok[0] == '(') {
|
||||
/* For now, the netgen verilog parser doesn't handle `define f(X) ... */
|
||||
SkipNewLine(VLOG_DELIMITERS);
|
||||
FREE(kl->key);
|
||||
FREE(kl);
|
||||
kl = NULL;
|
||||
}
|
||||
else if (ConvertStringToInteger(nexttok, &ival) == 1) {
|
||||
/* Parameter parses as an integer */
|
||||
kl->type = PROP_INTEGER;
|
||||
@@ -1319,6 +1472,8 @@ skip_endmodule:
|
||||
rhs = LookupObject(assignname, CurrentCell);
|
||||
*aptr = '[';
|
||||
}
|
||||
else
|
||||
strcpy(assignroot, nexttok);
|
||||
}
|
||||
else {
|
||||
j = -1;
|
||||
@@ -1514,7 +1669,7 @@ nextinst:
|
||||
|
||||
// Read the pin list
|
||||
while (nexttok != NULL) {
|
||||
SkipTokComments(VLOG_DELIMITERS);
|
||||
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
|
||||
if (match(nexttok, ")")) break;
|
||||
else if (match(nexttok, ",")) continue;
|
||||
|
||||
@@ -1577,6 +1732,14 @@ nextinst:
|
||||
}
|
||||
new_port->net = wire_bundle;
|
||||
}
|
||||
else if (nexttok[0] == '~' || nexttok[0] == '!' || nexttok[0] == '-') {
|
||||
/* All of these imply that the signal is logically manipulated */
|
||||
/* in turn implying behavioral code. */
|
||||
Printf("Module '%s' is not structural verilog, "
|
||||
"making black-box.\n", model);
|
||||
SetClass(CLASS_MODULE);
|
||||
goto skip_endmodule;
|
||||
}
|
||||
else
|
||||
new_port->net = strsave(nexttok);
|
||||
|
||||
@@ -1770,54 +1933,6 @@ nextinst:
|
||||
scan->width = width;
|
||||
|
||||
result = GetBus(scan->net, &wb);
|
||||
if (result == -1) {
|
||||
/* CHECK: THIS CODE SHOULD BE DELETED, IT IS NOT THE ISSUE */
|
||||
/* Not bus notation, but check if signal was defined as a bus */
|
||||
wb.start = wb.end = -1;
|
||||
minnet = maxnet = -1;
|
||||
|
||||
/* Pins should be in index order start->end. Other nodes */
|
||||
/* should be in order start->end by node number. */
|
||||
|
||||
for (bobj = CurrentCell->cell; bobj; bobj = bobj->next) {
|
||||
if (bobj->type == PORT) {
|
||||
if ((bptr = strvchr(bobj->name, '[')) != NULL) {
|
||||
*bptr = '\0';
|
||||
if (!strcmp(bobj->name, scan->net)) {
|
||||
*bptr = '[';
|
||||
if (wb.start == -1)
|
||||
sscanf(bptr + 1, "%d", &wb.start);
|
||||
else
|
||||
sscanf(bptr + 1, "%d", &wb.end);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bobj->type == NODE) {
|
||||
if ((bptr = strvchr(bobj->name, '[')) != NULL) {
|
||||
*bptr = '\0';
|
||||
if (!strcmp(bobj->name, scan->net)) {
|
||||
if (sscanf(bptr + 1, "%d", &testidx) == 1) {
|
||||
if (minnet == -1) {
|
||||
minnet = maxnet = bobj->node;
|
||||
wb.start = wb.end = testidx;
|
||||
}
|
||||
else if (bobj->node < minnet) {
|
||||
minnet = bobj->node;
|
||||
wb.start = testidx;
|
||||
}
|
||||
else if (bobj->node > maxnet) {
|
||||
maxnet = bobj->node;
|
||||
wb.end = testidx;
|
||||
}
|
||||
}
|
||||
}
|
||||
*bptr = '[';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wb.start != -1) result = 0;
|
||||
}
|
||||
|
||||
if (result == 0) {
|
||||
int match = 0;
|
||||
int wblen, arraylen;
|
||||
@@ -1927,7 +2042,25 @@ nextinst:
|
||||
}
|
||||
}
|
||||
else if (portstart != portend) {
|
||||
Fprintf(stderr, "Error: Single net %s is connected to bus port %s\n",
|
||||
/* If the name starts with "_noconnect_", then it was an
|
||||
* auto-generated name that incorrectly assumed a single-bit
|
||||
* wide signal because it did not have a module prototype.
|
||||
* Rewrite the noconnect name as an array. This just means
|
||||
* that the verilog had an empty list "()" and the initial
|
||||
* assumption was wrong. If not all instances agree on the
|
||||
* size, then this will eventually generate an error.
|
||||
*/
|
||||
if (!strncmp(scan->net, "_noconnect_", 11) &&
|
||||
(strchr(scan->net, '\[') == NULL) && (width > 1)) {
|
||||
char *savenet = scan->net;
|
||||
char *newnet = MALLOC(strlen(scan->net) + 12);
|
||||
sprintf(newnet, "%s[%d:0]", scan->net, scan->width - 1);
|
||||
FREE(savenet);
|
||||
scan->net = newnet;
|
||||
continue; /* Re-process this entry */
|
||||
}
|
||||
else
|
||||
Fprintf(stderr, "Error: Single net %s is connected to bus port %s\n",
|
||||
scan->net, scan->name);
|
||||
}
|
||||
}
|
||||
@@ -2095,6 +2228,9 @@ nextinst:
|
||||
obptr->next = nobj;
|
||||
HashPtrInstall(nobj->name, nobj, &(CurrentCell->objdict));
|
||||
|
||||
/* Ensure that CurrentTail is correct */
|
||||
if (obptr == CurrentTail) CurrentTail = nobj;
|
||||
|
||||
if (LookupObject(scan->net, CurrentCell) == NULL)
|
||||
Node(scan->net);
|
||||
join(scan->net, nobj->name);
|
||||
@@ -2109,7 +2245,7 @@ nextinst:
|
||||
sobj = sobj->next) {
|
||||
if (sobj->type == FIRSTPIN) {
|
||||
if (match(sobj->model.class, obptr->model.class)) {
|
||||
while (sobj->next->type > FIRSTPIN)
|
||||
while (sobj->next && (sobj->next->type > FIRSTPIN))
|
||||
sobj = sobj->next;
|
||||
/* Stop when reaching the current instance */
|
||||
if (sobj->type == obptr->type + 1) break;
|
||||
@@ -2136,6 +2272,7 @@ nextinst:
|
||||
}
|
||||
}
|
||||
}
|
||||
obptr = obptr->next;
|
||||
}
|
||||
else {
|
||||
Fprintf(stderr, "Error: Instance %s has pin %s which is "
|
||||
@@ -2231,11 +2368,22 @@ char *ReadVerilogTop(char *fname, int *fnum, int blackbox)
|
||||
else {
|
||||
matchfunc = match;
|
||||
matchintfunc = matchfile;
|
||||
hashfunc = hash;
|
||||
hashfunc = hashcase;
|
||||
}
|
||||
|
||||
InitializeHashTable(&verilogparams, OBJHASHSIZE);
|
||||
InitializeHashTable(&verilogdefs, OBJHASHSIZE);
|
||||
if ((hashfile != -1) && (hashfile != *fnum)) {
|
||||
/* Started a new file, so remove all the parameters and definitions */
|
||||
RecurseHashTable(&verilogparams, freeprop);
|
||||
HashKill(&verilogparams);
|
||||
RecurseHashTable(&verilogdefs, freeprop);
|
||||
HashKill(&verilogdefs);
|
||||
hashfile = -1;
|
||||
}
|
||||
if (hashfile == -1) {
|
||||
InitializeHashTable(&verilogparams, OBJHASHSIZE);
|
||||
InitializeHashTable(&verilogdefs, OBJHASHSIZE);
|
||||
hashfile = *fnum;
|
||||
}
|
||||
definitions = &verilogdefs;
|
||||
|
||||
/* Add the pre-defined key "LVS" to verilogdefs */
|
||||
@@ -2255,10 +2403,6 @@ char *ReadVerilogTop(char *fname, int *fnum, int blackbox)
|
||||
// Cleanup
|
||||
while (CellStack != NULL) PopStack(&CellStack);
|
||||
|
||||
RecurseHashTable(&verilogparams, freeprop);
|
||||
HashKill(&verilogparams);
|
||||
RecurseHashTable(&verilogdefs, freeprop);
|
||||
HashKill(&verilogdefs);
|
||||
definitions = (struct hashdict *)NULL;
|
||||
|
||||
// Record the top level file.
|
||||
|
||||
+7
-9
@@ -23,6 +23,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef IBMPC
|
||||
#include <stdlib.h> /* for strtol on PC */
|
||||
@@ -33,6 +34,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "netfile.h"
|
||||
#include "hash.h"
|
||||
#include "print.h"
|
||||
#include "xilinx.h"
|
||||
#include "flatten.h"
|
||||
|
||||
#define XILINXHASHSIZE 99
|
||||
static long xilinxhashbase = 0xA00;
|
||||
@@ -132,10 +135,8 @@ char *xilinx_class(model)
|
||||
}
|
||||
return(model);
|
||||
}
|
||||
void
|
||||
Xilinx(cellname, filename)
|
||||
char *cellname;
|
||||
char *filename;
|
||||
|
||||
void Xilinx(char *cellname, char *filename)
|
||||
{
|
||||
char Path[500];
|
||||
char FileName[500];
|
||||
@@ -163,8 +164,7 @@ Xilinx(cellname, filename)
|
||||
CloseFile(FileName);
|
||||
}
|
||||
|
||||
xilinxCell(cell)
|
||||
char *cell;
|
||||
int xilinxCell(char *cell)
|
||||
{
|
||||
struct nlist *nl;
|
||||
struct objlist *ob;
|
||||
@@ -252,9 +252,7 @@ struct objlist *xilinx_gate(ob,nl)
|
||||
return(nob);
|
||||
}
|
||||
|
||||
xilinx_sym(nl,gob)
|
||||
struct nlist *nl;
|
||||
struct objlist *gob;
|
||||
void xilinx_sym(struct nlist *nl, struct objlist *gob)
|
||||
{
|
||||
struct objlist *ob;
|
||||
char *cp,*rindex();
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#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 */
|
||||
@@ -29,6 +29,7 @@ lvs_manager.py: lvs_manager.py.in
|
||||
$(DESTDIR)${INSTALL_PYDIR}/lvs_manager.py: lvs_manager.py
|
||||
${RM} $@
|
||||
${CP} lvs_manager.py $@
|
||||
chmod a+x $@
|
||||
|
||||
$(DESTDIR)${INSTALL_PYDIR}/treeviewsplit.py: treeviewsplit.py
|
||||
${RM} $@
|
||||
|
||||
+112
-84
@@ -62,16 +62,18 @@ proc netgen::convert_to_json {filename lvs_final} {
|
||||
puts $fjson " \["
|
||||
set cktval [lindex $value 0]
|
||||
foreach pin [lrange $cktval 0 end-1] {
|
||||
puts $fjson " \"$pin\","
|
||||
set pinstr [string map {"\\" "\\\\"} $pin]
|
||||
puts $fjson " \"$pinstr\","
|
||||
}
|
||||
set pin [lindex $cktval end]
|
||||
set pin [string map {"\\" "\\\\"} [lindex $cktval end]]
|
||||
puts $fjson " \"$pin\""
|
||||
puts $fjson " \], \["
|
||||
set cktval [lindex $value 1]
|
||||
foreach pin [lrange $cktval 0 end-1] {
|
||||
puts $fjson " \"$pin\","
|
||||
set pinstr [string map {"\\" "\\\\"} $pin]
|
||||
puts $fjson " \"$pinstr\","
|
||||
}
|
||||
set pin [lindex $cktval end]
|
||||
set pin [string map {"\\" "\\\\"} [lindex $cktval end]]
|
||||
puts $fjson " \"$pin\""
|
||||
puts $fjson " \]"
|
||||
if {$kidx == $nkeys} {
|
||||
@@ -393,7 +395,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
# If argument is a filename then read the list of cells from it;
|
||||
# otherwise, argument is the list of files itself in quotes or
|
||||
# braces.
|
||||
if {![catch {file exists $value}]} {
|
||||
if {[file exists $value]} {
|
||||
if {![catch {open $value r} fnf]} {
|
||||
while {[gets $fnf line] >= 0} {
|
||||
if {[lindex $line 0] != "#"} {
|
||||
@@ -532,14 +534,24 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
}
|
||||
set properr {}
|
||||
set matcherr {}
|
||||
set pinsgood 0
|
||||
set childMismatch 0 ;# 1 indicates black-box child subcircuit mismatch
|
||||
while {$endval != {}} {
|
||||
if {$dolist == 1} {
|
||||
netgen::run -list converge
|
||||
} else {
|
||||
netgen::run converge
|
||||
}
|
||||
netgen::log echo on
|
||||
set pinMismatch 0 ;# indicates pin mismatch in top cell
|
||||
set doCheckFlatten 0
|
||||
set doFlatten 0
|
||||
if {[netgen::print queue] == {}} {
|
||||
set doEquatePins 1 ;# run equate pins on top cell
|
||||
} else {
|
||||
set doEquatePins 0 ;# don't run equate pins unless unique match
|
||||
}
|
||||
set forceMatch 0 ;# for pin matching
|
||||
netgen::log echo off
|
||||
|
||||
if {[verify equivalent]} {
|
||||
# Resolve automorphisms by pin and property
|
||||
if {$dolist == 1} {
|
||||
@@ -548,93 +560,105 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
netgen::run resolve
|
||||
}
|
||||
set uresult [verify unique]
|
||||
# uresult: -3 : unique with property error
|
||||
# -2 : equivalent with port errors
|
||||
# -1 : black box
|
||||
# 0 : equivalent but not unique
|
||||
# 1 : unique
|
||||
if {$uresult == 0} {
|
||||
netgen::log echo on
|
||||
netgen::log put " Networks match locally but not globally.\n"
|
||||
netgen::log put " Probably connections are swapped.\n"
|
||||
netgen::log put " Check the end of logfile ${logfile} for implicated nodes.\n"
|
||||
netgen::log echo off
|
||||
if {$dolist == 1} {
|
||||
verify -list nodes
|
||||
} else {
|
||||
verify nodes
|
||||
}
|
||||
|
||||
# Flatten the non-matching subcircuit (but not the top-level cells)
|
||||
if {[netgen::print queue] != {}} {
|
||||
if {([lsearch $noflat [lindex $endval 0]] == -1) &&
|
||||
([lsearch $noflat [lindex $endval 1]] == -1)} {
|
||||
netgen::log put " Flattening non-matched subcircuits $endval"
|
||||
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||
netgen::flatten class "[lindex $endval 1] $fnum2"
|
||||
} else {
|
||||
netgen::log put " Continuing with black-boxed subcircuits $endval"
|
||||
lappend matcherr [lindex $endval 0]
|
||||
# Match pins
|
||||
netgen::log echo off
|
||||
if {$dolist == 1} {
|
||||
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
} else {
|
||||
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
}
|
||||
if {$result != 0} {
|
||||
equate classes "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"
|
||||
}
|
||||
set pinsgood $result
|
||||
netgen::log echo on
|
||||
}
|
||||
}
|
||||
set doCheckFlatten 1
|
||||
} else {
|
||||
# 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
|
||||
# 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
|
||||
}
|
||||
if {$uresult == 2} {lappend properr [lindex $endval 0]}
|
||||
} else {
|
||||
# Flatten the non-matching subcircuit (but not the top-level cells)
|
||||
if {[netgen::print queue] != {}} {
|
||||
if {([lsearch $noflat [lindex $endval 1]] == -1) &&
|
||||
([lsearch $noflat [lindex $endval 1]] == -1)} {
|
||||
netgen::log put " Flattening non-matched subcircuits $endval"
|
||||
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||
netgen::flatten class "[lindex $endval 1] $fnum2"
|
||||
# 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 put " Continuing with black-boxed subcircuits $endval"
|
||||
lappend matcherr [lindex $endval 0]
|
||||
netgen::log put " Continuing with black-boxed subcircuits $endval"
|
||||
lappend matcherr [lindex $endval 0]
|
||||
# Match pins
|
||||
netgen::log echo off
|
||||
if {$dolist == 1} {
|
||||
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
} else {
|
||||
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
}
|
||||
if {$result != 0} {
|
||||
equate classes "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"
|
||||
}
|
||||
set pinsgood $result
|
||||
netgen::log echo on
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
netgen::log echo off
|
||||
if {$doEquatePins} {
|
||||
# Match pins
|
||||
if {$dolist == 1} {
|
||||
if {$forceMatch} {
|
||||
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
} else {
|
||||
set result [equate -list pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
}
|
||||
} else {
|
||||
if {$forceMatch} {
|
||||
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
} else {
|
||||
set result [equate pins "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"]
|
||||
}
|
||||
}
|
||||
if {$result >= 0} {
|
||||
equate classes "$fnum1 [lindex $endval 0]" \
|
||||
"$fnum2 [lindex $endval 1]"
|
||||
}
|
||||
# Do not set pinMismatch for black boxes
|
||||
if {$result < 0} {
|
||||
if {$result == -1 && [netgen::print queue] != {} && $forceMatch != 1} {
|
||||
# flatten pin mismatch, but not empty cells (-2) or top cell or
|
||||
# cells prohibited from flattening.
|
||||
set doFlatten 1
|
||||
}
|
||||
} elseif {[netgen::print queue] == {} && $result == 0} {
|
||||
set pinMismatch 1
|
||||
}
|
||||
}
|
||||
if {$doFlatten} {
|
||||
netgen::log echo on
|
||||
netgen::log put " Flattening non-matched subcircuits $endval\n"
|
||||
netgen::log echo off
|
||||
netgen::flatten class "[lindex $endval 0] $fnum1"
|
||||
netgen::flatten class "[lindex $endval 1] $fnum2"
|
||||
}
|
||||
|
||||
if {$dolist == 1} {
|
||||
catch {lappend lvs_final $lvs_out}
|
||||
set lvs_out {}
|
||||
@@ -643,19 +667,23 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
set endval [netgen::compare hierarchical]
|
||||
}
|
||||
}
|
||||
netgen::log echo off
|
||||
puts stdout "Result: " nonewline
|
||||
netgen::log echo on
|
||||
if {$pinsgood == 0} {
|
||||
netgen::log put "The top level cell failed pin matching.\n"
|
||||
netgen::log put "\nFinal result: "
|
||||
if {$pinMismatch || $childMismatch} {
|
||||
if {$childMismatch} {
|
||||
netgen::log put "Subcell(s) failed matching.\n"
|
||||
}
|
||||
if {$pinMismatch} {
|
||||
netgen::log put "Top level cell failed pin matching.\n"
|
||||
}
|
||||
} else {
|
||||
verify only
|
||||
}
|
||||
if {$properr != {}} {
|
||||
netgen::log put "The following cells had property errors: $properr\n"
|
||||
netgen::log put "\nThe following cells had property errors:\n " [regsub -all { } $properr "\n "] "\n"
|
||||
}
|
||||
if {$matcherr != {}} {
|
||||
netgen::log put "The following subcells failed to match: $matcherr\n"
|
||||
netgen::log put "\nThe following subcells failed to match:\n " [regsub -all { } $matcherr "\n "] "\n"
|
||||
}
|
||||
if {$dolog} {
|
||||
netgen::log end
|
||||
|
||||
+121
-42
@@ -32,6 +32,9 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "print.h"
|
||||
#include "query.h" /* for ElementNodes() */
|
||||
#include "hash.h"
|
||||
#include "xilinx.h"
|
||||
#include "tech.h"
|
||||
#include "flatten.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
@@ -976,7 +979,7 @@ _netgen_writenet(ClientData clientData,
|
||||
SpiceCell(repstr, filenum, "");
|
||||
break;
|
||||
case VERILOG_IDX:
|
||||
VerilogModule(repstr, filenum, "");
|
||||
VerilogTop(repstr, filenum, "");
|
||||
break;
|
||||
case WOMBAT_IDX:
|
||||
Wombat(repstr,NULL);
|
||||
@@ -1053,6 +1056,12 @@ _netgen_flatten(ClientData clientData,
|
||||
FlattenInstancesOf(repstr, filenum);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv, "prohibit") || !strcmp(argv, "deny")) {
|
||||
tp = GetTopCell(filenum);
|
||||
Printf("Will not flatten instances of %s in file %s\n", repstr, tp->name);
|
||||
/* Mark cell as placeholder so it will not be flattened */
|
||||
tp->flags |= CELL_PLACEHOLDER;
|
||||
}
|
||||
else {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "class valid_cellname");
|
||||
return TCL_ERROR;
|
||||
@@ -1928,9 +1937,17 @@ _netgen_log(ClientData clientData,
|
||||
switch(index) {
|
||||
case START_IDX:
|
||||
LoggingFile = fopen(LogFileName, "w");
|
||||
if (!LoggingFile) {
|
||||
Tcl_SetResult(interp, "Could not open log file.", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
case RESUME_IDX:
|
||||
LoggingFile = fopen(LogFileName, "a");
|
||||
if (!LoggingFile) {
|
||||
Tcl_SetResult(interp, "Could not open log file.", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
case END_IDX:
|
||||
fclose(LoggingFile);
|
||||
@@ -1939,6 +1956,10 @@ _netgen_log(ClientData clientData,
|
||||
case RESET_IDX:
|
||||
fclose(LoggingFile);
|
||||
LoggingFile = fopen(LogFileName, "w");
|
||||
if (!LoggingFile) {
|
||||
Tcl_SetResult(interp, "Could not open log file.", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
case SUSPEND_IDX:
|
||||
fclose(LoggingFile);
|
||||
@@ -2066,6 +2087,7 @@ _netcmp_format(ClientData clientData,
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "[col1_width [col2_width]]");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
@@ -2091,8 +2113,9 @@ _netcmp_compare(ClientData clientData,
|
||||
int dohierarchy = FALSE;
|
||||
int assignonly = FALSE;
|
||||
int argstart = 1, qresult, llen, result;
|
||||
int hascontents1, hascontents2;
|
||||
struct Correspond *nextcomp;
|
||||
struct nlist *tp;
|
||||
struct nlist *tp1 = NULL, *tp2 = NULL;
|
||||
Tcl_Obj *flist = NULL;
|
||||
|
||||
if (objc > 1) {
|
||||
@@ -2135,24 +2158,24 @@ _netcmp_compare(ClientData clientData,
|
||||
}
|
||||
else if ((objc - argstart) == 2) {
|
||||
|
||||
result = CommonParseCell(interp, objv[argstart], &tp, &fnum1);
|
||||
result = CommonParseCell(interp, objv[argstart], &tp1, &fnum1);
|
||||
if (result != TCL_OK) return TCL_ERROR;
|
||||
else if (fnum1 == -1) {
|
||||
Tcl_SetResult(interp, "Cannot use wildcard with compare command.\n",
|
||||
NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
name1 = tp->name;
|
||||
name1 = tp1->name;
|
||||
argstart++;
|
||||
|
||||
result = CommonParseCell(interp, objv[argstart], &tp, &fnum2);
|
||||
result = CommonParseCell(interp, objv[argstart], &tp2, &fnum2);
|
||||
if (result != TCL_OK) return TCL_ERROR;
|
||||
else if (fnum2 == -1) {
|
||||
Tcl_SetResult(interp, "Cannot use wildcard with compare command.\n",
|
||||
NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
name2 = tp->name;
|
||||
name2 = tp2->name;
|
||||
|
||||
if (dohierarchy) {
|
||||
RemoveCompareQueue();
|
||||
@@ -2191,11 +2214,38 @@ _netcmp_compare(ClientData clientData,
|
||||
ConvertGlobals(name2, fnum2);
|
||||
}
|
||||
|
||||
CreateTwoLists(name1, fnum1, name2, fnum2, dolist);
|
||||
while (PrematchLists(name1, fnum1, name2, fnum2) > 0) {
|
||||
Fprintf(stdout, "Making another compare attempt.\n");
|
||||
CreateTwoLists(name1, fnum1, name2, fnum2, dolist);
|
||||
tp1 = LookupCellFile(name1, fnum1);
|
||||
tp2 = LookupCellFile(name2, fnum2);
|
||||
|
||||
hascontents1 = HasContents(tp1);
|
||||
hascontents2 = HasContents(tp2);
|
||||
|
||||
if (hascontents1 && !hascontents2 && (tp2->flags & CELL_PLACEHOLDER)) {
|
||||
Fprintf(stdout, "\nCircuit 2 cell %s is a black box; will not flatten "
|
||||
"Circuit 1\n", name2);
|
||||
}
|
||||
else if (hascontents2 && !hascontents1 && (tp1->flags & CELL_PLACEHOLDER)) {
|
||||
Fprintf(stdout, "\nCircuit 1 cell %s is a black box; will not flatten "
|
||||
"Circuit 2\n", name1);
|
||||
}
|
||||
else if (hascontents1 || hascontents2) {
|
||||
FlattenUnmatched(tp1, name1, 1, 0);
|
||||
FlattenUnmatched(tp2, name2, 1, 0);
|
||||
DescribeContents(name1, fnum1, name2, fnum2);
|
||||
|
||||
while (PrematchLists(name1, fnum1, name2, fnum2) > 0) {
|
||||
Fprintf(stdout, "Making another compare attempt.\n");
|
||||
Printf("Flattened mismatched instances and attempting compare again.\n");
|
||||
FlattenUnmatched(tp1, name1, 1, 0);
|
||||
FlattenUnmatched(tp2, name2, 1, 0);
|
||||
DescribeContents(name1, fnum1, name2, fnum2);
|
||||
}
|
||||
}
|
||||
else { /* Two empty subcircuits */
|
||||
Fprintf(stdout, "\nCircuit 1 cell %s and Circuit 2 cell %s are black"
|
||||
" boxes.\n", name1, name2);
|
||||
}
|
||||
CreateTwoLists(name1, fnum1, name2, fnum2, dolist);
|
||||
|
||||
// Return the names of the two cells being compared, if doing "compare
|
||||
// hierarchical". If "-list" was specified, then append the output
|
||||
@@ -2428,6 +2478,8 @@ _netcmp_run(ClientData clientData,
|
||||
else {
|
||||
enable_interrupt();
|
||||
while (!Iterate() && !InterruptPending);
|
||||
ExhaustiveSubdivision = 1;
|
||||
while (!Iterate() && !InterruptPending);
|
||||
if (dolist) {
|
||||
result = _netcmp_verify(clientData, interp, 2, objv - 1);
|
||||
}
|
||||
@@ -2446,40 +2498,40 @@ _netcmp_run(ClientData clientData,
|
||||
else {
|
||||
enable_interrupt();
|
||||
while (!Iterate() && !InterruptPending);
|
||||
ExhaustiveSubdivision = 1;
|
||||
while (!Iterate() && !InterruptPending);
|
||||
automorphisms = VerifyMatching();
|
||||
if (automorphisms == -1)
|
||||
Fprintf(stdout, "Netlists do not match.\n");
|
||||
else if (automorphisms == 0)
|
||||
Fprintf(stdout, "Netlists match uniquely.\n");
|
||||
else {
|
||||
if (automorphisms > 0) {
|
||||
// First try to resolve automorphisms uniquely using
|
||||
// property matching
|
||||
automorphisms = ResolveAutomorphsByProperty();
|
||||
if (automorphisms == 0)
|
||||
Fprintf(stdout, "Netlists match uniquely.\n");
|
||||
else if (automorphisms > 0) {
|
||||
if (automorphisms > 0) {
|
||||
// Next, attempt to resolve automorphisms uniquely by
|
||||
// using the pin names
|
||||
automorphisms = ResolveAutomorphsByPin();
|
||||
}
|
||||
|
||||
if (automorphisms == 0)
|
||||
Fprintf(stdout, "Netlists match uniquely.\n");
|
||||
else if (automorphisms > 0) {
|
||||
if (automorphisms > 0) {
|
||||
// Anything left is truly indistinguishable
|
||||
Fprintf(stdout, "Netlists match with %d symmetr%s.\n",
|
||||
automorphisms, (automorphisms == 1) ? "y" : "ies");
|
||||
|
||||
while ((automorphisms = ResolveAutomorphisms()) > 0);
|
||||
while (ResolveAutomorphisms() > 0);
|
||||
}
|
||||
if (automorphisms == -1)
|
||||
Fprintf(stdout, "Netlists do not match.\n");
|
||||
else
|
||||
Fprintf(stdout, "Circuits match correctly.\n");
|
||||
}
|
||||
if (PropertyErrorDetected) {
|
||||
Fprintf(stdout, "There were property errors.\n");
|
||||
PrintPropertyResults(dolist);
|
||||
|
||||
if (automorphisms == -1)
|
||||
Fprintf(stdout, "Netlists do not match.\n");
|
||||
else if (automorphisms == -2)
|
||||
Fprintf(stdout, "Netlists match uniquely with port errors.\n");
|
||||
else {
|
||||
if (automorphisms == 0)
|
||||
Fprintf(stdout, "Netlists match uniquely");
|
||||
else
|
||||
Fprintf(stdout, "Netlists match with %d symmetr%s",
|
||||
automorphisms, (automorphisms == 1) ? "y" : "ies");
|
||||
if (PropertyErrorDetected) {
|
||||
Fprintf(stdout, " with property errors.\n");
|
||||
PrintPropertyResults(dolist);
|
||||
}
|
||||
else
|
||||
Fprintf(stdout, ".\n");
|
||||
}
|
||||
disable_interrupt();
|
||||
}
|
||||
@@ -2497,8 +2549,14 @@ _netcmp_run(ClientData clientData,
|
||||
/* all, or no option. */
|
||||
/* Formerly: v */
|
||||
/* Results: */
|
||||
/* For only, equivalent, unique: Return 1 if */
|
||||
/* verified, zero if not. */
|
||||
/* For only, equivalent, unique: Return */
|
||||
/* 1: verified */
|
||||
/* 0: not verified */
|
||||
/* -1: no elements or nodes */
|
||||
/* -3: verified with property error */
|
||||
/* equiv option */
|
||||
/* -2: pin mismatch */
|
||||
/* */
|
||||
/* Side Effects: */
|
||||
/* For options elements, nodes, and all without */
|
||||
/* option -list: Write output to log file. */
|
||||
@@ -2592,13 +2650,21 @@ _netcmp_verify(ClientData clientData,
|
||||
else
|
||||
Fprintf(stdout, "Netlists do not match.\n");
|
||||
}
|
||||
else if (automorphisms == -2) {
|
||||
if (index == EQUIV_IDX)
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
|
||||
else if (index == UNIQUE_IDX)
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(-2));
|
||||
else if (index > 0)
|
||||
Fprintf(stdout, "Circuits match uniquely with port errors.\n");
|
||||
}
|
||||
else {
|
||||
if (automorphisms) {
|
||||
if (index == EQUIV_IDX)
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj((int)automorphisms));
|
||||
else if (index == UNIQUE_IDX)
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
|
||||
else
|
||||
else if (index > 0)
|
||||
Printf("Circuits match with %d symmetr%s.\n",
|
||||
automorphisms, (automorphisms == 1) ? "y" : "ies");
|
||||
}
|
||||
@@ -2607,11 +2673,13 @@ _netcmp_verify(ClientData clientData,
|
||||
if (PropertyErrorDetected == 0)
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
|
||||
else
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(2));
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(-3));
|
||||
}
|
||||
else {
|
||||
else if (index > 0) {
|
||||
Fprintf(stdout, "Circuits match uniquely.\n");
|
||||
if (PropertyErrorDetected != 0)
|
||||
if (PropertyErrorDetected == 0)
|
||||
Fprintf(stdout, ".\n");
|
||||
else
|
||||
Fprintf(stdout, "Property errors were found.\n");
|
||||
}
|
||||
}
|
||||
@@ -3023,18 +3091,22 @@ _netcmp_equate(ClientData clientData,
|
||||
(tp2->flags & CELL_PLACEHOLDER)) {
|
||||
if (tp1->flags & CELL_PLACEHOLDER) {
|
||||
Fprintf(stdout, "Warning: Equate pins: cell %s "
|
||||
"has no definition, treated as a black box.\n", name1);
|
||||
"is a placeholder, treated as a black box.\n", name1);
|
||||
}
|
||||
if (tp2->flags & CELL_PLACEHOLDER) {
|
||||
Fprintf(stdout, "Warning: Equate pins: cell %s "
|
||||
"has no definition, treated as a black box.\n", name2);
|
||||
"is a placeholder, treated as a black box.\n", name2);
|
||||
}
|
||||
// If a cell in either circuit is marked as a black box, then
|
||||
// the cells in both circuits should be marked as a black box.
|
||||
tp1->flags |= CELL_PLACEHOLDER;
|
||||
tp2->flags |= CELL_PLACEHOLDER;
|
||||
}
|
||||
else {
|
||||
else if (doforce != TRUE) {
|
||||
/* When doforce is TRUE, ElementClass has been set to NULL
|
||||
* even though circuits contain elements, so this message
|
||||
* is not correct.
|
||||
*/
|
||||
Fprintf(stdout, "Equate pins: cell %s and/or %s "
|
||||
"has no elements.\n", name1, name2);
|
||||
/* This is not necessarily an error, so go ahead and match pins. */
|
||||
@@ -3066,6 +3138,13 @@ _netcmp_equate(ClientData clientData,
|
||||
else if (result > 0) {
|
||||
Fprintf(stdout, "Cell pin lists are equivalent.\n");
|
||||
}
|
||||
else if (result == -1) {
|
||||
Fprintf(stdout, "Cell pin lists for %s and %s do not match.\n",
|
||||
name1, name2);
|
||||
}
|
||||
else if (result == -2) {
|
||||
Fprintf(stdout, "Attempt to match empty cell to non-empty cell.\n");
|
||||
}
|
||||
else {
|
||||
Fprintf(stdout, "Cell pin lists for %s and %s altered to match.\n",
|
||||
name1, name2);
|
||||
|
||||
Reference in New Issue
Block a user