mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-22 22:17:22 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac8956c32e | ||
|
|
202ea0431f | ||
|
|
94754dbc4e | ||
|
|
b87f0fd5db | ||
|
|
bf67d3c275 | ||
|
|
21e9207924 | ||
|
|
62feed812e | ||
|
|
8392721885 | ||
|
|
d1c2848e4b | ||
|
|
6b0bd4d97b | ||
|
|
79bab50a79 | ||
|
|
d69fbc23bb | ||
|
|
b83800d69b | ||
|
|
c7fa0324d9 | ||
|
|
93b9cf6577 | ||
|
|
eb27a18ae3 | ||
|
|
bf53d52970 | ||
|
|
1817f4dd6a | ||
|
|
4250525e19 | ||
|
|
a7e859fcde | ||
|
|
c1ed4ce49e | ||
|
|
6d23844483 | ||
|
|
cc84364263 | ||
|
|
00b906c109 | ||
|
|
ab327c5f82 | ||
|
|
25a0e12428 | ||
|
|
eabb898578 | ||
|
|
2cb3937ee3 | ||
|
|
ec0e097fcf | ||
|
|
9b0afa893d | ||
|
|
f59c9ebcb7 | ||
|
|
c0f7ebd625 | ||
|
|
ce097d5d76 | ||
|
|
619409556c | ||
|
|
b1374e2bc8 | ||
|
|
9e9288f746 | ||
|
|
cff954f36a | ||
|
|
c27d933adc | ||
|
|
bcbc736b51 | ||
|
|
615c55cbe2 | ||
|
|
f5f1240073 | ||
|
|
87d8759a69 | ||
|
|
02d7a1bd01 | ||
|
|
1efa054ac1 | ||
|
|
7878b3cfbc | ||
|
|
609d1de250 | ||
|
|
7f727e6674 | ||
|
|
47c3b34612 | ||
|
|
d111fa0a3b | ||
|
|
66317c9848 | ||
|
|
eeb3c0e5c6 | ||
|
|
490f9f7dbc | ||
|
|
178b172c06 | ||
|
|
40cf82c2cb | ||
|
|
1ac2b592fb |
+298
-7
@@ -31,6 +31,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "print.h"
|
||||
#include "hash.h"
|
||||
|
||||
static int invlambda = 100; /* Used in sim and prm files */
|
||||
|
||||
void extCell(char *name, int filenum)
|
||||
{
|
||||
struct nlist *tp, *tp2;
|
||||
@@ -450,7 +452,8 @@ void simCell(char *name, int filenum)
|
||||
struct nlist *tp, *tp2;
|
||||
struct objlist *ob, *ob2;
|
||||
char FileName[500], simclass;
|
||||
short i;
|
||||
char writeLine[1024], paramString[128];
|
||||
short i, p, mult;
|
||||
double l, w, v;
|
||||
|
||||
tp = LookupCellFile(name, filenum);
|
||||
@@ -478,9 +481,9 @@ void simCell(char *name, int filenum)
|
||||
}
|
||||
|
||||
/* print out header list */
|
||||
/* distance units are multiplied by 100 (distances are in um) */
|
||||
/* distance units are multiplied by invlambda */
|
||||
|
||||
FlushString("| units: 100 tech: scmos\n");
|
||||
FlushString("| units: %d tech: scmos\n", 100 * invlambda);
|
||||
|
||||
/* now run through cell's contents, print instances */
|
||||
for (ob = tp->cell; ob != NULL; ob = ob->next) {
|
||||
@@ -516,13 +519,17 @@ void simCell(char *name, int filenum)
|
||||
case CLASS_NPN:
|
||||
simclass = 'b';
|
||||
break;
|
||||
default:
|
||||
case CLASS_SUBCKT:
|
||||
case CLASS_MODULE:
|
||||
simclass = 'x';
|
||||
break;
|
||||
default:
|
||||
simclass = '|';
|
||||
break;
|
||||
}
|
||||
|
||||
if (simclass != 'x')
|
||||
FlushString("%c", simclass);
|
||||
FlushString("%c", simclass);
|
||||
|
||||
switch (tp2->class) {
|
||||
case CLASS_NMOS: case CLASS_NMOS4:
|
||||
@@ -590,6 +597,115 @@ void simCell(char *name, int filenum)
|
||||
FlushString(" %g\n", v);
|
||||
break;
|
||||
|
||||
case CLASS_MODULE:
|
||||
*writeLine = 'x';
|
||||
*(writeLine + 1) = '\0';
|
||||
mult = 1;
|
||||
|
||||
/* Important---Need to look up the cell definition; if
|
||||
* the first pin is "drain" then it is a FET, and pins
|
||||
* get swapped from D-G-S-B to G-S-D-B. Source and drain
|
||||
* are treated here as equivalent because the .sim format
|
||||
* has no concept of an asymmetric source and drain.
|
||||
*/
|
||||
ob2 = tp2->cell;
|
||||
if ((*matchfunc)(ob2->next->name, "gate"))
|
||||
{
|
||||
strcat(writeLine, " ");
|
||||
strcat(writeLine, NodeAlias(tp, ob->next));
|
||||
strcat(writeLine, " ");
|
||||
strcat(writeLine, NodeAlias(tp, ob));
|
||||
ob2 = ob->next->next;
|
||||
}
|
||||
else
|
||||
ob2 = ob;
|
||||
|
||||
while (ob2 != NULL) {
|
||||
strcat(writeLine, " ");
|
||||
strcat(writeLine, NodeAlias(tp, ob2));
|
||||
ob2 = ob2->next;
|
||||
if ((ob2 == NULL) || (ob2->type <= FIRSTPIN)) break;
|
||||
}
|
||||
|
||||
if (ob2 && ob2->type == PROPERTY) {
|
||||
struct valuelist *vl;
|
||||
/* Only known parameters are L, W, X, and Y */
|
||||
for (p = 0;; p++) {
|
||||
vl = (struct valuelist *)(&(ob2->instance.props[p]));
|
||||
if (vl->type == PROP_ENDLIST) {
|
||||
strcat(writeLine, " l=1");
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(vl->key, "L")) {
|
||||
v = vl->value.dval;
|
||||
sprintf(paramString, " l=%d", (int)(0.5 + (v * invlambda)));
|
||||
strcat(writeLine, paramString);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (p = 0;; p++) {
|
||||
vl = (struct valuelist *)(&(ob2->instance.props[p]));
|
||||
if (vl->type == PROP_ENDLIST) {
|
||||
strcat(writeLine, " w=1");
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(vl->key, "W")) {
|
||||
v = vl->value.dval;
|
||||
sprintf(paramString, " w=%d", (int)(0.5 + (v * invlambda)));
|
||||
strcat(writeLine, paramString);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (p = 0;; p++) {
|
||||
vl = (struct valuelist *)(&(ob2->instance.props[p]));
|
||||
if (vl->type == PROP_ENDLIST) {
|
||||
strcat(writeLine, " x=0");
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(vl->key, "X")) {
|
||||
i = vl->value.ival;
|
||||
sprintf(paramString, " x=%d", i);
|
||||
strcat(writeLine, paramString);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (p = 0;; p++) {
|
||||
vl = (struct valuelist *)(&(ob2->instance.props[p]));
|
||||
if (vl->type == PROP_ENDLIST) {
|
||||
strcat(writeLine, " y=0");
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(vl->key, "Y")) {
|
||||
i = vl->value.ival;
|
||||
sprintf(paramString, " y=%d", i);
|
||||
strcat(writeLine, paramString);
|
||||
}
|
||||
}
|
||||
for (p = 0;; p++) {
|
||||
vl = (struct valuelist *)(&(ob2->instance.props[p]));
|
||||
if (vl->type == PROP_ENDLIST) {
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(vl->key, "M")) {
|
||||
if (vl->type == PROP_INTEGER)
|
||||
mult = vl->value.ival;
|
||||
else
|
||||
mult = vl->value.dval;
|
||||
}
|
||||
}
|
||||
}
|
||||
strcat(writeLine, " ");
|
||||
strcat(writeLine, tp2->name);
|
||||
strcat(writeLine, "\n");
|
||||
|
||||
/* Multiple instances (M != 1) are written multiple times.
|
||||
* NF is ignored in favor of having a single device with
|
||||
* the total width.
|
||||
*/
|
||||
for (i = 0; i < mult; i++)
|
||||
FlushString(writeLine);
|
||||
break;
|
||||
|
||||
default:
|
||||
FlushString("| unhandled component %s\n", tp2->name);
|
||||
break;
|
||||
@@ -626,6 +742,181 @@ int StrIsInt(char *s)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Read a .prm format file. This is specifically to */
|
||||
/* get the "device" lines that indicate how a SPICE */
|
||||
/* subcircuit model or a .sim "x" record needs to be */
|
||||
/* translated into a specific component type like a */
|
||||
/* FET, diode, resistor, etc. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
char *ReadPrm(char *fname, int *fnum)
|
||||
{
|
||||
int filenum;
|
||||
struct keyvalue *kvlist = NULL;
|
||||
struct nlist *tp;
|
||||
|
||||
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
|
||||
char name[MAX_STR_LEN];
|
||||
|
||||
SetExtension(name, fname, PRM_EXTENSION);
|
||||
if (OpenParseFile(name, *fnum) < 0) {
|
||||
Printf("Error in prm file read: No file %s\n",name);
|
||||
*fnum = filenum;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure all .prm file reading is case INsensitive */
|
||||
/* This is because the only reason to read a PRM file */
|
||||
/* is to find all the subcircuit device types so that */
|
||||
/* a SPICE file can be read and a SIM file written. */
|
||||
|
||||
matchfunc = matchnocase;
|
||||
matchintfunc = matchfile;
|
||||
hashfunc = hashnocase;
|
||||
|
||||
CellDef(fname, filenum);
|
||||
|
||||
while (!EndParseFile()) {
|
||||
char devicename[MAX_STR_LEN];
|
||||
SkipTok(NULL);
|
||||
|
||||
if (EndParseFile()) break;
|
||||
if (nexttok[0] == ';') continue; /* Comment line */
|
||||
else if (nexttok[0] == '\0') continue; /* Blank line */
|
||||
else if (match(nexttok, "lambda")) {
|
||||
SkipTok(NULL);
|
||||
invlambda = (int)(0.5 + (1.0 / atof(nexttok)));
|
||||
SkipNewLine(NULL); /* skip any attributes */
|
||||
}
|
||||
else if (match(nexttok, "device")) {
|
||||
SkipTok(NULL);
|
||||
if (match(nexttok, "nfet")) {
|
||||
SkipTok(NULL);
|
||||
strcpy(devicename, nexttok);
|
||||
/* Create 4-terminal nfet subcircuit device record */
|
||||
if (LookupCellFile(devicename, filenum) == NULL) {
|
||||
CellDef(devicename, filenum);
|
||||
Port("drain");
|
||||
Port("gate");
|
||||
Port("source");
|
||||
Port("bulk");
|
||||
PropertyDouble(devicename, filenum, "l", 0.01, 0.0);
|
||||
PropertyDouble(devicename, filenum, "w", 0.01, 0.0);
|
||||
PropertyInteger(devicename, filenum, "nf", 0, 1);
|
||||
PropertyInteger(devicename, filenum, "m", 0, 1);
|
||||
SetClass(CLASS_MODULE);
|
||||
EndCell();
|
||||
ReopenCellDef(fname, filenum);
|
||||
}
|
||||
LinkProperties(devicename, kvlist);
|
||||
SkipNewLine(NULL); /* skip any attributes */
|
||||
}
|
||||
else if (match(nexttok, "pfet")) {
|
||||
SkipTok(NULL);
|
||||
strcpy(devicename, nexttok);
|
||||
/* Create 4-terminal pfet subcircuit device record */
|
||||
if (LookupCellFile(devicename, filenum) == NULL) {
|
||||
CellDef(devicename, filenum);
|
||||
Port("drain");
|
||||
Port("gate");
|
||||
Port("source");
|
||||
Port("well");
|
||||
PropertyDouble(devicename, filenum, "l", 0.01, 0.0);
|
||||
PropertyDouble(devicename, filenum, "w", 0.01, 0.0);
|
||||
PropertyInteger(devicename, filenum, "nf", 0, 1);
|
||||
PropertyInteger(devicename, filenum, "m", 0, 1);
|
||||
SetClass(CLASS_MODULE);
|
||||
EndCell();
|
||||
ReopenCellDef(fname, filenum);
|
||||
}
|
||||
LinkProperties(devicename, kvlist);
|
||||
SkipNewLine(NULL); /* skip various attributes */
|
||||
}
|
||||
else if (match(nexttok, "resistor")) {
|
||||
SkipTok(NULL);
|
||||
strcpy(devicename, nexttok);
|
||||
/* Resistor device has additional record for the value */
|
||||
/* (Need to do something with this. . . ?) */
|
||||
SkipTok(NULL);
|
||||
/* Create resistor subcircuit device record */
|
||||
if (LookupCellFile(devicename, filenum) == NULL) {
|
||||
CellDef(devicename, filenum);
|
||||
Port("end_a");
|
||||
Port("end_b");
|
||||
PropertyDouble(devicename, filenum, "value", 0.01, 0.0);
|
||||
PropertyDouble(devicename, filenum, "l", 0.01, 0.0);
|
||||
PropertyDouble(devicename, filenum, "w", 0.01, 0.0);
|
||||
PropertyInteger(devicename, filenum, "m", 0, 1);
|
||||
SetClass(CLASS_MODULE);
|
||||
EndCell();
|
||||
ReopenCellDef(fname, filenum);
|
||||
}
|
||||
LinkProperties(devicename, kvlist);
|
||||
SkipNewLine(NULL); /* skip various attributes */
|
||||
}
|
||||
else if (match(nexttok, "capacitor")) {
|
||||
SkipTok(NULL);
|
||||
strcpy(devicename, nexttok);
|
||||
/* Capacitor device has additional record for the value */
|
||||
/* (Need to do something with this. . . ?) */
|
||||
SkipTok(NULL);
|
||||
/* Create capacitor subcircuit device record */
|
||||
if (LookupCellFile(devicename, filenum) == NULL) {
|
||||
CellDef(devicename, filenum);
|
||||
Port("top");
|
||||
Port("bottom");
|
||||
PropertyDouble(devicename, filenum, "value", 0.01, 0.0);
|
||||
PropertyDouble(devicename, filenum, "l", 0.01, 0.0);
|
||||
PropertyDouble(devicename, filenum, "w", 0.01, 0.0);
|
||||
PropertyInteger(devicename, filenum, "m", 0, 1);
|
||||
SetClass(CLASS_MODULE);
|
||||
EndCell();
|
||||
ReopenCellDef(fname, filenum); /* Reopen */
|
||||
}
|
||||
LinkProperties(devicename, kvlist);
|
||||
SkipNewLine(NULL);
|
||||
}
|
||||
else if (match(nexttok, "diode")) {
|
||||
SkipTok(NULL);
|
||||
strcpy(devicename, nexttok);
|
||||
/* Create diode subcircuit device record */
|
||||
if (LookupCellFile(devicename, filenum) == NULL) {
|
||||
CellDef(devicename, filenum);
|
||||
Port("anode");
|
||||
Port("cathode");
|
||||
PropertyInteger(devicename, filenum, "m", 0, 1);
|
||||
SetClass(CLASS_MODULE);
|
||||
EndCell();
|
||||
ReopenCellDef(fname, filenum); /* Reopen */
|
||||
}
|
||||
LinkProperties(devicename, kvlist);
|
||||
SkipNewLine(NULL);
|
||||
}
|
||||
else {
|
||||
Printf("Unknown device type in .prm: '%s'\n", nexttok);
|
||||
InputParseError(stderr);
|
||||
SkipNewLine(NULL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Could spell out all the keywords used in .prm files */
|
||||
/* but probably not worth the effort. */
|
||||
SkipNewLine(NULL);
|
||||
}
|
||||
DeleteProperties(&kvlist);
|
||||
}
|
||||
EndCell();
|
||||
CloseParseFile();
|
||||
|
||||
tp = LookupCellFile(fname, filenum);
|
||||
if (tp) tp->flags |= CELL_TOP;
|
||||
|
||||
*fnum = filenum;
|
||||
return fname;
|
||||
}
|
||||
|
||||
/*-------------------------*/
|
||||
/* Read a .sim format file */
|
||||
/*-------------------------*/
|
||||
@@ -644,7 +935,7 @@ char *ReadSim(char *fname, int *fnum)
|
||||
|
||||
SetExtension(name, fname, SIM_EXTENSION);
|
||||
if (OpenParseFile(name, *fnum) < 0) {
|
||||
Printf("Error in ext file read: No file %s\n",name);
|
||||
Printf("Error in sim file read: No file %s\n",name);
|
||||
*fnum = filenum;
|
||||
return NULL;
|
||||
}
|
||||
@@ -847,7 +1138,7 @@ char *ReadSim(char *fname, int *fnum)
|
||||
}
|
||||
else if (match(nexttok, "r")) { /* 2-port resistors */
|
||||
if (IgnoreRC) {
|
||||
/* ignore all capacitances */
|
||||
/* ignore all resistances */
|
||||
SkipNewLine(NULL);
|
||||
}
|
||||
else {
|
||||
|
||||
+126
-20
@@ -136,17 +136,16 @@ void flattenCell(char *name, int file)
|
||||
ob2 = ob2->next;
|
||||
}
|
||||
|
||||
|
||||
/* delete all port elements from child */
|
||||
while (IsPort(ChildObjList)) {
|
||||
/* delete all ports at beginning of list */
|
||||
if (Debug) Printf("deleting leading port from child\n");
|
||||
tmp = ChildObjList->next;
|
||||
FreeObjectAndHash(ChildObjList, ChildCell);
|
||||
ChildObjList = tmp;
|
||||
if ((ChildObjList = tmp) == NULL) break;
|
||||
}
|
||||
tmp = ChildObjList;
|
||||
while (tmp->next != NULL) {
|
||||
while (tmp && (tmp->next != NULL)) {
|
||||
if (IsPort(tmp->next)) {
|
||||
ob2 = (tmp->next)->next;
|
||||
if (Debug) Printf("deleting a port from child\n");
|
||||
@@ -536,11 +535,10 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
|
||||
/* Do property inheritance */
|
||||
|
||||
/* NOTE: Need to do: Check properties for M > 1 and decrement
|
||||
* and repeat without moving CurrentProp
|
||||
*/
|
||||
|
||||
if (CurrentProp) {
|
||||
int i, mval;
|
||||
struct valuelist *kv;
|
||||
|
||||
for (ob2 = ChildStart; ob2 != NULL; ob2=ob2->next) {
|
||||
|
||||
/* If the parent cell has properties to declare, then */
|
||||
@@ -548,10 +546,49 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
/* spiceparams dictionary is active (during file */
|
||||
/* reading only). */
|
||||
|
||||
if (ob2->type == PROPERTY)
|
||||
if (ob2->type == PROPERTY) {
|
||||
ReduceExpressions(ob2, CurrentProp, ChildCell,
|
||||
(spiceparams.hashtab == NULL) ? 0 : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for property M. If it exists and is greater than */
|
||||
/* one, reduce it and repeat; i.e., generate multiple */
|
||||
/* child instances to match the M value. Probably this */
|
||||
/* could be done quicker by just creating a new property */
|
||||
/* M for a single child. */
|
||||
|
||||
mval = 0;
|
||||
for (i = 0; ; i++) {
|
||||
kv = &(CurrentProp->instance.props[i]);
|
||||
if (kv->type == PROP_ENDLIST) break;
|
||||
if ((*matchfunc)(kv->key, "M")) {
|
||||
if (kv->type == PROP_INTEGER) {
|
||||
mval = kv->value.ival;
|
||||
kv->value.ival = mval - 1;
|
||||
break;
|
||||
}
|
||||
else if (kv->type == PROP_DOUBLE) {
|
||||
mval = (int)kv->value.dval;
|
||||
kv->value.dval = (double)mval - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mval > 1) {
|
||||
/* Put the child cell at the start of ChildObjList */
|
||||
if (ChildEnd) {
|
||||
ChildEnd->next = ChildObjList;
|
||||
ChildObjList = ChildStart;
|
||||
|
||||
/* Continue without moving CurrentProp */
|
||||
/* Note that if ChildEnd is NULL then the child cell
|
||||
* is optimized out and there is no need to do it
|
||||
* M times.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Repeat for each property record, as each property represents a
|
||||
* unique instance that must be flattened individually.
|
||||
@@ -1177,7 +1214,6 @@ 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) {
|
||||
@@ -1188,16 +1224,16 @@ int UniquePins(char *name, int filenum)
|
||||
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.
|
||||
/* Note: Previously there was code here to move the shorted port
|
||||
* next to the pin it is shorted to. This causes the cell def pins
|
||||
* to become scrambled with respect to the pin order of its instances.
|
||||
* Removed the code 9/1/2023. But---Not sure if any code depends
|
||||
* on shorted pins being adjacent.
|
||||
*/
|
||||
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;
|
||||
/* When two pins are shorted, they are by definition permutable */
|
||||
PermuteSetup(ThisCell->name, ThisCell->file, ob->name,
|
||||
firstport[ob->node]->name);
|
||||
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
@@ -1218,7 +1254,6 @@ int UniquePins(char *name, int filenum)
|
||||
}
|
||||
}
|
||||
portcount++;
|
||||
lob = ob;
|
||||
}
|
||||
|
||||
if (needscleanup)
|
||||
@@ -1600,6 +1635,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
ECompList *list0X, *listX0;
|
||||
int hascontents1, hascontents2;
|
||||
int match, modified = 0;
|
||||
int not_top;
|
||||
|
||||
if (file1 == -1)
|
||||
tc1 = LookupCell(name1);
|
||||
@@ -1870,6 +1906,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
// Remove non-matching zero-value devices. This can
|
||||
// be done on a per-instance basis.
|
||||
|
||||
not_top = (PeekCompareQueueTop(NULL, NULL, NULL, NULL) == -1) ? FALSE : TRUE;
|
||||
|
||||
ecomp = (ECompare *)HashFirst(&compdict);
|
||||
while (ecomp != NULL) {
|
||||
if ((ecomp->num1 != ecomp->num2) && (ecomp->cell1 != NULL) &&
|
||||
@@ -1916,6 +1954,33 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do NOT remove shorting devices that */
|
||||
/* connect two ports. Otherwise the */
|
||||
/* port lists get screwed up. It is */
|
||||
/* better in that case to force the */
|
||||
/* cells to be declared mismatched. */
|
||||
/* This is ignored for a top-level cell */
|
||||
/* because it will just show up as a */
|
||||
/* port mismatch error as it should. */
|
||||
|
||||
if ((not_top == TRUE) &&
|
||||
(ecomp->cell1->class != CLASS_ISOURCE)) {
|
||||
int found1 = FALSE;
|
||||
int found2 = FALSE;
|
||||
for (ob2 = tc1->cell; ob2; ob2 = ob2->next) {
|
||||
if (!IsPort(ob2)) break;
|
||||
else if (ob2->node == node1)
|
||||
found1 = TRUE;
|
||||
else if (ob2->node == node2)
|
||||
found2 = TRUE;
|
||||
if (found1 && found2) {
|
||||
found = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found) break;
|
||||
}
|
||||
if (found) {
|
||||
@@ -1929,6 +1994,16 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
|
||||
if (ecomp->cell1->class != CLASS_ISOURCE) {
|
||||
/* merge node of endpoints */
|
||||
/* Prefer a port node over a non-port node */
|
||||
for (ob2 = tc1->cell; ob2; ob2 = ob2->next) {
|
||||
if (!IsPort(ob2)) break;
|
||||
else if (ob2->node == node1) break;
|
||||
else if (ob2->node == node2) {
|
||||
int ntemp = node1;
|
||||
node1 = node2;
|
||||
node2 = ntemp;
|
||||
}
|
||||
}
|
||||
for (ob2 = tc1->cell; ob2; ob2 = ob2->next) {
|
||||
if (ob2->node == node2)
|
||||
ob2->node = node1;
|
||||
@@ -2027,6 +2102,27 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* (See comments above about removing shorts */
|
||||
/* between two ports.) */
|
||||
|
||||
if ((not_top == TRUE) &&
|
||||
(ecomp->cell2->class != CLASS_ISOURCE)) {
|
||||
int found1 = FALSE;
|
||||
int found2 = FALSE;
|
||||
for (ob1 = tc2->cell; ob1; ob1 = ob1->next) {
|
||||
if (!IsPort(ob1)) break;
|
||||
else if (ob1->node == node1)
|
||||
found1 = TRUE;
|
||||
else if (ob1->node == node2)
|
||||
found2 = TRUE;
|
||||
if (found1 && found2) {
|
||||
found = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found) break;
|
||||
}
|
||||
if (found) {
|
||||
@@ -2037,6 +2133,16 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
|
||||
/* merge node of endpoints */
|
||||
if (ecomp->cell2->class != CLASS_ISOURCE) {
|
||||
/* Prefer a port node over a non-port node */
|
||||
for (ob1 = tc2->cell; ob1; ob1 = ob1->next) {
|
||||
if (!IsPort(ob1)) break;
|
||||
else if (ob1->node == node1) break;
|
||||
else if (ob1->node == node2) {
|
||||
int ntemp = node1;
|
||||
node1 = node2;
|
||||
node2 = ntemp;
|
||||
}
|
||||
}
|
||||
for (ob1 = tc2->cell; ob1; ob1 = ob1->next) {
|
||||
if (ob1->node == node2)
|
||||
ob1->node = node1;
|
||||
|
||||
+270
-58
@@ -3773,20 +3773,23 @@ int CreateCompareQueue(char *name1, int file1, char *name2, int file2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------*/
|
||||
/* Read the top of the compare queue, but do */
|
||||
/* not alter the stack. */
|
||||
/*----------------------------------------------*/
|
||||
/*----------------------------------------------------------------*/
|
||||
/* Read the top of the compare queue, but do not alter the stack. */
|
||||
/* Return -1 if there is no compare queue. This is a way to */
|
||||
/* check if the current cells being checked are the topmost in */
|
||||
/* the queue. Call with all NULL values for a quick check for a */
|
||||
/* top-level compare. */
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
int PeekCompareQueueTop(char **name1, int *file1, char **name2, int *file2)
|
||||
{
|
||||
if (CompareQueue == NULL)
|
||||
return -1;
|
||||
|
||||
*name1 = CompareQueue->class1;
|
||||
*file1 = CompareQueue->file1;
|
||||
*name2 = CompareQueue->class2;
|
||||
*file2 = CompareQueue->file2;
|
||||
if (name1) *name1 = CompareQueue->class1;
|
||||
if (file1) *file1 = CompareQueue->file1;
|
||||
if (name2) *name2 = CompareQueue->class2;
|
||||
if (file2) *file2 = CompareQueue->file2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4201,6 +4204,28 @@ static int compsort(const void *p1, const void *p2)
|
||||
return (s1->value > s2->value) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* compdsort() is like compsort() but uses the definition for */
|
||||
/* "slop" used for type double instead of type integer. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
static int compdsort(const void *p1, const void *p2)
|
||||
{
|
||||
propsort *s1, *s2;
|
||||
double smax, ddiff;
|
||||
|
||||
s1 = (propsort *)p1;
|
||||
s2 = (propsort *)p2;
|
||||
|
||||
smax = fmax(s1->slop, s2->slop);
|
||||
ddiff = fabs(s1->value - s2->value) /
|
||||
fabs(s1->value + s2->value);
|
||||
if (ddiff <= smax)
|
||||
return (s1->avalue > s2->avalue) ? 1 : 0;
|
||||
else
|
||||
return (s1->value > s2->value) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Sort properties of ob1 starting at property idx1 up to */
|
||||
/* property (idx1 + run). Use series critical property for */
|
||||
@@ -4218,7 +4243,8 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
struct valuelist *vl, *sl;
|
||||
int i, p, sval, merge_type;
|
||||
// double cval, slop;
|
||||
int has_crit;
|
||||
int (*sortfunc)() = compsort;
|
||||
int has_crit, is_float;
|
||||
char ca, co;
|
||||
double tval, tslop;
|
||||
double aval, pval, oval, aslop, pslop;
|
||||
@@ -4238,6 +4264,7 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
for (i = 0; i < run; i++) {
|
||||
has_crit = FALSE;
|
||||
merge_type = MERGE_NONE;
|
||||
is_float = FALSE;
|
||||
ca = co = (char)0;
|
||||
|
||||
for (p = 0;; p++) {
|
||||
@@ -4270,6 +4297,8 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
else {
|
||||
tval = vl->value.dval;
|
||||
tslop = kl->slop.dval;
|
||||
sortfunc = compdsort;
|
||||
is_float = TRUE;
|
||||
}
|
||||
|
||||
if (kl->merge & MERGE_S_CRIT) {
|
||||
@@ -4324,10 +4353,11 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
|
||||
obn = obp; /* Link from last property */
|
||||
|
||||
qsort(&proplist[0], run, sizeof(propsort), compsort);
|
||||
qsort(&proplist[0], run, sizeof(propsort), sortfunc);
|
||||
|
||||
// Re-sort list
|
||||
obp = ob1;
|
||||
for (i = 0; i < idx1; i++) obp = obp->next;
|
||||
for (i = 0; i < run; i++) {
|
||||
obp->next = proplist[i].ob;
|
||||
obp = obp->next;
|
||||
@@ -4413,6 +4443,7 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
propsort *proplist;
|
||||
struct property *kl;
|
||||
struct valuelist *vl;
|
||||
int (*sortfunc)() = compsort;
|
||||
int i, p, mval, merge_type;
|
||||
int has_crit;
|
||||
char ca, co;
|
||||
@@ -4473,6 +4504,7 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
else {
|
||||
tval = vl->value.dval;
|
||||
tslop = kl->slop.dval;
|
||||
sortfunc = compdsort;
|
||||
}
|
||||
|
||||
if (kl->merge & MERGE_P_CRIT) {
|
||||
@@ -4527,10 +4559,11 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
|
||||
obn = obp; /* Link from last property */
|
||||
|
||||
qsort(&proplist[0], run, sizeof(propsort), compsort);
|
||||
qsort(&proplist[0], run, sizeof(propsort), sortfunc);
|
||||
|
||||
// Re-sort list
|
||||
obp = ob1;
|
||||
for (i = 0; i < idx1; i++) obp = obp->next;
|
||||
for (i = 0; i < run; i++) {
|
||||
obp->next = proplist[i].ob;
|
||||
obp = obp->next;
|
||||
@@ -5026,21 +5059,30 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
switch(vl->type) {
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
dval = 2 * fabs(vl->value.dval - vl2->value.dval)
|
||||
if ((vl2->type == PROP_DOUBLE) || (vl2->type == PROP_VALUE)) {
|
||||
dval = 2 * fabs(vl->value.dval - vl2->value.dval)
|
||||
/ (vl->value.dval + vl2->value.dval);
|
||||
if (dval <= kl->slop.dval) pmatch++;
|
||||
if (dval <= kl->slop.dval) pmatch++;
|
||||
}
|
||||
break;
|
||||
case PROP_INTEGER:
|
||||
ival = abs(vl->value.ival - vl2->value.ival);
|
||||
if (ival <= kl->slop.ival) pmatch++;
|
||||
if (vl2->type == PROP_INTEGER) {
|
||||
ival = abs(vl->value.ival - vl2->value.ival);
|
||||
if (ival <= kl->slop.ival) pmatch++;
|
||||
}
|
||||
break;
|
||||
case PROP_STRING:
|
||||
if ((*matchfunc)(vl->value.string, vl2->value.string)) pmatch++;
|
||||
if (vl2->type == PROP_STRING) {
|
||||
if ((*matchfunc)(vl->value.string, vl2->value.string)) pmatch++;
|
||||
}
|
||||
break;
|
||||
|
||||
/* will not attempt to match expressions, but it could
|
||||
/* Will not attempt to match expressions, but it could
|
||||
* be done with some minor effort by matching each
|
||||
* stack token and comparing those that are strings.
|
||||
* Likewise, will not attempt to match properties
|
||||
* whose types are mismatched, but they could be
|
||||
* promoted here.
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -6110,7 +6152,9 @@ PropertyMatch(struct Element *E1, struct Element *E2,
|
||||
if (kl2 != NULL)
|
||||
break; // Property is required
|
||||
}
|
||||
else if (vl2->value.ival != 1)
|
||||
else if ((vl2->type == PROP_INTEGER) && (vl2->value.ival != 1))
|
||||
break; // Property M != 1 or S != 1 is a mismatch.
|
||||
else if ((vl2->type == PROP_DOUBLE) && (vl2->value.dval != 1))
|
||||
break; // Property M != 1 or S != 1 is a mismatch.
|
||||
}
|
||||
if (vl2->type != PROP_ENDLIST) {
|
||||
@@ -7168,7 +7212,7 @@ int reorderpins(struct hashlist *p, int file)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
struct nlist *tc2 = Circuit2;
|
||||
struct objlist *ob, *ob2, *firstpin;
|
||||
struct objlist *ob, *ob2, *firstpin, *oblast, *newob;
|
||||
int i, numports, *nodes, unordered;
|
||||
char **names;
|
||||
|
||||
@@ -7220,6 +7264,7 @@ int reorderpins(struct hashlist *p, int file)
|
||||
names[ob2->model.port] = ob->name;
|
||||
}
|
||||
|
||||
oblast = ob;
|
||||
ob = ob->next;
|
||||
ob2 = ob2->next;
|
||||
if (i < numports - 1) {
|
||||
@@ -7227,7 +7272,34 @@ int reorderpins(struct hashlist *p, int file)
|
||||
Fprintf(stderr, "Instance of %s has only "
|
||||
"%d of %d ports\n",
|
||||
tc2->name, i + 1, numports);
|
||||
break;
|
||||
if (ptr->flags & CELL_VERILOG) {
|
||||
/* If parent cell is verilog, and the cells
|
||||
* have been matched, then the instance can
|
||||
* be assumed to be using an implicit pin.
|
||||
*/
|
||||
Fprintf(stderr, "Assuming implicit verilog pin \"%s\".\n",
|
||||
ob2->name);
|
||||
newob = (struct objlist *)CALLOC(1,
|
||||
sizeof(struct objlist));
|
||||
newob->name = (char *)MALLOC(strlen(oblast->instance.name)
|
||||
+ strlen(ob2->name) + 2);
|
||||
sprintf(newob->name, "%s/%s",
|
||||
oblast->instance.name, ob2->name);
|
||||
newob->type = oblast->type + 1;
|
||||
newob->model.class = strsave(oblast->model.class);
|
||||
newob->instance.name = strsave(oblast->instance.name);
|
||||
newob->flags = 0;
|
||||
ptr->nodename_cache_maxnodenum++;
|
||||
newob->node = ptr->nodename_cache_maxnodenum;
|
||||
newob->next = ob;
|
||||
oblast->next = newob; /* Splice into object list */
|
||||
/* Fill in the missing entries */
|
||||
nodes[ob2->model.port] = newob->node;
|
||||
names[ob2->model.port] = newob->name;
|
||||
ob = newob;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if (ob2 == NULL || ob2->type != PORT) {
|
||||
Fprintf(stderr, "Instance of %s has "
|
||||
@@ -7428,6 +7500,9 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
int result = 1, haspins = 0, notempty = 0;
|
||||
int hasproxy1 = 0, hasproxy2 = 0;
|
||||
int needclean1 = 0, needclean2 = 0;
|
||||
int nomatch = 0;
|
||||
int filenum = -1;
|
||||
int *correspond;
|
||||
char *ostr;
|
||||
#ifdef TCL_NETGEN
|
||||
Tcl_Obj *mlist, *plist1, *plist2;
|
||||
@@ -7519,72 +7594,79 @@ 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++) {
|
||||
nomatch = FALSE;
|
||||
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", ob1->name);
|
||||
if ((*matchfunc)(ob1->name, ob2->name))
|
||||
}
|
||||
if ((*matchfunc)(ob1->name, ob2->name)) {
|
||||
if (Debug == 0)
|
||||
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;
|
||||
}
|
||||
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;
|
||||
if (Debug == 0)
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ob3 = NULL;
|
||||
break; /* All pins w/the same node should be together */
|
||||
}
|
||||
}
|
||||
if (ob3 == NULL) {
|
||||
}
|
||||
}
|
||||
if (ob3 == NULL) {
|
||||
if (Debug == 0) {
|
||||
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;
|
||||
}
|
||||
nomatch = TRUE;
|
||||
/* Pins with different names are on different nets,
|
||||
* so this should trigger an error return code.
|
||||
*/
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (Debug == 0) {
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
}
|
||||
else if (nomatch) {
|
||||
Fprintf(stderr, "No matching pin in cell %s for "
|
||||
"cell %s pin %s\n",
|
||||
tc2->name, tc1->name, ob1->name);
|
||||
}
|
||||
else {
|
||||
Fprintf(stdout, "Circuit %s port %d \"%s\""
|
||||
" = cell %s port %d \"%s\"\n",
|
||||
tc1->name, i, obn->name,
|
||||
tc2->name, j, obp->name);
|
||||
tc1->name, i, ob1->name,
|
||||
tc2->name, j, ob2->name);
|
||||
}
|
||||
#ifdef TCL_NETGEN
|
||||
if (dolist) {
|
||||
Tcl_ListObjAppendElement(netgeninterp, plist1,
|
||||
Tcl_NewStringObj(obn->name, -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, plist2,
|
||||
Tcl_NewStringObj(obp->name, -1));
|
||||
Tcl_NewStringObj(ob1->name, -1));
|
||||
if (nomatch)
|
||||
Tcl_ListObjAppendElement(netgeninterp, plist2,
|
||||
Tcl_NewStringObj("(no matching pin)", -1));
|
||||
else
|
||||
Tcl_ListObjAppendElement(netgeninterp, plist2,
|
||||
Tcl_NewStringObj(ob2->name, -1));
|
||||
}
|
||||
#endif
|
||||
ob2->model.port = i; /* save order */
|
||||
*(cover + i) = (char)1;
|
||||
|
||||
/* 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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ob2 == NULL) {
|
||||
@@ -7681,6 +7763,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
/* legal SPICE. */
|
||||
|
||||
ob1 = tc1->cell;
|
||||
|
||||
correspond = (int *)CALLOC((tc1->nodename_cache_maxnodenum + 1), sizeof(int));
|
||||
|
||||
for (i = 0; i < numorig; i++) {
|
||||
bangptr1 = strrchr(ob1->name, '!');
|
||||
@@ -7723,7 +7807,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
(tc2->flags & CELL_PLACEHOLDER)) ||
|
||||
(NodeClasses == NULL))) {
|
||||
|
||||
ob2->model.port = i; /* save order */
|
||||
ob2->model.port = i; /* save order */
|
||||
*(cover + i) = (char)1;
|
||||
|
||||
if (Debug == 0) {
|
||||
@@ -7752,6 +7836,129 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (bangptr2) *bangptr2 = '!';
|
||||
break;
|
||||
}
|
||||
else if ((ob1->node != -1) && (ob2->node != -1)) {
|
||||
/* Check for the case of ports on both sides being shorted
|
||||
* together. That means that the nodes on both sides connect
|
||||
* only to ports, that they connect to the same number of ports,
|
||||
* and that each port pair has a matching name.
|
||||
*/
|
||||
int onlyports = 1;
|
||||
struct objlist *oba, *obb;
|
||||
for (oba = tc1->cell; oba != NULL; oba = oba->next) {
|
||||
if ((oba->node == ob1->node) && (oba->type != PORT)) {
|
||||
onlyports = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (onlyports) {
|
||||
for (obb = tc2->cell; obb != NULL; obb = obb->next) {
|
||||
if ((obb->node == ob2->node) && (obb->type != PORT)) {
|
||||
onlyports = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (onlyports) {
|
||||
if ((correspond[ob1->node] == 0) || (correspond[ob1->node] == ob2->node)) {
|
||||
|
||||
correspond[ob1->node] = ob2->node; /* remember corresponding node */
|
||||
ob2->model.port = i; /* save order */
|
||||
*(cover + i) = (char)1;
|
||||
|
||||
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", ob1->name);
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
}
|
||||
else {
|
||||
Fprintf(stdout, "Circuit %s port %d \"%s\""
|
||||
" = cell %s port %d \"%s\"\n",
|
||||
tc1->name, i, ob1->name,
|
||||
tc2->name, j, ob2->name);
|
||||
}
|
||||
#ifdef TCL_NETGEN
|
||||
if (dolist) {
|
||||
Tcl_ListObjAppendElement(netgeninterp, plist1,
|
||||
Tcl_NewStringObj(ob1->name, -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, plist2,
|
||||
Tcl_NewStringObj(ob2->name, -1));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (bangptr2) *bangptr2 = '!';
|
||||
break;
|
||||
}
|
||||
else {
|
||||
struct Permutation *permute1, *permute2;
|
||||
struct objlist *ob1a = NULL, *ob2a = NULL;
|
||||
|
||||
/* Check the permutation list. If any permutable pin
|
||||
* matches, and both nodes equal the nodes of their
|
||||
* pin permutations, then the pins also match.
|
||||
*/
|
||||
for (permute1 = tc1->permutes; permute1; permute1 = permute1->next) {
|
||||
if ((*matchfunc)(ob1->name, permute1->pin1)) {
|
||||
ob1a = LookupObject(permute1->pin1, tc1);
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(ob1->name, permute1->pin2)) {
|
||||
ob1a = LookupObject(permute1->pin2, tc1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (permute2 = tc2->permutes; permute2; permute2 = permute2->next) {
|
||||
if ((*matchfunc)(ob2->name, permute2->pin1)) {
|
||||
ob2a = LookupObject(permute2->pin1, tc2);
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(ob2->name, permute2->pin2)) {
|
||||
ob2a = LookupObject(permute2->pin2, tc2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ob1a && ob2a) {
|
||||
if ((ob1->node == ob1a->node) && (ob2->node == ob2a->node)) {
|
||||
/* This should be enough to prove equivalency */
|
||||
if ((correspond[ob1->node] == 0) || (correspond[ob1->node] == ob2->node)) {
|
||||
|
||||
correspond[ob1->node] = ob2->node; /* remember corresponding node */
|
||||
ob2->model.port = i; /* save order */
|
||||
*(cover + i) = (char)1;
|
||||
|
||||
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", ob1->name);
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
}
|
||||
else {
|
||||
Fprintf(stdout, "Circuit %s port %d \"%s\""
|
||||
" = cell %s port %d \"%s\"\n",
|
||||
tc1->name, i, ob1->name,
|
||||
tc2->name, j, ob2->name);
|
||||
}
|
||||
#ifdef TCL_NETGEN
|
||||
if (dolist) {
|
||||
Tcl_ListObjAppendElement(netgeninterp, plist1,
|
||||
Tcl_NewStringObj(ob1->name, -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, plist2,
|
||||
Tcl_NewStringObj(ob2->name, -1));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (bangptr2) *bangptr2 = '!';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bangptr2) *bangptr2 = '!';
|
||||
j++;
|
||||
@@ -7760,6 +7967,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
ob1 = ob1->next;
|
||||
if (bangptr1) *bangptr1 = '!';
|
||||
}
|
||||
FREE(correspond);
|
||||
|
||||
/* Find the end of the pin list in tc1, for adding proxy pins */
|
||||
|
||||
@@ -8025,7 +8233,11 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
|
||||
/* Reorder pins in Circuit2 instances to match Circuit1 */
|
||||
|
||||
RecurseCellFileHashTable(reorderpins, Circuit2->file);
|
||||
if (Circuit2 != NULL)
|
||||
filenum = Circuit2->file;
|
||||
else
|
||||
filenum = tc2->file;
|
||||
RecurseCellFileHashTable(reorderpins, filenum);
|
||||
|
||||
/* Reorder pins in Circuit2 cell to match Circuit1 */
|
||||
/* Unlike the instance records, the structures are swapped, */
|
||||
|
||||
+49
-14
@@ -183,7 +183,6 @@ void CloseFile(char *filename)
|
||||
fclose(outfile);
|
||||
}
|
||||
|
||||
|
||||
/* STUFF TO READ INPUT FILES */
|
||||
|
||||
static char *line = NULL; /* actual line read in */
|
||||
@@ -207,6 +206,21 @@ struct hashdict *definitions = (struct hashdict *)NULL;
|
||||
|
||||
#define WHITESPACE_DELIMITER " \t\n\r"
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Seek and Tell on infile stream, for use with handling generate */
|
||||
/* loops in verilog. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void SeekFile(long offset)
|
||||
{
|
||||
fseek(infile, offset, SEEK_SET);
|
||||
}
|
||||
|
||||
long TellFile()
|
||||
{
|
||||
return ftell(infile);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* TrimQuoted() --- */
|
||||
/* Remove spaces from inside single- or double-quoted strings. */
|
||||
@@ -573,6 +587,12 @@ void SkipTokNoNewline(char *delimiter)
|
||||
/* */
|
||||
/* Modified 3/30/2015 to include the condition where a comment line is */
|
||||
/* in the middle of a series of continuation lines. */
|
||||
/* */
|
||||
/* Modified 1/3/2024 to avoid skipping two lines if a line has only the */
|
||||
/* comment character '*' followed by a newline. It seems that '\n' is */
|
||||
/* being ignored in WHITESPACE_DELIMITER, but it's easier to write the */
|
||||
/* code to find the exception rather than track down the problem in */
|
||||
/* GetNextLine(). */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void SpiceTokNoNewline(void)
|
||||
@@ -584,8 +604,14 @@ void SpiceTokNoNewline(void)
|
||||
while (nexttok == NULL) {
|
||||
contline = getc(infile);
|
||||
if (contline == '*') {
|
||||
GetNextLine(WHITESPACE_DELIMITER);
|
||||
SkipNewLine(NULL);
|
||||
char testline = ' ';
|
||||
while ((testline == ' ') || (testline == '\t'))
|
||||
testline = getc(infile);
|
||||
if (testline != '\n') {
|
||||
ungetc(testline, infile);
|
||||
GetNextLine(WHITESPACE_DELIMITER);
|
||||
SkipNewLine(NULL);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (contline != '+') {
|
||||
@@ -597,7 +623,8 @@ void SpiceTokNoNewline(void)
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Skip to the next token, ignoring any C-style comments. */
|
||||
/* Skip to the next token, ignoring any C-style comments and verilog */
|
||||
/* "(* ... *)"-style comments. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void SkipTokComments(char *delimiter)
|
||||
@@ -613,6 +640,11 @@ void SkipTokComments(char *delimiter)
|
||||
SkipTok(delimiter);
|
||||
if (nexttok) SkipTok(delimiter);
|
||||
}
|
||||
else if (match(nexttok, "(*")) {
|
||||
while (nexttok && !match(nexttok, "*)"))
|
||||
SkipTok(delimiter);
|
||||
if (nexttok) SkipTok(delimiter);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
@@ -717,7 +749,7 @@ char *strdtok(char *pstring, char *delim1, char *delim2)
|
||||
if (*s == '\\') {
|
||||
s++;
|
||||
while (*s != '\0') {
|
||||
if ((*s == ' ') || (*s == '\\')) {
|
||||
if ((*s == ' ') || ((*s == '\\') && (*(s + 1) == '\0'))) {
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
@@ -866,7 +898,7 @@ char *ReadNetlist(char *fname, int *fnum)
|
||||
};
|
||||
|
||||
#ifdef mips
|
||||
struct filetype formats[7];
|
||||
struct filetype formats[8];
|
||||
|
||||
formats[0].extension = NTK_EXTENSION;
|
||||
formats[0].proc = ReadNtk;
|
||||
@@ -874,14 +906,16 @@ char *ReadNetlist(char *fname, int *fnum)
|
||||
formats[1].proc = ReadExtHier;
|
||||
formats[2].extension = SIM_EXTENSION;
|
||||
formats[2].proc = ReadSim;
|
||||
formats[3].extension = SPICE_EXTENSION;
|
||||
formats[3].proc = ReadSpice;
|
||||
formats[4].extension = NETGEN_EXTENSION;
|
||||
formats[4].proc = ReadNetgenFile;
|
||||
formats[5].extension = VERILOG_EXTENSION;
|
||||
formats[5].proc = ReadVerilogFile;
|
||||
formats[6].extension = NULL;
|
||||
formats[6].proc = NULL;
|
||||
formats[3].extension = PRM_EXTENSION;
|
||||
formats[3].proc = ReadPrm;
|
||||
formats[4].extension = SPICE_EXTENSION;
|
||||
formats[4].proc = ReadSpice;
|
||||
formats[5].extension = NETGEN_EXTENSION;
|
||||
formats[5].proc = ReadNetgenFile;
|
||||
formats[6].extension = VERILOG_EXTENSION;
|
||||
formats[6].proc = ReadVerilogFile;
|
||||
formats[7].extension = NULL;
|
||||
formats[7].proc = NULL;
|
||||
|
||||
#else /* not mips (i.e. compiler with reasonable initializers) */
|
||||
|
||||
@@ -890,6 +924,7 @@ char *ReadNetlist(char *fname, int *fnum)
|
||||
{NTK_EXTENSION, ReadNtk},
|
||||
{EXT_EXTENSION, ReadExtHier},
|
||||
{SIM_EXTENSION, ReadSim},
|
||||
{PRM_EXTENSION, ReadPrm},
|
||||
{SPICE_EXTENSION, ReadSpice},
|
||||
{SPICE_EXT2, ReadSpice},
|
||||
{SPICE_EXT3, ReadSpice},
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define WOMBAT_EXTENSION ".wom"
|
||||
#define EXT_EXTENSION ".ext"
|
||||
#define SIM_EXTENSION ".sim"
|
||||
#define PRM_EXTENSION ".prm"
|
||||
#define SPICE_EXTENSION ".spice"
|
||||
#define SPICE_EXT2 ".spc"
|
||||
#define SPICE_EXT3 ".sp"
|
||||
@@ -47,5 +48,7 @@ extern void InputParseError(FILE *f);
|
||||
extern int OpenParseFile(char *name, int fnum);
|
||||
extern int EndParseFile(void);
|
||||
extern int CloseParseFile(void);
|
||||
extern void SeekFile(long offset); /* handles verilog 'for' loops */
|
||||
extern long TellFile(); /* handles verilog 'for' loops */
|
||||
|
||||
#endif /* _NETFILE_H */
|
||||
|
||||
+6
-2
@@ -300,7 +300,9 @@ int ReduceOneExpression(struct valuelist *kv, struct objlist *parprops,
|
||||
tstr = sstr - 1;
|
||||
numlast = 1;
|
||||
}
|
||||
break;
|
||||
/* But might not be. . . */
|
||||
if ((dval != 0) || (sstr > estr))
|
||||
break;
|
||||
}
|
||||
/* Not a number, so must be arithmetic */
|
||||
*tstr = '\0';
|
||||
@@ -320,7 +322,9 @@ int ReduceOneExpression(struct valuelist *kv, struct objlist *parprops,
|
||||
tstr = sstr - 1;
|
||||
numlast = 1;
|
||||
}
|
||||
break;
|
||||
/* But might not be. . . */
|
||||
if ((dval != 0) || (sstr > estr))
|
||||
break;
|
||||
}
|
||||
/* Not a number, so must be arithmetic */
|
||||
*tstr = '\0';
|
||||
|
||||
@@ -191,6 +191,7 @@ extern char *ReadNtk (char *fname, int *fnum);
|
||||
extern char *ReadExtHier(char *fname, int *fnum);
|
||||
extern char *ReadExtFlat(char *fname, int *fnum);
|
||||
extern char *ReadSim(char *fname, int *fnum);
|
||||
extern char *ReadPrm(char *fname, int *fnum);
|
||||
extern char *ReadSpice(char *fname, int *fnum);
|
||||
extern char *ReadSpiceLib(char *fname, int *fnum);
|
||||
extern char *ReadNetgenFile (char *fname, int *fnum);
|
||||
|
||||
+75
-6
@@ -43,6 +43,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "print.h"
|
||||
#include "query.h"
|
||||
#include "objlist.h"
|
||||
#include "netcmp.h"
|
||||
|
||||
// Global storage for parameters from .PARAM
|
||||
struct hashdict spiceparams;
|
||||
@@ -519,7 +520,7 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
char *eqptr, devtype, in_subckt;
|
||||
struct keyvalue *kvlist = NULL;
|
||||
char inst[MAX_STR_LEN], model[MAX_STR_LEN], instname[MAX_STR_LEN];
|
||||
struct nlist *tp;
|
||||
struct nlist *tp, *tpsave;
|
||||
struct objlist *parent, *sobj, *nobj, *lobj, *pobj;
|
||||
|
||||
inst[MAX_STR_LEN-1] = '\0';
|
||||
@@ -557,6 +558,7 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
||||
tp = LookupCellFile(nexttok, filenum);
|
||||
tpsave = NULL;
|
||||
|
||||
/* Check for name conflict with duplicate cell names */
|
||||
/* This may mean that the cell was used before it was */
|
||||
@@ -595,11 +597,46 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
tp = LookupCellFile(nexttok, filenum);
|
||||
}
|
||||
else if (tp != NULL) { /* Make a new definition for an empty cell */
|
||||
FreePorts(nexttok);
|
||||
CellDelete(nexttok, filenum); /* This removes any PLACEHOLDER flag */
|
||||
CellDef(model, filenum);
|
||||
tp = LookupCellFile(model, filenum);
|
||||
update = 1; /* Will need to update existing instances */
|
||||
/* Handle issue with SPICE read after verilog, where a placeholder
|
||||
* was created from the verilog. (1) If the pin names are "1", "2",
|
||||
* "3", then this is a SPICE placeholder, and just remove the CellDef
|
||||
* and re-create it. Otherwise, create new cell "_PLACEHOLDER_".
|
||||
* (2) After encountering .ends, run MatchPins between the two cells.
|
||||
* (3) delete the original cell and rename the new cell.
|
||||
*/
|
||||
int i = 1;
|
||||
char pname[10];
|
||||
for (pobj = tp->cell; pobj && pobj->type == PORT; pobj = pobj->next) {
|
||||
sprintf(pname, "%d", i);
|
||||
if (!matchnocase(pobj->name, pname)) break;
|
||||
i++;
|
||||
}
|
||||
if ((pobj == NULL) || (pobj->type != PORT)) {
|
||||
/* This is a SPICE placeholder created because the cell was instanced
|
||||
* before it was defined. However, the pins can be assumed to be in
|
||||
* the correct order, and pin reordering does not need to be done.
|
||||
*/
|
||||
FreePorts(nexttok);
|
||||
CellDelete(nexttok, filenum); /* This removes any PLACEHOLDER flag */
|
||||
CellDef(model, filenum);
|
||||
tp = LookupCellFile(model, filenum);
|
||||
update = 1; /* Will need to update existing instances */
|
||||
}
|
||||
else {
|
||||
/* This is (probably) a verilog placeholder created because the
|
||||
* verilog was read before the (SPICE) definitions. The verilog
|
||||
* netlist should have named the pins of the parent cell. However,
|
||||
* there is no guarantee the order of pins is correct. The MatchPins()
|
||||
* routine from netcmp.c can be used here to match the cell against
|
||||
* the placeholder, and reorder the pins in all instances to match.
|
||||
* Note that we cannot just reorder the SPICE pins to match the
|
||||
* verilog order, because there may be other SPICE netlists which
|
||||
* instance the cell with the correct SPICE port order.
|
||||
*/
|
||||
tpsave = tp;
|
||||
CellDef("_PLACEHOLDER_", filenum);
|
||||
tp = LookupCellFile("_PLACEHOLDER_", filenum);
|
||||
}
|
||||
}
|
||||
else if (tp == NULL) { /* Completely new cell, no name conflict */
|
||||
CellDef(model, filenum);
|
||||
@@ -691,6 +728,38 @@ skip_ends:
|
||||
if (*CellStackPtr) PopStack(CellStackPtr);
|
||||
if (*CellStackPtr) ReopenCellDef((*CellStackPtr)->cellname, filenum);
|
||||
SkipNewLine(NULL);
|
||||
|
||||
if (tpsave != NULL) {
|
||||
struct nlist *tpplace;
|
||||
char *savename;
|
||||
|
||||
/* Handle a placeholder from a verilog file that has been replaced
|
||||
* by a netlist with pins in a different order. The pins need to
|
||||
* be matched, corrected in the original cell and all instances,
|
||||
* and the new cell deleted.
|
||||
*/
|
||||
|
||||
Printf("Verilog placeholder %s replaced by SPICE definition\n",
|
||||
tpsave->name);
|
||||
tpplace = LookupCellFile("_PLACEHOLDER_", filenum);
|
||||
/* MatchPins is part of netcmp and normally Circuit2 is the
|
||||
* circuit being matched, so set Circuit2 to the original
|
||||
* verilog black-box cell, and MatchPins() will force its
|
||||
* pins to be rearranged to match the SPICE definition just
|
||||
* read.
|
||||
*/
|
||||
Circuit2 = tpsave;
|
||||
MatchPins(tpplace, tpsave, 0);
|
||||
savename = strsave(tpsave->name);
|
||||
/* Now the original verilog black-box cell can be removed */
|
||||
FreePorts(savename);
|
||||
CellDelete(savename, filenum);
|
||||
/* And _PLACEHOLDER_ is renamed to the original name of the cell. */
|
||||
CellRehash("_PLACEHOLDER_", savename, filenum);
|
||||
tpsave = NULL;
|
||||
Circuit2 = NULL;
|
||||
FREE(savename);
|
||||
}
|
||||
}
|
||||
else if (matchnocase(nexttok, ".MODEL")) {
|
||||
unsigned char class = CLASS_SUBCKT;
|
||||
|
||||
+402
-45
@@ -42,6 +42,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for calloc(), free(), getenv() */
|
||||
#include <ctype.h> /* for isalnum() */
|
||||
#ifndef IBMPC
|
||||
#include <sys/types.h> /* for getpwnam() tilde expansion */
|
||||
#include <pwd.h>
|
||||
@@ -56,6 +57,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "netfile.h"
|
||||
#include "print.h"
|
||||
#include "hash.h"
|
||||
#include "netcmp.h"
|
||||
|
||||
// See netfile.c for explanation of delimiters. 'X'
|
||||
// separates single-character delimiters from two-character delimiters.
|
||||
@@ -63,6 +65,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#define VLOG_EQUATION_DELIMITERS "X///**/#((**)X,;:(){}[]=+-*/"
|
||||
#define VLOG_PIN_NAME_DELIMITERS "X///**/(**)X()"
|
||||
#define VLOG_PIN_CHECK_DELIMITERS "X///**/(**)X,;(){}"
|
||||
#define VLOG_INTEGER_DELIMITERS "X///**/X;[]"
|
||||
|
||||
// Used by portelement structure "flags" record.
|
||||
#define PORT_NOT_FOUND 0
|
||||
@@ -83,6 +86,16 @@ struct bus {
|
||||
int end;
|
||||
};
|
||||
|
||||
// Global storage for a 'for' loop
|
||||
struct _loop {
|
||||
char *loopvar;
|
||||
int start;
|
||||
int end;
|
||||
long filepos;
|
||||
};
|
||||
|
||||
struct _loop loop;
|
||||
|
||||
// Free a bus structure in the hash table during cleanup
|
||||
|
||||
int freebus (struct hashlist *p)
|
||||
@@ -244,7 +257,16 @@ int EvalExpr(struct expr_stack **stackptr, int *valptr)
|
||||
|
||||
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')) {
|
||||
/* Watch for (a)*b+c or a+b*(c); multiplies must be solved first */
|
||||
if ((texp->last->last != NULL) && ((texp->last->last->oper == '*')
|
||||
|| (texp->last->last->oper == '/'))) {
|
||||
/* Do nothing */
|
||||
}
|
||||
else if ((texp->next->next != NULL) && ((texp->next->next->oper == '*')
|
||||
|| (texp->next->next->oper == '/'))) {
|
||||
/* Do nothing */
|
||||
}
|
||||
else if ((texp->last->oper == '\0') && (texp->next->oper == '\0')) {
|
||||
if (texp->oper == '-') {
|
||||
/* Subtract */
|
||||
texp->last->value -= texp->next->value;
|
||||
@@ -290,6 +312,7 @@ int EvalExpr(struct expr_stack **stackptr, int *valptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* If only one numerical item remains, then place it in valptr and return 1 */
|
||||
@@ -311,6 +334,134 @@ int EvalExpr(struct expr_stack **stackptr, int *valptr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Parse an expression which must resolve to a single integer.
|
||||
// If it does, return "1" and put the integer in the return
|
||||
// pointer "iptr". If not, return "0" and iptr is undefined.
|
||||
// The expression may use parameters, standard arithmetic,
|
||||
// and parenthetic grouping. This routine does not tokenize input
|
||||
// but assumes that the entire expression is in the string "expr".
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
int ParseIntegerExpression(char *expr, int *iptr)
|
||||
{
|
||||
int result, value;
|
||||
char *sptr, *cptr, savec;
|
||||
struct property *kl = NULL;
|
||||
struct expr_stack *stack, *newexp;
|
||||
|
||||
stack = NULL;
|
||||
savec = '\0';
|
||||
sptr = expr;
|
||||
result = 1;
|
||||
|
||||
while (sptr && (*sptr != '\0')) {
|
||||
// Move sptr to first non-space character
|
||||
while (isspace(*sptr)) sptr++;
|
||||
|
||||
// Tokenize. Look ahead to next delimeter and truncate string there.
|
||||
cptr = sptr + 1;
|
||||
if (isalnum(*sptr) || (*sptr == '_') || (*sptr == '$')) {
|
||||
while (*cptr != '\0') {
|
||||
if (isalnum(*cptr)) cptr++;
|
||||
else if ((*cptr == '_') || (*cptr == '$')) cptr++;
|
||||
else break;
|
||||
}
|
||||
}
|
||||
savec = *cptr;
|
||||
*cptr = '\0';
|
||||
|
||||
if (match(sptr, "+") || match(sptr, "-")
|
||||
|| match(sptr, "*") || match(sptr, "/")
|
||||
|| match(sptr, "(") || match(sptr, ")")) {
|
||||
newexp = (struct expr_stack *)MALLOC(sizeof(struct expr_stack));
|
||||
newexp->oper = *sptr;
|
||||
newexp->value = 0;
|
||||
newexp->next = NULL;
|
||||
newexp->last = stack;
|
||||
if (stack) stack->next = newexp;
|
||||
stack = newexp;
|
||||
|
||||
sptr = cptr;
|
||||
*cptr = savec;
|
||||
continue;
|
||||
}
|
||||
if ((result = sscanf(sptr, "%d", &value)) != 1) {
|
||||
|
||||
// Is name in the parameter list?
|
||||
kl = (struct property *)HashLookup(nexttok, &verilogparams);
|
||||
if (kl == NULL) {
|
||||
Printf("Value %s in expression is not a number or a parameter.\n",
|
||||
sptr);
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (kl->type == PROP_STRING) {
|
||||
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);
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (kl->type == PROP_INTEGER) {
|
||||
value = kl->pdefault.ival;
|
||||
}
|
||||
else if (kl->type == PROP_DOUBLE) {
|
||||
value = (int)kl->pdefault.dval;
|
||||
if ((double)value != kl->pdefault.dval) {
|
||||
Printf("Parameter %s has value %g that cannot be parsed"
|
||||
" as an integer.\n",
|
||||
nexttok, kl->pdefault.dval);
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Printf("Parameter %s has unknown type; don't know how"
|
||||
" to parse.\n", nexttok);
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* Move to next token */
|
||||
sptr = cptr;
|
||||
*cptr = savec;
|
||||
}
|
||||
|
||||
if (result != 0) {
|
||||
if (stack == NULL) {
|
||||
Printf("Empty array found.\n");
|
||||
result = 0;
|
||||
}
|
||||
else if (EvalExpr(&stack, iptr) != 1) {
|
||||
Printf("Bad expression found in array.\n");
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* In case of error, stack may need cleaning up */
|
||||
while (stack != NULL) {
|
||||
newexp = stack;
|
||||
stack = stack->last;
|
||||
FREE(newexp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// 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.
|
||||
@@ -323,7 +474,6 @@ int EvalExpr(struct expr_stack **stackptr, int *valptr)
|
||||
int GetBusTok(struct bus *wb)
|
||||
{
|
||||
int result, start, end, value;
|
||||
char oper;
|
||||
struct property *kl = NULL;
|
||||
struct expr_stack *stack, *newexp;
|
||||
|
||||
@@ -338,7 +488,6 @@ int GetBusTok(struct bus *wb)
|
||||
|
||||
if (match(nexttok, "[")) {
|
||||
start = end = -1;
|
||||
oper = '\0';
|
||||
while (nexttok) {
|
||||
SkipTokComments(VLOG_EQUATION_DELIMITERS);
|
||||
if (match(nexttok, "]")) {
|
||||
@@ -467,13 +616,16 @@ int GetBusTok(struct bus *wb)
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// GetBus() is similar to GetBusTok() (see above), but it parses from
|
||||
// a string instead of the input tokenizer.
|
||||
// a string instead of the input tokenizer, and expressions are not
|
||||
// allowed.
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
int GetBus(char *astr, struct bus *wb)
|
||||
{
|
||||
char *colonptr, *brackstart, *brackend, *sigend, sdelim, *aastr;
|
||||
int result, start, end;
|
||||
struct property *kl = NULL;
|
||||
struct expr_stack *stack, *newexp;
|
||||
|
||||
if (wb == NULL) return 0;
|
||||
else {
|
||||
@@ -531,7 +683,7 @@ int GetBus(char *astr, struct bus *wb)
|
||||
*brackend = '\0';
|
||||
colonptr = strvchr(aastr, ':');
|
||||
if (colonptr) *colonptr = '\0';
|
||||
result = sscanf(brackstart + 1, "%d", &start);
|
||||
result = ParseIntegerExpression(brackstart + 1, &start);
|
||||
if (colonptr) *colonptr = ':';
|
||||
if (result != 1) {
|
||||
Printf("Badly formed array notation \"%s\"\n", astr);
|
||||
@@ -539,7 +691,7 @@ int GetBus(char *astr, struct bus *wb)
|
||||
return 1;
|
||||
}
|
||||
if (colonptr)
|
||||
result = sscanf(colonptr + 1, "%d", &end);
|
||||
result = ParseIntegerExpression(colonptr + 1, &end);
|
||||
else {
|
||||
result = 1;
|
||||
end = start; // Single bit
|
||||
@@ -866,16 +1018,17 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
char devtype, in_module, in_param;
|
||||
char *eqptr, *matchptr;
|
||||
struct keyvalue *kvlist = NULL;
|
||||
char inst[MAX_STR_LEN], model[MAX_STR_LEN], instname[MAX_STR_LEN], portname[MAX_STR_LEN], pkey[MAX_STR_LEN];
|
||||
struct nlist *tp;
|
||||
char inst[MAX_STR_LEN], model[MAX_STR_LEN], portname[MAX_STR_LEN], pkey[MAX_STR_LEN];
|
||||
struct nlist *tp, *tpsave;
|
||||
struct objlist *parent, *sobj, *nobj, *lobj, *pobj, *cref;
|
||||
|
||||
inst[MAX_STR_LEN-1] = '\0';
|
||||
model[MAX_STR_LEN-1] = '\0';
|
||||
instname[MAX_STR_LEN-1] = '\0';
|
||||
in_module = (char)0;
|
||||
in_param = (char)0;
|
||||
|
||||
loop.loopvar = NULL;
|
||||
|
||||
while (!EndParseFile()) {
|
||||
|
||||
SkipTokComments(VLOG_DELIMITERS); /* get the next token */
|
||||
@@ -1000,6 +1153,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
||||
tp = LookupCellFile(nexttok, filenum);
|
||||
tpsave = NULL;
|
||||
hasports = (char)0;
|
||||
|
||||
/* Check for name conflict with duplicate cell names */
|
||||
@@ -1039,35 +1193,9 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
tp = LookupCellFile(nexttok, filenum);
|
||||
}
|
||||
else if (tp != NULL) { /* Cell exists, but as a placeholder */
|
||||
struct nlist *tptmp = NULL;
|
||||
char ctemp[8];
|
||||
int n = 0;
|
||||
|
||||
/* This redefines a placeholder module to an unused temporary cell name */
|
||||
while (1) {
|
||||
sprintf(ctemp, "%d", n);
|
||||
tptmp = LookupCellFile(ctemp, filenum);
|
||||
if (tptmp == NULL) break;
|
||||
n++;
|
||||
}
|
||||
CellRehash(nexttok, ctemp, filenum);
|
||||
tptmp = LookupCellFile(ctemp, filenum);
|
||||
|
||||
/* Create a new module definition */
|
||||
CellDef(model, filenum);
|
||||
tp = LookupCellFile(model, filenum);
|
||||
|
||||
/* Find an instance of this module in the netlist */
|
||||
cref = FindInstanceOf(tp);
|
||||
if ((cref != NULL) && (cref->name != NULL)) {
|
||||
hasports = (char)1;
|
||||
/* Copy ports from the original parent cell to the new parent cell */
|
||||
for (pobj = tptmp->cell; pobj && (pobj->type == PORT); pobj = pobj->next)
|
||||
Port(pobj->name);
|
||||
}
|
||||
/* Remove the original cell definition */
|
||||
FreePorts(ctemp);
|
||||
CellDelete(ctemp, filenum); /* This removes any PLACEHOLDER flag */
|
||||
tpsave = tp;
|
||||
CellDef("_PLACEHOLDER_", filenum);
|
||||
tp = LookupCellFile("_PLACEHOLDER_", filenum);
|
||||
}
|
||||
else if (tp == NULL) { /* Completely new cell, no name conflict */
|
||||
CellDef(model, filenum);
|
||||
@@ -1276,6 +1404,38 @@ skip_endmodule:
|
||||
if (*CellStackPtr) PopStack(CellStackPtr);
|
||||
if (*CellStackPtr) ReopenCellDef((*CellStackPtr)->cellname, filenum);
|
||||
SkipNewLine(VLOG_DELIMITERS);
|
||||
|
||||
if (tpsave != NULL) {
|
||||
struct nlist *tpplace;
|
||||
char *savename;
|
||||
|
||||
/* Handle a placeholder from a verilog file that has been replaced
|
||||
* by a netlist with pins in a different order. The pins need to
|
||||
* be matched, corrected in the original cell and all instances,
|
||||
* and the new cell deleted.
|
||||
*/
|
||||
|
||||
Printf("Verilog placeholder module %s replaced by module definition\n",
|
||||
tpsave->name);
|
||||
tpplace = LookupCellFile("_PLACEHOLDER_", filenum);
|
||||
/* MatchPins is part of netcmp and normally Circuit2 is the
|
||||
* circuit being matched, so set Circuit2 to the original
|
||||
* verilog black-box cell, and MatchPins() will force its
|
||||
* pins to be rearranged to match the module definition just
|
||||
* read.
|
||||
*/
|
||||
Circuit2 = tpsave;
|
||||
MatchPins(tpplace, tpsave, 0);
|
||||
savename = strsave(tpsave->name);
|
||||
/* Now the original verilog black-box cell can be removed */
|
||||
FreePorts(savename);
|
||||
CellDelete(savename, filenum);
|
||||
/* And _PLACEHOLDER_ is renamed to the original name of the cell. */
|
||||
CellRehash("_PLACEHOLDER_", savename, filenum);
|
||||
tpsave = NULL;
|
||||
Circuit2 = NULL;
|
||||
FREE(savename);
|
||||
}
|
||||
}
|
||||
|
||||
else if (match(nexttok, "`include")) {
|
||||
@@ -1416,6 +1576,145 @@ skip_endmodule:
|
||||
while (!match(nexttok, ";")) SkipTok("X///**/X,;");
|
||||
continue;
|
||||
}
|
||||
else if (match(nexttok, "end")) {
|
||||
/* Handle a 'for' loop */
|
||||
if (loop.loopvar != NULL) {
|
||||
int loopval;
|
||||
struct property *klr;
|
||||
|
||||
klr = (struct property *)HashLookup(loop.loopvar, &verilogparams);
|
||||
loopval = klr->pdefault.ival;
|
||||
|
||||
if (loopval < loop.end) loopval++;
|
||||
else if (loopval > loop.end) loopval--;
|
||||
SeekFile(loop.filepos);
|
||||
if (loopval == loop.end)
|
||||
{
|
||||
HashDelete(loop.loopvar, &verilogparams);
|
||||
FREE(klr);
|
||||
FREE(loop.loopvar);
|
||||
loop.loopvar = NULL;
|
||||
}
|
||||
else
|
||||
klr->pdefault.ival = loopval;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (match(nexttok, "begin") || match(nexttok, "generate")) {
|
||||
/* 'generate' section or 'for' loop start is ignored */
|
||||
continue;
|
||||
}
|
||||
else if (match(nexttok, "generate") || match(nexttok, "endgenerate")) {
|
||||
/* 'generate' section is ignored */
|
||||
continue;
|
||||
}
|
||||
else if (match(nexttok, "genvar")) {
|
||||
while (!match(nexttok, ";")) SkipTok("X///**/X,;");
|
||||
continue;
|
||||
}
|
||||
else if (match(nexttok, "for")) {
|
||||
char limittype = '\0';
|
||||
char *paramkey = NULL;
|
||||
struct property *kl = NULL, *klr;
|
||||
/* Parse out the loop variable and count. Set the loop
|
||||
* variable as a parameter. Find the beginning of the
|
||||
* loop block and record the file position so that the
|
||||
* block can be re-parsed for each loop iteration.
|
||||
*/
|
||||
SkipTokNoNewline(VLOG_DELIMITERS);
|
||||
if ((nexttok == NULL) || !match(nexttok, "(")) {
|
||||
Printf("Badly formed 'for' loop.\n");
|
||||
FREE(paramkey);
|
||||
break;
|
||||
}
|
||||
SkipTokNoNewline(VLOG_DELIMITERS);
|
||||
/* Next token must be the loop variable */
|
||||
if (nexttok == NULL) break;
|
||||
paramkey = strsave(nexttok);
|
||||
SkipTokNoNewline(VLOG_DELIMITERS);
|
||||
if (!match(nexttok, "=")) {
|
||||
Printf("Badly formed 'for' loop.\n");
|
||||
FREE(paramkey);
|
||||
break;
|
||||
}
|
||||
SkipTokNoNewline(VLOG_INTEGER_DELIMITERS);
|
||||
if (ParseIntegerExpression(nexttok, &ival) == 0) {
|
||||
FREE(paramkey);
|
||||
break;
|
||||
}
|
||||
|
||||
kl = NewProperty();
|
||||
kl->type = PROP_INTEGER;
|
||||
kl->slop.ival = 0;
|
||||
kl->pdefault.ival = ival;
|
||||
kl->key = paramkey;
|
||||
kl->idx = 0;
|
||||
kl->merge = MERGE_NONE;
|
||||
|
||||
SkipTokNoNewline(VLOG_DELIMITERS);
|
||||
if (!match(nexttok, ";")) {
|
||||
Printf("Badly formed 'for' loop.\n");
|
||||
FREE(paramkey);
|
||||
FREE(kl);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Assuming a standard 'for' loop here */
|
||||
SkipTokNoNewline(VLOG_DELIMITERS);
|
||||
if (!match(nexttok, paramkey)) {
|
||||
Printf("Don't know how to parse this 'for' loop!\n");
|
||||
FREE(paramkey);
|
||||
FREE(kl);
|
||||
break;
|
||||
}
|
||||
SkipTokNoNewline(VLOG_DELIMITERS);
|
||||
if (strlen(nexttok) == 1) limittype = *nexttok;
|
||||
SkipTokNoNewline(VLOG_INTEGER_DELIMITERS);
|
||||
if (ParseIntegerExpression(nexttok, &ival) == 0) {
|
||||
FREE(kl);
|
||||
FREE(paramkey);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Loops will stop after the last value, so if value is > or <,
|
||||
* then adjust the end value accordingly.
|
||||
*/
|
||||
if (limittype == '<')
|
||||
ival--;
|
||||
else if (limittype == '>')
|
||||
ival++;
|
||||
|
||||
SkipTokNoNewline(VLOG_DELIMITERS);
|
||||
if (!match(nexttok, ";")) {
|
||||
Printf("Badly formed 'for' loop.\n");
|
||||
FREE(paramkey);
|
||||
FREE(kl);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Assume a standard 'for' loop and skip to the block begin */
|
||||
/* To do: Parse out the loop increment value. */
|
||||
while (1) {
|
||||
SkipTokNoNewline(VLOG_DELIMITERS);
|
||||
if (EndParseFile()) break;
|
||||
else if (match(nexttok, "begin")) break;
|
||||
}
|
||||
if (EndParseFile()) {
|
||||
Printf("Badly formed 'for' loop: No begin/end block.\n");
|
||||
FREE(paramkey);
|
||||
FREE(kl);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Save the loop variable, ending value, and file position */
|
||||
loop.loopvar = paramkey;
|
||||
loop.start = kl->pdefault.ival;
|
||||
loop.end = ival;
|
||||
loop.filepos = TellFile();
|
||||
|
||||
/* 'for' loop has been completely parsed, so save the loop variable */
|
||||
HashPtrInstall(paramkey, kl, &verilogparams);
|
||||
}
|
||||
else if (match(nexttok, "wire") || match(nexttok, "assign")) { /* wire = node */
|
||||
struct bus wb, wb2, *nb;
|
||||
char nodename[MAX_STR_LEN], noderoot[MAX_STR_LEN];
|
||||
@@ -1479,7 +1778,7 @@ skip_endmodule:
|
||||
}
|
||||
else { /* "assign" */
|
||||
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
|
||||
if (GetBus(nexttok, &wb) == 0) {
|
||||
if (GetBusTok(&wb) == 0) {
|
||||
char *aptr = strvchr(nexttok, '[');
|
||||
if (aptr != NULL) {
|
||||
*aptr = '\0';
|
||||
@@ -1514,9 +1813,11 @@ skip_endmodule:
|
||||
// "assign a = b" joins two nets.
|
||||
// "assign a = {b, c, ...}" creates a bus from components.
|
||||
// "assign" using any boolean arithmetic is not structural verilog.
|
||||
// "assign a = {x{b}}" creates a bus by repeating a component.
|
||||
|
||||
if (nexttok && match(nexttok, "=")) {
|
||||
char assignname[MAX_STR_LEN], assignroot[MAX_STR_LEN];
|
||||
int multiplier = 1;
|
||||
|
||||
i = wb.start;
|
||||
while (1) {
|
||||
@@ -1525,6 +1826,10 @@ skip_endmodule:
|
||||
|
||||
if (match(nexttok, "{")) {
|
||||
/* RHS is a bundle */
|
||||
/* Make provisional multiplier active. NOTE: */
|
||||
/* this is not going to properly handle complex */
|
||||
/* multipliers like {2{a,b}}. Needs rework. */
|
||||
if (multiplier < 0) multiplier = -multiplier;
|
||||
continue;
|
||||
}
|
||||
else if (match(nexttok, "}")) {
|
||||
@@ -1540,7 +1845,7 @@ skip_endmodule:
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (GetBus(nexttok, &wb2) == 0) {
|
||||
if (GetBusTok(&wb2) == 0) {
|
||||
char *aptr = strvchr(nexttok, '[');
|
||||
j = wb2.start;
|
||||
if (aptr != NULL) {
|
||||
@@ -1556,6 +1861,18 @@ skip_endmodule:
|
||||
else {
|
||||
j = -1;
|
||||
rhs = LookupObject(nexttok, CurrentCell);
|
||||
|
||||
/* Check if rhs starts with a signal multiplier */
|
||||
if (rhs == NULL) {
|
||||
if (ConvertStringToInteger(nexttok, &multiplier) == 1) {
|
||||
/* Set multiplier to a negative value to
|
||||
* indicate that it is provisional, waiting on
|
||||
* signal specification to follow.
|
||||
*/
|
||||
multiplier = -multiplier;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((lhs == NULL) || (rhs == NULL)) {
|
||||
if (rhs != NULL) {
|
||||
@@ -1568,7 +1885,7 @@ skip_endmodule:
|
||||
Printf("Improper expression is \"%s\".\n", nexttok);
|
||||
break;
|
||||
}
|
||||
if (lhs != NULL) {
|
||||
if ((lhs != NULL) || (multiplier < 0)) {
|
||||
Printf("Improper assignment; right-hand side cannot "
|
||||
"be parsed.\n");
|
||||
if (i != -1)
|
||||
@@ -1589,20 +1906,35 @@ skip_endmodule:
|
||||
|
||||
if (i != -1)
|
||||
snprintf(nodename, MAX_STR_LEN, "%s[%d]", noderoot, i);
|
||||
else
|
||||
else if (lhs != NULL)
|
||||
strncpy(nodename, lhs->name, MAX_STR_LEN - 1);
|
||||
else {
|
||||
Printf("Error: Improper node name \"%s\".\n", noderoot);
|
||||
goto skip_endmodule;
|
||||
}
|
||||
if (j != -1)
|
||||
snprintf(assignname, MAX_STR_LEN, "%s[%d]", assignroot, j);
|
||||
else
|
||||
else if (rhs != NULL)
|
||||
strncpy(assignname, rhs->name, MAX_STR_LEN - 1);
|
||||
else {
|
||||
Printf("Error: Improper assignment name \"%s\".\n",
|
||||
assignroot);
|
||||
goto skip_endmodule;
|
||||
}
|
||||
|
||||
join(nodename, assignname);
|
||||
|
||||
if (i == wb.end) break;
|
||||
i += (wb.end > wb.start) ? 1 : -1;
|
||||
|
||||
if (j == wb2.end) break;
|
||||
j += (wb2.end > wb2.start) ? 1 : -1;
|
||||
if (j == wb2.end) {
|
||||
if (multiplier <= 1)
|
||||
break;
|
||||
else
|
||||
multiplier--;
|
||||
}
|
||||
else
|
||||
j += (wb2.end > wb2.start) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1810,6 +2142,31 @@ nextinst:
|
||||
}
|
||||
new_port->net = wire_bundle;
|
||||
}
|
||||
else if ((strchr(nexttok, '[') != NULL) &&
|
||||
(strchr(nexttok, ']') == NULL)) {
|
||||
/* If a bus expressions has whitespace, then treat it like
|
||||
* a bundle, above, concatenating to the closing ']'.
|
||||
*/
|
||||
char *array_expr = (char *)MALLOC(1);
|
||||
char *new_array_expr = NULL;
|
||||
*array_expr = '\0';
|
||||
/* Read to "]" */
|
||||
while (nexttok) {
|
||||
new_array_expr = (char *)MALLOC(strlen(array_expr) +
|
||||
strlen(nexttok) + 1);
|
||||
/* Roundabout way to do realloc() becase there is no REALLOC() */
|
||||
strcpy(new_array_expr, array_expr);
|
||||
strcat(new_array_expr, nexttok);
|
||||
FREE(array_expr);
|
||||
array_expr = new_array_expr;
|
||||
if (strchr(nexttok, ']')) break;
|
||||
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
|
||||
}
|
||||
if (!nexttok) {
|
||||
Printf("Unterminated net in pin %s\n", array_expr);
|
||||
}
|
||||
new_port->net = array_expr;
|
||||
}
|
||||
else if (nexttok[0] == '~' || nexttok[0] == '!' || nexttok[0] == '-') {
|
||||
/* All of these imply that the signal is logically manipulated */
|
||||
/* in turn implying behavioral code. */
|
||||
|
||||
Vendored
+699
-418
File diff suppressed because it is too large
Load Diff
Vendored
+1487
-1430
File diff suppressed because it is too large
Load Diff
Vendored
+1
-52
@@ -668,7 +668,6 @@ XMKMF
|
||||
HAVE_PYTHON3
|
||||
EGREP
|
||||
GREP
|
||||
M4
|
||||
RANLIB
|
||||
INSTALL_DATA
|
||||
INSTALL_SCRIPT
|
||||
@@ -3702,56 +3701,6 @@ else
|
||||
fi
|
||||
|
||||
|
||||
for ac_prog in gm4 gnum4 m4
|
||||
do
|
||||
# Extract the first word of "$ac_prog", so it can be a program name with args.
|
||||
set dummy $ac_prog; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_path_M4+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
case $M4 in
|
||||
[\\/]* | ?:[\\/]*)
|
||||
ac_cv_path_M4="$M4" # Let the user override the test with a path.
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_path_M4="$as_dir/$ac_word$ac_exec_ext"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
M4=$ac_cv_path_M4
|
||||
if test -n "$M4"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $M4" >&5
|
||||
$as_echo "$M4" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
test -n "$M4" && break
|
||||
done
|
||||
test -n "$M4" || M4="no"
|
||||
|
||||
if test x$M4 = xno; then
|
||||
as_fn_error $? "M4 is required" "$LINENO" 5
|
||||
fi
|
||||
|
||||
|
||||
if test "$CPP" = "$CC -E" ; then
|
||||
CPP="$CPP -x c"
|
||||
@@ -6302,7 +6251,7 @@ fi
|
||||
|
||||
*darwin*)
|
||||
SHDLIB_EXT=".dylib"
|
||||
LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind"
|
||||
LDDL_FLAGS="-dynamiclib -undefined dynamic_lookup"
|
||||
LDFLAGS="${LDFLAGS} ${LIB_SPECS}"
|
||||
CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common"
|
||||
;;
|
||||
|
||||
@@ -26,12 +26,6 @@ AC_ISC_POSIX
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_RANLIB
|
||||
|
||||
dnl GNU M4 is preferred due to some of the option switches.
|
||||
AC_PATH_PROGS([M4], [gm4 gnum4 m4], [no])
|
||||
if test x$M4 = xno; then
|
||||
AC_MSG_ERROR([M4 is required])
|
||||
fi
|
||||
|
||||
dnl check size of pointer for correct behavior on 64-bit systems
|
||||
dnl If the C preprocessor is GCC, we need to force the flag to
|
||||
dnl assert that input files are of type C, or else the preprocessing
|
||||
@@ -1033,7 +1027,7 @@ fi
|
||||
|
||||
*darwin*)
|
||||
SHDLIB_EXT=".dylib"
|
||||
LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind"
|
||||
LDDL_FLAGS="-dynamiclib -undefined dynamic_lookup"
|
||||
LDFLAGS="${LDFLAGS} ${LIB_SPECS}"
|
||||
CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common"
|
||||
;;
|
||||
|
||||
+23
-4
@@ -479,8 +479,12 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
|
||||
netgen::compare assign "$fnum1 $cell1" "$fnum2 $cell2"
|
||||
|
||||
if {[file exists $setupfile]} {
|
||||
puts stdout "Reading setup file $setupfile"
|
||||
if {$setupfile == ""} {
|
||||
puts stdout "\nNo setup file specified. Using trivial default setup.\n"
|
||||
netgen::permute default ;# transistors and resistors
|
||||
netgen::property default
|
||||
} elseif {[file exists $setupfile]} {
|
||||
puts stdout "\nReading setup file $setupfile\n"
|
||||
# Instead of sourcing the setup file, run each line so we can
|
||||
# catch individual errors and not let them halt the LVS process
|
||||
set perrors 0
|
||||
@@ -508,8 +512,10 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
puts stdout "Warning: There were errors reading the setup file"
|
||||
}
|
||||
} elseif {[string first nosetup $setupfile] < 0} {
|
||||
netgen::permute default ;# transistors and resistors
|
||||
netgen::property default
|
||||
puts stderr "\nError: Setup file $setupfile does not exist.\n"
|
||||
return
|
||||
} else {
|
||||
puts stderr "\nNo setup file specified. Continuing without a setup.\n"
|
||||
}
|
||||
|
||||
if {[string first nolog $logfile] < 0} {
|
||||
@@ -735,6 +741,19 @@ set auto_noexec 1 ;# don't EVER call UNIX commands w/o "shell" in front
|
||||
# Cross-Application section
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
# For use with open_pdks, set PDK_ROOT from the environment. If no
|
||||
# such environment variable exists, check some common locations.
|
||||
|
||||
if {[catch {set PDK_ROOT $::env(PDK_ROOT)}]} {
|
||||
if {[file isdir /usr/local/share/pdk] == 1} {
|
||||
set PDK_ROOT /usr/local/share/pdk
|
||||
} elseif {[file isdir /usr/share/pdk] == 1} {
|
||||
set PDK_ROOT /usr/share/pdk
|
||||
} elseif {[file isdir /foss/pdk] == 1} {
|
||||
set PDK_ROOT /foss/pdk
|
||||
}
|
||||
}
|
||||
|
||||
# Setup IRSIM assuming that the Tcl version is installed.
|
||||
# We do not need to rename procedure irsim to NULL because it is
|
||||
# redefined in a script, which simply overwrites the original.
|
||||
|
||||
+5
-2
@@ -707,11 +707,11 @@ _netgen_readnet(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
|
||||
{
|
||||
char *formats[] = {
|
||||
"automatic", "ext", "extflat", "sim", "ntk", "spice",
|
||||
"automatic", "ext", "extflat", "sim", "prm", "ntk", "spice",
|
||||
"verilog", "netgen", "actel", "xilinx", NULL
|
||||
};
|
||||
enum FormatIdx {
|
||||
AUTO_IDX, EXT_IDX, EXTFLAT_IDX, SIM_IDX, NTK_IDX,
|
||||
AUTO_IDX, EXT_IDX, EXTFLAT_IDX, SIM_IDX, PRM_IDX, NTK_IDX,
|
||||
SPICE_IDX, VERILOG_IDX, NETGEN_IDX, ACTEL_IDX, XILINX_IDX
|
||||
};
|
||||
struct nlist *tc;
|
||||
@@ -807,6 +807,9 @@ _netgen_readnet(ClientData clientData,
|
||||
case SIM_IDX:
|
||||
retstr = ReadSim(savstr, &filenum);
|
||||
break;
|
||||
case PRM_IDX:
|
||||
retstr = ReadPrm(savstr, &filenum);
|
||||
break;
|
||||
case NTK_IDX:
|
||||
retstr = ReadNtk(savstr, &filenum);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user