mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-25 23:47:06 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
758b5a249a | ||
|
|
15d10f1d93 | ||
|
|
a6e3e7e457 | ||
|
|
5f634b2a91 |
+5
-5
@@ -39,7 +39,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#define ACTELHASHSIZE 99
|
||||
static long actelhashbase = 0xA00;
|
||||
static struct hashlist *actelnametab[ACTELHASHSIZE];
|
||||
static struct hashdict actelnamedict;
|
||||
static FILE *actelfile;
|
||||
|
||||
char *ActelName(char *Name);
|
||||
@@ -53,16 +53,16 @@ void PrintActelNames(char *filename)
|
||||
{
|
||||
if (filename == NULL) actelfile = stdout;
|
||||
else actelfile = fopen(filename,"w");
|
||||
RecurseHashTable(actelnametab, ACTELHASHSIZE, PrintActelName);
|
||||
RecurseHashTable(&actelnamedict, PrintActelName);
|
||||
if (actelfile != stdout) fclose(actelfile);
|
||||
}
|
||||
|
||||
long ActelNameHash(char *name)
|
||||
/* hashes name into nametab if necessary, then returns address of entry */
|
||||
/* hashes name into namedict if necessary, then returns address of entry */
|
||||
{
|
||||
struct hashlist *p;
|
||||
|
||||
p = HashInstall(name, actelnametab, ACTELHASHSIZE);
|
||||
p = HashInstall(name, &actelnamedict);
|
||||
if (p == NULL) return(0);
|
||||
if (p->ptr != NULL) return ((long)(p->ptr));
|
||||
actelhashbase++;
|
||||
@@ -403,7 +403,7 @@ void Actel(char *name, char *filename)
|
||||
return;
|
||||
}
|
||||
ClearDumpedList();
|
||||
InitializeHashTable(actelnametab, ACTELHASHSIZE);
|
||||
InitializeHashTable(&actelnamedict, ACTELHASHSIZE);
|
||||
if (LookupCell(name) != NULL)
|
||||
actelCell(name);
|
||||
CloseFile(FileName);
|
||||
|
||||
+3
-3
@@ -544,10 +544,10 @@ void simCell(char *name, int filenum)
|
||||
if (ob2 && ob2->type == PROPERTY) {
|
||||
struct property *kl;
|
||||
struct valuelist *vl;
|
||||
kl = (struct property *)HashLookup("length", tp2->proptab, OBJHASHSIZE);
|
||||
kl = (struct property *)HashLookup("length", &(tp2->propdict));
|
||||
vl = (struct valuelist *)ob2->instance.name;
|
||||
l = 1.0e6 * vl[kl->idx].value.dval; /* m -> um */
|
||||
kl = (struct property *)HashLookup("width", tp2->proptab, OBJHASHSIZE);
|
||||
kl = (struct property *)HashLookup("width", &(tp2->propdict));
|
||||
w = 1.0e6 * vl[kl->idx].value.dval; /* m -> um */
|
||||
}
|
||||
FlushString(" %g %g\n", l, w);
|
||||
@@ -579,7 +579,7 @@ void simCell(char *name, int filenum)
|
||||
if (ob2 && ob2->type == PROPERTY) {
|
||||
struct property *kl;
|
||||
struct valuelist *vl;
|
||||
kl = (struct property *)HashLookup("value", tp2->proptab, OBJHASHSIZE);
|
||||
kl = (struct property *)HashLookup("value", &(tp2->propdict));
|
||||
vl = (struct valuelist *)ob2->instance.name;
|
||||
if (tp2->class == CLASS_CAP)
|
||||
v = 1.0e15 * vl[kl->idx].value.dval; /* F -> fF */
|
||||
|
||||
+456
-79
@@ -24,6 +24,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef IBMPC
|
||||
#include <alloc.h>
|
||||
@@ -39,6 +40,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "print.h"
|
||||
#include "netcmp.h"
|
||||
|
||||
extern struct hashdict spiceparams;
|
||||
|
||||
#define OLDPREFIX 1
|
||||
|
||||
void flattenCell(char *name, int file)
|
||||
@@ -95,7 +98,7 @@ void flattenCell(char *name, int file)
|
||||
if (ChildCell->dumped == 0) flattenCell(ParentParams->model.class,
|
||||
ChildCell->file);
|
||||
|
||||
ChildObjList = CopyObjList(ChildCell->cell);
|
||||
ChildObjList = CopyObjList(ChildCell->cell, 1);
|
||||
|
||||
/* update node numbers in child to unique numbers */
|
||||
oldmax = 0;
|
||||
@@ -177,7 +180,7 @@ void flattenCell(char *name, int file)
|
||||
}
|
||||
}
|
||||
}
|
||||
HashPtrInstall(tmp->name, tmp, ThisCell->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -198,9 +201,9 @@ void flattenCell(char *name, int file)
|
||||
#endif
|
||||
FreeString(tmp->instance.name);
|
||||
tmp->instance.name = strsave(tmpstr);
|
||||
HashPtrInstall(tmp->name, tmp, ThisCell->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
|
||||
if (tmp->type == FIRSTPIN)
|
||||
HashPtrInstall(tmp->instance.name, tmp, ThisCell->insttab, OBJHASHSIZE);
|
||||
HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict));
|
||||
}
|
||||
|
||||
/* splice instance out of parent */
|
||||
@@ -322,7 +325,7 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
/* if this is a new instance, flatten it */
|
||||
/* if (ChildCell->dumped == 0) flattenCell(ParentParams->model.class, file); */
|
||||
|
||||
ChildObjList = CopyObjList(ChildCell->cell);
|
||||
ChildObjList = CopyObjList(ChildCell->cell, 1);
|
||||
numflat++;
|
||||
|
||||
/* update node numbers in child to unique numbers */
|
||||
@@ -440,7 +443,7 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
}
|
||||
// Don't hash this if the parent had a port of this name
|
||||
if (!ob2 || ob2->type != PORT)
|
||||
HashPtrInstall(tmp->name, tmp, ThisCell->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -461,33 +464,24 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
#endif
|
||||
FreeString(tmp->instance.name);
|
||||
tmp->instance.name = strsave(tmpstr);
|
||||
HashPtrInstall(tmp->name, tmp, ThisCell->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
|
||||
if (tmp->type == FIRSTPIN)
|
||||
HashPtrInstall(tmp->instance.name, tmp, ThisCell->insttab, OBJHASHSIZE);
|
||||
HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict));
|
||||
}
|
||||
|
||||
/* do property inheritance */
|
||||
/* Do property inheritance */
|
||||
|
||||
if (ParentProps) {
|
||||
for (ob2 = ChildObjList; ob2 != NULL; ob2=ob2->next) {
|
||||
|
||||
/* If the parent cell has properties to declare, then */
|
||||
/* pass them on to children. */
|
||||
/* pass them on to children. Use globals only if the */
|
||||
/* spiceparams dictionary is active (during file reading */
|
||||
/* only). */
|
||||
|
||||
if (ob2->type == PROPERTY) {
|
||||
struct valuelist *vl;
|
||||
int i;
|
||||
for (i == 0;; i++) {
|
||||
vl = &(ob2->instance.props[i]);
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
else if (vl->type == PROP_EXPRESSION) {
|
||||
/* Only expressions take substitutions */
|
||||
struct tokstack *token;
|
||||
for (token = vl->value.stack; token; token = token->next) {
|
||||
/* WIP */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ob2->type == PROPERTY)
|
||||
ReduceExpressions(ob2, ParentProps, ChildCell,
|
||||
(spiceparams.hashtab == NULL) ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,7 +502,7 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
tmp = ParentParams;
|
||||
do {
|
||||
tmp = tmp->next;
|
||||
} while ((tmp != NULL) && (tmp->type > FIRSTPIN));
|
||||
} while ((tmp != NULL) && ((tmp->type > FIRSTPIN) || (tmp->type == PROPERTY)));
|
||||
if (ob2) ob2->next = tmp;
|
||||
while (ParentParams != tmp) {
|
||||
ob2 = ParentParams->next;
|
||||
@@ -526,8 +520,8 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
||||
|
||||
void Flatten(char *name, int file)
|
||||
{
|
||||
ClearDumpedList(); /* keep track of flattened cells */
|
||||
flattenCell(name, file);
|
||||
ClearDumpedList(); /* keep track of flattened cells */
|
||||
flattenCell(name, file);
|
||||
}
|
||||
|
||||
|
||||
@@ -704,7 +698,7 @@ void convertGlobalsOf(char *name, int fnum, char *instance)
|
||||
newnode->instance.name = NULL;
|
||||
newnode->model.class = NULL;
|
||||
newpin->node = maxnode;
|
||||
HashPtrInstall(newnode->name, newnode, ThisCell->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(newnode->name, newnode, &(ThisCell->objdict));
|
||||
}
|
||||
|
||||
// Remove any references to the net as a GLOBAL type in the instance
|
||||
@@ -727,7 +721,7 @@ void convertGlobalsOf(char *name, int fnum, char *instance)
|
||||
// Now there should be only one object of this name in the instance,
|
||||
// which is the pin, and we will set the hash table to point to it.
|
||||
|
||||
HashPtrInstall(newpin->name, newpin, ThisCell->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(newpin->name, newpin, &(ThisCell->objdict));
|
||||
|
||||
}
|
||||
CacheNodeNames(ThisCell);
|
||||
@@ -840,7 +834,7 @@ void ConvertGlobals(char *name, int filenum)
|
||||
strsave(ObjList->instance.name) : NULL;
|
||||
NewObj->name = (ObjList->name) ? strsave(ObjList->name) : NULL;
|
||||
|
||||
HashPtrInstall(NewObj->name, NewObj, ThisCell->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(NewObj->name, NewObj, &(ThisCell->objdict));
|
||||
|
||||
/* Find all parent cells of this cell. Find the global node */
|
||||
/* if it exists or create it if it doesn't. Add the node to */
|
||||
@@ -959,11 +953,11 @@ struct nlist *uniquepins(struct hashlist *p, void *clientdata)
|
||||
modified = 1;
|
||||
|
||||
// Check if the node we're about to remove is in the
|
||||
// objtab hash table; if so, replace it with the one
|
||||
// objdict hash table; if so, replace it with the one
|
||||
// that we are going to keep.
|
||||
|
||||
if (LookupObject(ob->name, ptr) == ob) {
|
||||
HashPtrInstall(ob->name, saveob, ptr->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(ob->name, saveob, &(ptr->objdict));
|
||||
}
|
||||
}
|
||||
tob = tob->next;
|
||||
@@ -998,7 +992,7 @@ struct nlist *uniquepins(struct hashlist *p, void *clientdata)
|
||||
|
||||
// Renumber the pins in order. Since when removing duplicates, the
|
||||
// first entry is always kept, the first pin is never changed, so
|
||||
// the insttab record is never corrupted.
|
||||
// the instdict record is never corrupted.
|
||||
|
||||
i = FIRSTPIN;
|
||||
firstpin->type = i++;
|
||||
@@ -1093,8 +1087,7 @@ int UniquePins(char *name, int filenum)
|
||||
// The hash table is pointing at the cell we are
|
||||
// about to delete. Hash the one we're keeping instead.
|
||||
|
||||
HashPtrInstall(ob->name, firstport[ob->node],
|
||||
ThisCell->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(ob->name, firstport[ob->node], &(ThisCell->objdict));
|
||||
}
|
||||
|
||||
if (lob == NULL) {
|
||||
@@ -1131,7 +1124,7 @@ int UniquePins(char *name, int filenum)
|
||||
/* Callback function for CleanupPins */
|
||||
/* Note that if the first pin of the instance is a */
|
||||
/* disconnected node, then removing it invalidates the */
|
||||
/* insttab hash. */
|
||||
/* instdict hash. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
|
||||
@@ -1181,9 +1174,9 @@ struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
|
||||
}
|
||||
|
||||
// Check if the node we're about to remove is in the
|
||||
// objtab hash table
|
||||
// objdict hash table
|
||||
if (LookupObject(ob->name, ptr) == ob) {
|
||||
HashDelete(ob->name, ptr->objtab, OBJHASHSIZE);
|
||||
HashDelete(ob->name, &(ptr->objdict));
|
||||
}
|
||||
|
||||
FREE(ob->name);
|
||||
@@ -1199,10 +1192,9 @@ struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
|
||||
obt = obt->next;
|
||||
}
|
||||
|
||||
/* Rehash the insttab, in case the first pin got removed */
|
||||
/* Rehash the instdict, in case the first pin got removed */
|
||||
if (firstpin && (firstpin->type == FIRSTPIN))
|
||||
HashPtrInstall(firstpin->instance.name, firstpin, ptr->insttab,
|
||||
OBJHASHSIZE);
|
||||
HashPtrInstall(firstpin->instance.name, firstpin, &(ptr->instdict));
|
||||
}
|
||||
}
|
||||
return NULL; /* Keep the search going */
|
||||
@@ -1272,9 +1264,9 @@ int CleanupPins(char *name, int filenum)
|
||||
}
|
||||
|
||||
// Check if the node we're about to remove is in the
|
||||
// objtab hash table
|
||||
// objdict hash table
|
||||
if (LookupObject(ob->name, ThisCell) == ob) {
|
||||
HashDelete(ob->name, ThisCell->objtab, OBJHASHSIZE);
|
||||
HashDelete(ob->name, &(ThisCell->objdict));
|
||||
}
|
||||
|
||||
FREE(ob->name);
|
||||
@@ -1307,11 +1299,235 @@ typedef struct ecomplist {
|
||||
} ECompList;
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Survey the contents of a cell and
|
||||
/* Split a device into multiple devices based on a */
|
||||
/* critical property; e.g., MOSFET width. Devices with */
|
||||
/* property name equal to kl->key and value "value" */
|
||||
/* will be split into "ndev" devices with the property */
|
||||
/* of each divided down by "ndev". */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
void
|
||||
SurveyCell(struct nlist *tc, struct hashlist **comptab, int file1, int file2, int which)
|
||||
SplitDevice(struct nlist *tc, struct nlist *cell, struct property *kl,
|
||||
double value, int ndev, int file1, int file2, int which)
|
||||
{
|
||||
struct objlist *ob, *ob2, *newdevs, *ob3, *lastob, *nob;
|
||||
struct nlist *tsub;
|
||||
unsigned char found;
|
||||
int file = (which == 0) ? file1 : file2;
|
||||
|
||||
newdevs = NULL; /* Linked list of the copied devices */
|
||||
|
||||
for (ob = tc->cell; ob; ob = ob->next) {
|
||||
if (ob->type == FIRSTPIN) {
|
||||
tsub = LookupCellFile(ob->model.class, file);
|
||||
if (tsub == cell) {
|
||||
|
||||
// Advance ob to property list
|
||||
found = 0;
|
||||
for (ob2 = ob->next; ob2 && ob2->type != FIRSTPIN; ob2 = ob2->next) {
|
||||
if (ob2->type == PROPERTY) {
|
||||
struct valuelist *kv;
|
||||
int i;
|
||||
double dval = 0.0;
|
||||
for (i = 0; ; i++) {
|
||||
kv = &(ob2->instance.props[i]);
|
||||
if (kv->type == PROP_ENDLIST) break;
|
||||
if ((*matchfunc)(kv->key, kl->key)) {
|
||||
switch(kv->type) {
|
||||
case PROP_INTEGER:
|
||||
dval = (double)kv->value.ival;
|
||||
break;
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
dval = kv->value.dval;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* To-do: Account for slop */
|
||||
|
||||
if (dval == value) {
|
||||
switch(kv->type) {
|
||||
case PROP_INTEGER:
|
||||
kv->value.ival /= ndev;
|
||||
found = 1;
|
||||
break;
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
kv->value.dval /= ndev;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found) break;
|
||||
}
|
||||
if (found) {
|
||||
int i;
|
||||
for (i = 1; i < ndev; i++) {
|
||||
ob3 = CopyObjList(ob, 0); // Make exact copy
|
||||
for (nob = ob3; nob->next != NULL; nob = nob->next);
|
||||
nob->next = newdevs;
|
||||
newdevs = ob3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lastob = ob;
|
||||
}
|
||||
lastob->next = newdevs; // Append new devices to list
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Survey a specific device in a cell and sort into a */
|
||||
/* hash by critical property. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
void
|
||||
SurveyDevice(struct nlist *tc, struct hashdict *devdict,
|
||||
struct nlist *cell, struct property *kl,
|
||||
int file1, int file2, int which)
|
||||
{
|
||||
struct objlist *ob, *ob2;
|
||||
struct nlist *tsub, *teq;
|
||||
ECompare *dcomp, *ncomp, *qcomp;
|
||||
int file = (which == 0) ? file1 : file2;
|
||||
int ofile = (which == 0) ? file2 : file1;
|
||||
char *p1str, *p2str, *d1str, *d2str;
|
||||
|
||||
for (ob = tc->cell; ob; ob = ob->next) {
|
||||
if (ob->type == FIRSTPIN) {
|
||||
|
||||
tsub = LookupCellFile(ob->model.class, file);
|
||||
if (tsub == cell) {
|
||||
|
||||
p1str = (char *)MALLOC(strlen(ob->model.class) + 20);
|
||||
sprintf(p1str, "%s", ob->model.class);
|
||||
|
||||
if (tsub->flags & CELL_DUPLICATE) {
|
||||
// Always register a duplicate under the original name
|
||||
d1str = strstr(p1str, "[[");
|
||||
if (d1str) *d1str = '\0';
|
||||
}
|
||||
d1str = p1str + strlen(p1str);
|
||||
sprintf(d1str, "::");
|
||||
d1str += 2;
|
||||
|
||||
teq = LookupClassEquivalent(ob->model.class, file, ofile);
|
||||
p2str = (char *)MALLOC(strlen(teq->name) + 20);
|
||||
sprintf(p2str, "%s", teq->name);
|
||||
|
||||
if (teq->flags & CELL_DUPLICATE) {
|
||||
// Always register a duplicate under the original name
|
||||
d2str = strstr(p2str, "[[");
|
||||
if (d2str) *d2str = '\0';
|
||||
}
|
||||
d2str = p2str + strlen(p2str);
|
||||
sprintf(d2str, "::");
|
||||
d2str += 2;
|
||||
|
||||
// Advance ob to property list
|
||||
// To-do: Quantize values according to slop
|
||||
|
||||
for (ob2 = ob->next; ob2 && ob2->type != FIRSTPIN; ob2 = ob2->next) {
|
||||
if (ob2->type == PROPERTY) {
|
||||
struct valuelist *kv;
|
||||
int i;
|
||||
for (i = 0; ; i++) {
|
||||
kv = &(ob2->instance.props[i]);
|
||||
if (kv->type == PROP_ENDLIST) break;
|
||||
if ((*matchfunc)(kv->key, kl->key)) {
|
||||
switch(kv->type) {
|
||||
case PROP_INTEGER:
|
||||
sprintf(d1str, "%d", kv->value.ival);
|
||||
sprintf(d2str, "%d", kv->value.ival);
|
||||
break;
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
// To-do: Round to tolerance
|
||||
sprintf(d1str, "%g", kv->value.dval);
|
||||
sprintf(d2str, "%g", kv->value.dval);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*d1str == '\0') {
|
||||
// No critical property instanced, so use default
|
||||
switch(kl->type) {
|
||||
case PROP_INTEGER:
|
||||
sprintf(d1str, "%d", kl->pdefault.ival);
|
||||
sprintf(d2str, "%d", kl->pdefault.ival);
|
||||
break;
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
// To-do: Round to tolerance
|
||||
sprintf(d1str, "%g", kl->pdefault.dval);
|
||||
sprintf(d2str, "%g", kl->pdefault.dval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Create hash key from object class and the critical
|
||||
// property affecting the device count.
|
||||
|
||||
dcomp = (ECompare *)HashInt2Lookup(p1str, file, devdict);
|
||||
|
||||
// Fill in the values for this device::property combination
|
||||
|
||||
if (dcomp == NULL) {
|
||||
ncomp = (ECompare *)MALLOC(sizeof(ECompare));
|
||||
if (which == 0) {
|
||||
ncomp->num1 = 1;
|
||||
ncomp->num2 = 0;
|
||||
ncomp->cell1 = tsub;
|
||||
ncomp->cell2 = teq;
|
||||
}
|
||||
else {
|
||||
ncomp->num1 = 0;
|
||||
ncomp->num2 = 1;
|
||||
ncomp->cell2 = tsub;
|
||||
ncomp->cell1 = teq;
|
||||
}
|
||||
ncomp->add1 = 0;
|
||||
ncomp->add2 = 0;
|
||||
ncomp->refcount = (char)1;
|
||||
|
||||
HashInt2PtrInstall(p1str, file, ncomp, devdict);
|
||||
if (teq != NULL) {
|
||||
qcomp = (ECompare *)HashInt2Lookup(p2str, ofile,
|
||||
devdict);
|
||||
if (qcomp == NULL) {
|
||||
HashInt2PtrInstall(p2str, ofile, ncomp, devdict);
|
||||
ncomp->refcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (which == 0)
|
||||
dcomp->num1++;
|
||||
else
|
||||
dcomp->num2++;
|
||||
}
|
||||
|
||||
FREE(p1str);
|
||||
FREE(p2str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Survey the contents of a cell and sort into a hash */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
void
|
||||
SurveyCell(struct nlist *tc, struct hashdict *compdict, int file1, int file2, int which)
|
||||
{
|
||||
struct objlist *ob;
|
||||
struct nlist *tsub, *teq;
|
||||
@@ -1331,8 +1547,7 @@ SurveyCell(struct nlist *tc, struct hashlist **comptab, int file1, int file2, in
|
||||
else dstr = NULL;
|
||||
|
||||
teq = LookupClassEquivalent(ob->model.class, file, ofile);
|
||||
ecomp = (ECompare *)HashInt2Lookup(ob->model.class, file,
|
||||
comptab, OBJHASHSIZE);
|
||||
ecomp = (ECompare *)HashInt2Lookup(ob->model.class, file, compdict);
|
||||
|
||||
if (ecomp == NULL) {
|
||||
ncomp = (ECompare *)MALLOC(sizeof(ECompare));
|
||||
@@ -1352,19 +1567,16 @@ SurveyCell(struct nlist *tc, struct hashlist **comptab, int file1, int file2, in
|
||||
ncomp->add2 = 0;
|
||||
ncomp->refcount = (char)1;
|
||||
|
||||
HashInt2PtrInstall(ob->model.class, file, ncomp, comptab,
|
||||
OBJHASHSIZE);
|
||||
HashInt2PtrInstall(ob->model.class, file, ncomp, compdict);
|
||||
if (teq != NULL) {
|
||||
char *bstr = NULL;
|
||||
if (teq->flags & CELL_DUPLICATE) {
|
||||
bstr = strstr(teq->name, "[[");
|
||||
if (bstr) *bstr = '\0';
|
||||
}
|
||||
qcomp = (ECompare *)HashInt2Lookup(teq->name, ofile,
|
||||
comptab, OBJHASHSIZE);
|
||||
qcomp = (ECompare *)HashInt2Lookup(teq->name, ofile, compdict);
|
||||
if (qcomp == NULL) {
|
||||
HashInt2PtrInstall(teq->name, ofile, ncomp, comptab,
|
||||
OBJHASHSIZE);
|
||||
HashInt2PtrInstall(teq->name, ofile, ncomp, compdict);
|
||||
ncomp->refcount++;
|
||||
}
|
||||
if (bstr) *bstr = '[';
|
||||
@@ -1393,7 +1605,7 @@ SurveyCell(struct nlist *tc, struct hashlist **comptab, int file1, int file2, in
|
||||
/* */
|
||||
/* If there is a mismatch between instances of low- */
|
||||
/* level devices, determine if the mismatches can be */
|
||||
/* resolved by parallel/serial combining, accoring to */
|
||||
/* resolved by parallel/serial combining, according to */
|
||||
/* combination rules. */
|
||||
/* */
|
||||
/* Return the number of modifications made. */
|
||||
@@ -1404,7 +1616,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
{
|
||||
struct nlist *tc1, *tc2, *tsub1, *tsub2;
|
||||
struct objlist *ob1, *ob2, *lob;
|
||||
struct hashlist **comptab;
|
||||
struct hashdict compdict;
|
||||
ECompare *ecomp, *ncomp;
|
||||
ECompList *list0X, *listX0;
|
||||
int match, modified = 0;
|
||||
@@ -1421,14 +1633,13 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
|
||||
if (tc1 == NULL || tc2 == NULL) return;
|
||||
|
||||
comptab = (struct hashlist **)CALLOC(OBJHASHSIZE,
|
||||
sizeof(struct hashlist *));
|
||||
InitializeHashTable(&compdict, OBJHASHSIZE);
|
||||
|
||||
// Gather information about instances of cell "name1"
|
||||
SurveyCell(tc1, comptab, file1, file2, 0);
|
||||
SurveyCell(tc1, &compdict, file1, file2, 0);
|
||||
|
||||
// Gather information about instances of cell "name2"
|
||||
SurveyCell(tc2, comptab, file1, file2, 1);
|
||||
SurveyCell(tc2, &compdict, file1, file2, 1);
|
||||
|
||||
// Find all instances of one cell that have fewer in
|
||||
// the compared circuit. Check whether subcircuits
|
||||
@@ -1436,7 +1647,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
// or subcircuits that have more in the compared circuit.
|
||||
|
||||
listX0 = list0X = NULL;
|
||||
ecomp = (ECompare *)HashFirst(comptab, OBJHASHSIZE);
|
||||
ecomp = (ECompare *)HashFirst(&compdict);
|
||||
while (ecomp != NULL) {
|
||||
|
||||
/* Case 1: Both cell1 and cell2 classes are subcircuits, */
|
||||
@@ -1452,7 +1663,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
for (ob2 = ecomp->cell2->cell; ob2; ob2 = ob2->next) {
|
||||
if (ob2->type == FIRSTPIN) {
|
||||
ncomp = (ECompare *)HashInt2Lookup(ob2->model.class,
|
||||
ecomp->cell2->file, comptab, OBJHASHSIZE);
|
||||
ecomp->cell2->file, &compdict);
|
||||
if (ncomp != NULL) {
|
||||
if ((ncomp->num1 > ncomp->num2) &&
|
||||
((ncomp->add2 + ecomp->num2) >=
|
||||
@@ -1498,8 +1709,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
for (ob2 = ecomp->cell2->cell; ob2; ob2 = ob2->next) {
|
||||
if (ob2->type == FIRSTPIN) {
|
||||
ncomp = (ECompare *)HashInt2Lookup(ob2->model.class,
|
||||
ecomp->cell2->file, comptab,
|
||||
OBJHASHSIZE);
|
||||
ecomp->cell2->file, &compdict);
|
||||
if (ncomp != NULL) {
|
||||
if (match) {
|
||||
ncomp->num1 += ncomp->add1;
|
||||
@@ -1549,7 +1759,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
for (ob2 = ecomp->cell2->cell; ob2; ob2 = ob2->next) {
|
||||
if (ob2->type == FIRSTPIN) {
|
||||
ncomp = (ECompare *)HashInt2Lookup(ob2->model.class,
|
||||
ecomp->cell2->file, comptab, OBJHASHSIZE);
|
||||
ecomp->cell2->file, &compdict);
|
||||
if (ncomp != NULL) {
|
||||
if ((ncomp->num1 > ncomp->num2) &&
|
||||
((ncomp->add2 + ecomp->num2) <=
|
||||
@@ -1582,8 +1792,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
for (ob2 = ecomp->cell2->cell; ob2; ob2 = ob2->next) {
|
||||
if (ob2->type == FIRSTPIN) {
|
||||
ncomp = (ECompare *)HashInt2Lookup(ob2->model.class,
|
||||
ecomp->cell2->file, comptab,
|
||||
OBJHASHSIZE);
|
||||
ecomp->cell2->file, &compdict);
|
||||
if (ncomp != NULL) {
|
||||
if (match) {
|
||||
ncomp->num2 += ncomp->add2;
|
||||
@@ -1608,7 +1817,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
for (ob2 = ecomp->cell1->cell; ob2; ob2 = ob2->next) {
|
||||
if (ob2->type == FIRSTPIN) {
|
||||
ncomp = (ECompare *)HashInt2Lookup(ob2->model.class,
|
||||
ecomp->cell1->file, comptab, OBJHASHSIZE);
|
||||
ecomp->cell1->file, &compdict);
|
||||
if (ncomp != NULL) {
|
||||
if ((ncomp->num2 > ncomp->num1) &&
|
||||
((ncomp->add1 + ecomp->num1) <=
|
||||
@@ -1641,8 +1850,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
for (ob2 = ecomp->cell1->cell; ob2; ob2 = ob2->next) {
|
||||
if (ob2->type == FIRSTPIN) {
|
||||
ncomp = (ECompare *)HashInt2Lookup(ob2->model.class,
|
||||
ecomp->cell1->file, comptab,
|
||||
OBJHASHSIZE);
|
||||
ecomp->cell1->file, &compdict);
|
||||
if (ncomp != NULL) {
|
||||
if (match) {
|
||||
ncomp->num1 += ncomp->add1;
|
||||
@@ -1656,13 +1864,183 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
ecomp->add1 = 0;
|
||||
}
|
||||
ecomp = (ECompare *)HashNext(comptab, OBJHASHSIZE);
|
||||
ecomp = (ECompare *)HashNext(&compdict);
|
||||
}
|
||||
|
||||
// Check for cells, either low-level devices or subcircuits,
|
||||
// that have properties allowing devices to be merged. If
|
||||
// the classes of both cells are the same, and the number of
|
||||
// instances is different, and merging the device with more
|
||||
// instances improves the matching, then perform the merge.
|
||||
|
||||
ecomp = (ECompare *)HashFirst(&compdict);
|
||||
while (ecomp != NULL) {
|
||||
|
||||
if ((ecomp->num1 != ecomp->num2) &&
|
||||
(ecomp->cell1 != NULL) &&
|
||||
(ecomp->cell2 != NULL) &&
|
||||
(ecomp->cell1->classhash == ecomp->cell2->classhash)) {
|
||||
|
||||
struct hashdict devdict;
|
||||
ECompare *dcomp;
|
||||
|
||||
// Determine if either device has mergeable properties. If so,
|
||||
// sort the device into bins by critical (mergeable) property,
|
||||
// and merge devices where merging makes a better match.
|
||||
|
||||
struct property *kl1, *kl2;
|
||||
double slop = 0.0;
|
||||
|
||||
// Look for a mergeable property in cell1
|
||||
|
||||
kl1 = (struct property *)HashFirst(&(ecomp->cell1->propdict));
|
||||
while (kl1 != NULL) {
|
||||
if (kl1->merge == MERGE_ADD_CRIT || kl1->merge == MERGE_PAR_CRIT)
|
||||
break;
|
||||
kl1 = (struct property *)HashNext(&(ecomp->cell1->propdict));
|
||||
}
|
||||
|
||||
// Look for the equivalent property in cell2 (mergeable or not).
|
||||
// If cell1 had no mergeable properties, then look for one is cell2.
|
||||
|
||||
kl2 = (struct property *)HashFirst(&(ecomp->cell2->propdict));
|
||||
while (kl2 != NULL) {
|
||||
if (kl1 != NULL) {
|
||||
if ((*matchfunc)(kl1->key, kl2->key))
|
||||
break;
|
||||
}
|
||||
else if (kl2->merge == MERGE_ADD_CRIT || kl2->merge == MERGE_PAR_CRIT)
|
||||
break;
|
||||
kl2 = (struct property *)HashNext(&(ecomp->cell2->propdict));
|
||||
}
|
||||
if (kl2 != NULL) {
|
||||
// Get slop value
|
||||
switch (kl2->type) {
|
||||
case PROP_INTEGER:
|
||||
slop = (double)kl2->slop.ival;
|
||||
break;
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
slop = kl2->slop.dval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If cell2 had a mergeable property but cell1 didn't, then look
|
||||
// through cell1 again to find the equivalent property.
|
||||
|
||||
if ((kl1 == NULL) && (kl2 != NULL)) {
|
||||
kl1 = (struct property *)HashFirst(&(ecomp->cell1->propdict));
|
||||
while (kl1 != NULL) {
|
||||
if ((*matchfunc)(kl1->key, kl2->key))
|
||||
break;
|
||||
kl1 = (struct property *)HashNext(&(ecomp->cell1->propdict));
|
||||
}
|
||||
}
|
||||
if (kl1 != NULL) {
|
||||
// Get slop value
|
||||
switch (kl1->type) {
|
||||
case PROP_INTEGER:
|
||||
slop = MAX(slop, (double)kl1->slop.ival);
|
||||
break;
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
slop = MAX(slop, kl1->slop.dval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((kl1 != NULL) && (kl2 != NULL)) {
|
||||
|
||||
double dval, dval1, dval2, mindev, pd, df, dr;
|
||||
unsigned char dosplit;
|
||||
char *valptr;
|
||||
int ndev;
|
||||
|
||||
// Create the device hash table
|
||||
|
||||
InitializeHashTable(&devdict, OBJHASHSIZE);
|
||||
|
||||
// Populate the device hash table
|
||||
|
||||
SurveyDevice(tc1, &devdict, ecomp->cell1, kl1, file1, file2, 0);
|
||||
SurveyDevice(tc2, &devdict, ecomp->cell2, kl2, file1, file2, 1);
|
||||
|
||||
// Scan the device hash table. If devices can be merged
|
||||
// and this improves the matching between cells, then do
|
||||
// the merge.
|
||||
|
||||
mindev = 1E20;
|
||||
dval1 = dval2 = 0.0;
|
||||
|
||||
dcomp = (ECompare *)HashFirst(&devdict);
|
||||
while (dcomp != NULL) {
|
||||
if ((dcomp->num1 == 0) || (dcomp->num2 == 0)) {
|
||||
valptr = strstr(devdict.hashfirstptr->name, "::");
|
||||
if (sscanf(valptr + 2, "%lg", &dval) == 1) {
|
||||
if (dval < mindev) mindev = dval;
|
||||
if (dcomp->num1 == 0)
|
||||
dval2 += (dval * dcomp->num2) / dcomp->refcount;
|
||||
else
|
||||
dval1 += (dval * dcomp->num1) / dcomp->refcount;
|
||||
}
|
||||
}
|
||||
dcomp = (ECompare *)HashNext(&devdict);
|
||||
}
|
||||
|
||||
// If dval2 and dval1 agree within slop, and both are
|
||||
// divisible by mindev, then break up all devices into
|
||||
// sizes of mindev.
|
||||
|
||||
dosplit = 0;
|
||||
pd = 2 * fabs(dval1 - dval2) / (dval1 + dval2);
|
||||
if (pd < slop) {
|
||||
df = dval1 / mindev;
|
||||
dr = round(df);
|
||||
pd = 2 * fabs(df - dr) / (df + dr);
|
||||
if (pd < slop) dosplit = 1;
|
||||
}
|
||||
|
||||
if (dosplit) {
|
||||
dcomp = (ECompare *)HashFirst(&devdict);
|
||||
while (dcomp != NULL) {
|
||||
if (dcomp->num1 == 0 || dcomp->num2 == 0) {
|
||||
valptr = strstr(devdict.hashfirstptr->name, "::");
|
||||
sscanf(valptr + 2, "%lg", &dval);
|
||||
ndev = (int)round(dval / mindev);
|
||||
}
|
||||
if (dcomp->num1 == 0) {
|
||||
SplitDevice(tc2, ecomp->cell2, kl2, dval, ndev,
|
||||
file1, file2, 1);
|
||||
modified++;
|
||||
}
|
||||
else if (dcomp->num2 == 0) {
|
||||
SplitDevice(tc1, ecomp->cell1, kl1, dval, ndev,
|
||||
file1, file2, 0);
|
||||
modified++;
|
||||
}
|
||||
dcomp = (ECompare *)HashNext(&devdict);
|
||||
}
|
||||
}
|
||||
|
||||
// Free the device hash table
|
||||
|
||||
dcomp = (ECompare *)HashFirst(&devdict);
|
||||
while (dcomp != NULL) {
|
||||
if (--dcomp->refcount == (char)0) FREE(dcomp);
|
||||
dcomp = (ECompare *)HashNext(&devdict);
|
||||
}
|
||||
HashKill(&devdict);
|
||||
}
|
||||
}
|
||||
|
||||
ecomp = (ECompare *)HashNext(&compdict);
|
||||
}
|
||||
|
||||
// Remove non-matching zero-value devices. This can
|
||||
// be done on a per-instance basis.
|
||||
|
||||
ecomp = (ECompare *)HashFirst(comptab, OBJHASHSIZE);
|
||||
ecomp = (ECompare *)HashFirst(&compdict);
|
||||
while (ecomp != NULL) {
|
||||
if ((ecomp->num1 != ecomp->num2) && (ecomp->cell1 != NULL) &&
|
||||
(ecomp->cell1->class == CLASS_RES)) {
|
||||
@@ -1869,7 +2247,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
}
|
||||
}
|
||||
ecomp = (ECompare *)HashNext(comptab, OBJHASHSIZE);
|
||||
ecomp = (ECompare *)HashNext(&compdict);
|
||||
}
|
||||
|
||||
// Finally, check all entries in listX0 vs. all entries in list0X to see
|
||||
@@ -1901,7 +2279,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
if (dstr) *dstr = '\0';
|
||||
}
|
||||
ncomp = (ECompare *)HashInt2Lookup(ob1->model.class,
|
||||
ecompX0->cell1->file, comptab, OBJHASHSIZE);
|
||||
ecompX0->cell1->file, &compdict);
|
||||
if (dstr) *dstr = '[';
|
||||
if ((ncomp == ecomp0X) && (ecomp0X->num2 <= ecompX0->num1)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
@@ -1927,7 +2305,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
if (dstr) *dstr = '\0';
|
||||
}
|
||||
ncomp = (ECompare *)HashInt2Lookup(ob2->model.class,
|
||||
ecomp0X->cell2->file, comptab, OBJHASHSIZE);
|
||||
ecomp0X->cell2->file, &compdict);
|
||||
if (dstr) *dstr = '[';
|
||||
if ((ncomp == ecompX0) && (ecompX0->num1 <= ecomp0X->num2)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
@@ -1948,13 +2326,12 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
|
||||
// Free the hash table and its contents.
|
||||
|
||||
ecomp = (ECompare *)HashFirst(comptab, OBJHASHSIZE);
|
||||
ecomp = (ECompare *)HashFirst(&compdict);
|
||||
while (ecomp != NULL) {
|
||||
if (--ecomp->refcount == (char)0) FREE(ecomp);
|
||||
ecomp = (ECompare *)HashNext(comptab, OBJHASHSIZE);
|
||||
ecomp = (ECompare *)HashNext(&compdict);
|
||||
}
|
||||
HashKill(comptab, OBJHASHSIZE);
|
||||
FREE(comptab);
|
||||
HashKill(&compdict);
|
||||
|
||||
// Free the 0:X and X:0 lists
|
||||
while (listX0 != NULL) {
|
||||
|
||||
+85
-78
@@ -33,22 +33,25 @@ unsigned long (*hashfunc)(char *, int) = NULL;
|
||||
int (*matchfunc)(char *, char *) = NULL;
|
||||
int (*matchintfunc)(char *, char *, int, int) = NULL;
|
||||
|
||||
void InitializeHashTable(struct hashlist **tab, int size)
|
||||
void InitializeHashTable(struct hashdict *dict, int size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < size; i++) tab[i] = NULL;
|
||||
struct hashlist **hashtab;
|
||||
|
||||
dict->hashtab = (struct hashlist **)CALLOC(size, sizeof(struct hashlist *));
|
||||
dict->hashsize = size;
|
||||
dict->hashfirstindex = 0;
|
||||
dict->hashfirstptr = NULL;
|
||||
}
|
||||
|
||||
int RecurseHashTable(struct hashlist **hashtab, int hashsize,
|
||||
int (*func)(struct hashlist *elem))
|
||||
int RecurseHashTable(struct hashdict *dict, int (*func)(struct hashlist *elem))
|
||||
/* returns the sum of the return values of (*func) */
|
||||
{
|
||||
int i, sum;
|
||||
struct hashlist *p;
|
||||
|
||||
sum = 0;
|
||||
for (i = 0; i < hashsize; i++)
|
||||
for (p = hashtab[i]; p != NULL; p = p->next)
|
||||
for (i = 0; i < dict->hashsize; i++)
|
||||
for (p = dict->hashtab[i]; p != NULL; p = p->next)
|
||||
sum += (*func)(p);
|
||||
return(sum);
|
||||
}
|
||||
@@ -57,15 +60,15 @@ int RecurseHashTable(struct hashlist **hashtab, int hashsize,
|
||||
* type int value to the function.
|
||||
*/
|
||||
|
||||
int RecurseHashTableValue(struct hashlist **hashtab, int hashsize,
|
||||
int RecurseHashTableValue(struct hashdict *dict,
|
||||
int (*func)(struct hashlist *elem, int), int value)
|
||||
{
|
||||
int i, sum;
|
||||
struct hashlist *p;
|
||||
|
||||
sum = 0;
|
||||
for (i = 0; i < hashsize; i++)
|
||||
for (p = hashtab[i]; p != NULL; p = p->next)
|
||||
for (i = 0; i < dict->hashsize; i++)
|
||||
for (p = dict->hashtab[i]; p != NULL; p = p->next)
|
||||
sum += (*func)(p, value);
|
||||
return(sum);
|
||||
}
|
||||
@@ -76,7 +79,7 @@ int RecurseHashTableValue(struct hashlist **hashtab, int hashsize,
|
||||
* function through that structure.
|
||||
*/
|
||||
|
||||
struct nlist *RecurseHashTablePointer(struct hashlist **hashtab, int hashsize,
|
||||
struct nlist *RecurseHashTablePointer(struct hashdict *dict,
|
||||
struct nlist *(*func)(struct hashlist *elem, void *),
|
||||
void *pointer)
|
||||
{
|
||||
@@ -84,8 +87,8 @@ struct nlist *RecurseHashTablePointer(struct hashlist **hashtab, int hashsize,
|
||||
struct hashlist *p;
|
||||
struct nlist *tp;
|
||||
|
||||
for (i = 0; i < hashsize; i++) {
|
||||
for (p = hashtab[i]; p != NULL; p = p->next) {
|
||||
for (i = 0; i < dict->hashsize; i++) {
|
||||
for (p = dict->hashtab[i]; p != NULL; p = p->next) {
|
||||
tp = (*func)(p, pointer);
|
||||
if (tp != NULL) return tp;
|
||||
}
|
||||
@@ -164,14 +167,14 @@ unsigned long genhash(char *s, int c, int hashsize)
|
||||
/* return the 'ptr' field of the hash table entry, or NULL if not found */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void *HashLookup(char *s, struct hashlist **hashtab, int hashsize)
|
||||
void *HashLookup(char *s, struct hashdict *dict)
|
||||
{
|
||||
struct hashlist *np;
|
||||
unsigned long hashval;
|
||||
|
||||
hashval = (*hashfunc)(s, hashsize);
|
||||
hashval = (*hashfunc)(s, dict->hashsize);
|
||||
|
||||
for (np = hashtab[hashval]; np != NULL; np = np->next)
|
||||
for (np = dict->hashtab[hashval]; np != NULL; np = np->next)
|
||||
if ((*matchfunc)(s, np->name)) return (np->ptr); /* correct match */
|
||||
return (NULL); /* not found */
|
||||
}
|
||||
@@ -183,14 +186,14 @@ void *HashLookup(char *s, struct hashlist **hashtab, int hashsize)
|
||||
/* passed integer value i */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void *HashIntLookup(char *s, int i, struct hashlist **hashtab, int hashsize)
|
||||
void *HashIntLookup(char *s, int i, struct hashdict *dict)
|
||||
{
|
||||
struct hashlist *np;
|
||||
unsigned long hashval;
|
||||
|
||||
hashval = (*hashfunc)(s, hashsize);
|
||||
hashval = (*hashfunc)(s, dict->hashsize);
|
||||
|
||||
for (np = hashtab[hashval]; np != NULL; np = np->next) {
|
||||
for (np = dict->hashtab[hashval]; np != NULL; np = np->next) {
|
||||
if (np->ptr == NULL) {
|
||||
if ((*matchintfunc)(s, np->name, i, -1))
|
||||
return NULL;
|
||||
@@ -209,14 +212,14 @@ void *HashIntLookup(char *s, int i, struct hashlist **hashtab, int hashsize)
|
||||
/* first, then the character string. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void *HashInt2Lookup(char *s, int c, struct hashlist **hashtab, int hashsize)
|
||||
void *HashInt2Lookup(char *s, int c, struct hashdict *dict)
|
||||
{
|
||||
struct hashlist *np;
|
||||
unsigned long hashval;
|
||||
|
||||
hashval = genhash(s, c, hashsize);
|
||||
hashval = genhash(s, c, dict->hashsize);
|
||||
|
||||
for (np = hashtab[hashval]; np != NULL; np = np->next)
|
||||
for (np = dict->hashtab[hashval]; np != NULL; np = np->next)
|
||||
if (!strcmp(s, np->name))
|
||||
return (np->ptr); /* correct match */
|
||||
|
||||
@@ -228,14 +231,13 @@ void *HashInt2Lookup(char *s, int c, struct hashlist **hashtab, int hashsize)
|
||||
/* return the hashlist entry, after (re)initializing its 'ptr' field */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
struct hashlist *HashPtrInstall(char *name, void *ptr,
|
||||
struct hashlist **hashtab, int hashsize)
|
||||
struct hashlist *HashPtrInstall(char *name, void *ptr, struct hashdict *dict)
|
||||
{
|
||||
struct hashlist *np;
|
||||
unsigned long hashval;
|
||||
|
||||
hashval = (*hashfunc)(name,hashsize);
|
||||
for (np = hashtab[hashval]; np != NULL; np = np->next)
|
||||
hashval = (*hashfunc)(name, dict->hashsize);
|
||||
for (np = dict->hashtab[hashval]; np != NULL; np = np->next)
|
||||
if ((*matchfunc)(name, np->name)) {
|
||||
np->ptr = ptr;
|
||||
return (np); /* match found in hash table */
|
||||
@@ -246,8 +248,8 @@ struct hashlist *HashPtrInstall(char *name, void *ptr,
|
||||
return (NULL);
|
||||
if ((np->name = strsave(name)) == NULL) return (NULL);
|
||||
np->ptr = ptr;
|
||||
np->next = hashtab[hashval];
|
||||
return(hashtab[hashval] = np);
|
||||
np->next = dict->hashtab[hashval];
|
||||
return(dict->hashtab[hashval] = np);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
@@ -256,13 +258,13 @@ struct hashlist *HashPtrInstall(char *name, void *ptr,
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
struct hashlist *HashIntPtrInstall(char *name, int value, void *ptr,
|
||||
struct hashlist **hashtab, int hashsize)
|
||||
struct hashdict *dict)
|
||||
{
|
||||
struct hashlist *np;
|
||||
unsigned long hashval;
|
||||
|
||||
hashval = (*hashfunc)(name,hashsize);
|
||||
for (np = hashtab[hashval]; np != NULL; np = np->next)
|
||||
hashval = (*hashfunc)(name, dict->hashsize);
|
||||
for (np = dict->hashtab[hashval]; np != NULL; np = np->next)
|
||||
if ((*matchintfunc)(name, np->name, value, (int)(*((int *)np->ptr)))) {
|
||||
np->ptr = ptr;
|
||||
return (np); /* match found in hash table */
|
||||
@@ -273,8 +275,8 @@ struct hashlist *HashIntPtrInstall(char *name, int value, void *ptr,
|
||||
return (NULL);
|
||||
if ((np->name = strsave(name)) == NULL) return (NULL);
|
||||
np->ptr = ptr;
|
||||
np->next = hashtab[hashval];
|
||||
return(hashtab[hashval] = np);
|
||||
np->next = dict->hashtab[hashval];
|
||||
return(dict->hashtab[hashval] = np);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
@@ -282,13 +284,13 @@ struct hashlist *HashIntPtrInstall(char *name, int value, void *ptr,
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
struct hashlist *HashInt2PtrInstall(char *name, int c, void *ptr,
|
||||
struct hashlist **hashtab, int hashsize)
|
||||
struct hashdict *dict)
|
||||
{
|
||||
struct hashlist *np;
|
||||
unsigned long hashval;
|
||||
|
||||
hashval = genhash(name, c, hashsize);
|
||||
for (np = hashtab[hashval]; np != NULL; np = np->next)
|
||||
hashval = genhash(name, c, dict->hashsize);
|
||||
for (np = dict->hashtab[hashval]; np != NULL; np = np->next)
|
||||
if (!strcmp(name, np->name)) {
|
||||
np->ptr = ptr;
|
||||
return (np); /* match found in hash table */
|
||||
@@ -299,27 +301,31 @@ struct hashlist *HashInt2PtrInstall(char *name, int c, void *ptr,
|
||||
return (NULL);
|
||||
if ((np->name = strsave(name)) == NULL) return (NULL);
|
||||
np->ptr = ptr;
|
||||
np->next = hashtab[hashval];
|
||||
return(hashtab[hashval] = np);
|
||||
np->next = dict->hashtab[hashval];
|
||||
return(dict->hashtab[hashval] = np);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* destroy a hash table, freeing associated memory */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void *HashKill(struct hashlist **hashtab, int hashsize)
|
||||
void *HashKill(struct hashdict *dict)
|
||||
{
|
||||
struct hashlist *np, *p;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < hashsize; i++) {
|
||||
for (p = hashtab[i]; p != NULL; ) {
|
||||
if (dict->hashtab == NULL) return; // Hash not initialized
|
||||
|
||||
for (i = 0; i < dict->hashsize; i++) {
|
||||
for (p = dict->hashtab[i]; p != NULL; ) {
|
||||
np = p->next;
|
||||
FREE(p->name);
|
||||
FREE(p);
|
||||
p = np;
|
||||
}
|
||||
}
|
||||
FREE(dict->hashtab);
|
||||
dict->hashtab = NULL;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
@@ -327,14 +333,13 @@ void *HashKill(struct hashlist **hashtab, int hashsize)
|
||||
/* to the new hash entry. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
struct hashlist *HashInstall(char *name,
|
||||
struct hashlist **hashtab, int hashsize)
|
||||
struct hashlist *HashInstall(char *name, struct hashdict *dict)
|
||||
{
|
||||
struct hashlist *np;
|
||||
unsigned long hashval;
|
||||
|
||||
hashval = (*hashfunc)(name,hashsize);
|
||||
for (np = hashtab[hashval]; np != NULL; np = np->next)
|
||||
hashval = (*hashfunc)(name, dict->hashsize);
|
||||
for (np = dict->hashtab[hashval]; np != NULL; np = np->next)
|
||||
if ((*matchfunc)(name, np->name)) return (np); /* match found in hash table */
|
||||
|
||||
/* not in table, so install it */
|
||||
@@ -342,27 +347,27 @@ struct hashlist *HashInstall(char *name,
|
||||
return (NULL);
|
||||
if ((np->name = strsave(name)) == NULL) return (NULL);
|
||||
np->ptr = NULL;
|
||||
np->next = hashtab[hashval];
|
||||
return(hashtab[hashval] = np);
|
||||
np->next = dict->hashtab[hashval];
|
||||
return(dict->hashtab[hashval] = np);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* frees a hash table entry, (but not the 'ptr' field) */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void HashDelete(char *name, struct hashlist **hashtab, int hashsize)
|
||||
void HashDelete(char *name, struct hashdict *dict)
|
||||
{
|
||||
unsigned long hashval;
|
||||
struct hashlist *np;
|
||||
struct hashlist *np2;
|
||||
|
||||
hashval = (*hashfunc)(name, hashsize);
|
||||
np = hashtab[hashval];
|
||||
hashval = (*hashfunc)(name, dict->hashsize);
|
||||
np = dict->hashtab[hashval];
|
||||
if (np == NULL) return;
|
||||
|
||||
if ((*matchfunc)(name, np->name)) {
|
||||
/* it is the first element in the list */
|
||||
hashtab[hashval] = np->next;
|
||||
dict->hashtab[hashval] = np->next;
|
||||
FREE(np->name);
|
||||
FREE(np);
|
||||
return;
|
||||
@@ -385,19 +390,19 @@ void HashDelete(char *name, struct hashlist **hashtab, int hashsize)
|
||||
/* HashDelete with additional integer value matching */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void HashIntDelete(char *name, int value, struct hashlist **hashtab, int hashsize)
|
||||
void HashIntDelete(char *name, int value, struct hashdict *dict)
|
||||
{
|
||||
unsigned long hashval;
|
||||
struct hashlist *np;
|
||||
struct hashlist *np2;
|
||||
|
||||
hashval = (*hashfunc)(name, hashsize);
|
||||
np = hashtab[hashval];
|
||||
hashval = (*hashfunc)(name, dict->hashsize);
|
||||
np = dict->hashtab[hashval];
|
||||
if (np == NULL) return;
|
||||
|
||||
if ((*matchintfunc)(name, np->name, value, (int)(*((int *)np->ptr)))) {
|
||||
/* it is the first element in the list */
|
||||
hashtab[hashval] = np->next;
|
||||
dict->hashtab[hashval] = np->next;
|
||||
FREE(np->name);
|
||||
FREE(np);
|
||||
return;
|
||||
@@ -417,33 +422,35 @@ void HashIntDelete(char *name, int value, struct hashlist **hashtab, int hashsiz
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Hash key iterator */
|
||||
/* returns 'ptr' field of next element, NULL when done */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
static int hashfirstindex; /* was long */
|
||||
static struct hashlist *hashfirstptr;
|
||||
|
||||
void *HashNext(struct hashlist **hashtab, int hashsize)
|
||||
/* returns 'ptr' field of next element, NULL when done */
|
||||
void *HashNext(struct hashdict *dict)
|
||||
{
|
||||
if (hashfirstptr != NULL && hashfirstptr->next != NULL) {
|
||||
hashfirstptr = hashfirstptr->next;
|
||||
return(hashfirstptr->ptr);
|
||||
}
|
||||
while (hashfirstindex < hashsize) {
|
||||
if ((hashfirstptr = hashtab[hashfirstindex++]) != NULL) {
|
||||
return(hashfirstptr->ptr);
|
||||
}
|
||||
}
|
||||
hashfirstindex = 0;
|
||||
hashfirstptr = NULL;
|
||||
return(NULL);
|
||||
if (dict->hashfirstptr != NULL && dict->hashfirstptr->next != NULL) {
|
||||
dict->hashfirstptr = dict->hashfirstptr->next;
|
||||
return(dict->hashfirstptr->ptr);
|
||||
}
|
||||
while (dict->hashfirstindex < dict->hashsize) {
|
||||
if ((dict->hashfirstptr = dict->hashtab[dict->hashfirstindex++]) != NULL) {
|
||||
return(dict->hashfirstptr->ptr);
|
||||
}
|
||||
}
|
||||
|
||||
dict->hashfirstindex = 0;
|
||||
dict->hashfirstptr = NULL;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
void *HashFirst(struct hashlist **hashtab, int hashsize)
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Hash key iterator setup */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void *HashFirst(struct hashdict *dict)
|
||||
{
|
||||
hashfirstindex = 0;
|
||||
hashfirstptr = NULL;
|
||||
return(HashNext(hashtab,hashsize));
|
||||
dict->hashfirstindex = 0;
|
||||
dict->hashfirstptr = NULL;
|
||||
return HashNext(dict);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+25
-19
@@ -7,38 +7,44 @@ struct hashlist {
|
||||
struct hashlist *next;
|
||||
};
|
||||
|
||||
extern void InitializeHashTable(struct hashlist **tab, int size);
|
||||
extern int RecurseHashTable(struct hashlist **hashtab, int hashsize,
|
||||
struct hashdict {
|
||||
int hashsize;
|
||||
int hashfirstindex;
|
||||
struct hashlist *hashfirstptr;
|
||||
struct hashlist **hashtab;
|
||||
};
|
||||
|
||||
|
||||
extern void InitializeHashTable(struct hashdict *dict, int size);
|
||||
extern int RecurseHashTable(struct hashdict *dict,
|
||||
int (*func)(struct hashlist *elem));
|
||||
extern int RecurseHashTableValue(struct hashlist **hashtab, int hashsize,
|
||||
extern int RecurseHashTableValue(struct hashdict *dict,
|
||||
int (*func)(struct hashlist *elem, int), int);
|
||||
extern struct nlist *RecurseHashTablePointer(struct hashlist **hashtab,
|
||||
int hashsize, struct nlist *(*func)(struct hashlist *elem,
|
||||
void *), void *pointer);
|
||||
extern struct nlist *RecurseHashTablePointer(struct hashdict *dict,
|
||||
struct nlist *(*func)(struct hashlist *elem, void *),
|
||||
void *pointer);
|
||||
extern void HashDelete(char *name, struct hashdict *dict);
|
||||
extern void HashIntDelete(char *name, int value, struct hashdict *dict);
|
||||
|
||||
|
||||
extern int CountHashTableEntries(struct hashlist *p);
|
||||
extern int CountHashTableBinsUsed(struct hashlist *p);
|
||||
extern void HashDelete(char *name, struct hashlist **hashtab, int hashsize);
|
||||
extern void HashIntDelete(char *name, int value, struct hashlist **hashtab,
|
||||
int hashsize);
|
||||
|
||||
/* these functions return a pointer to a hash list element */
|
||||
extern struct hashlist *HashInstall(char *name, struct hashlist **hashtab,
|
||||
int hashsize);
|
||||
extern struct hashlist *HashInstall(char *name, struct hashdict *dict);
|
||||
extern struct hashlist *HashPtrInstall(char *name, void *ptr,
|
||||
struct hashlist **hashtab, int hashsize);
|
||||
struct hashdict *dict);
|
||||
extern struct hashlist *HashIntPtrInstall(char *name, int value, void *ptr,
|
||||
struct hashlist **hashtab, int hashsize);
|
||||
struct hashdict *dict);
|
||||
extern struct hashlist *HashInt2PtrInstall(char *name, int c, void *ptr,
|
||||
struct hashlist **hashtab, int hashsize);
|
||||
struct hashdict *dict);
|
||||
|
||||
/* these functions return the ->ptr field of a struct hashlist */
|
||||
extern void *HashLookup(char *s, struct hashlist **hashtab, int hashsize);
|
||||
extern void *HashIntLookup(char *s, int i, struct hashlist **hashtab, int hashsize);
|
||||
extern void *HashInt2Lookup(char *s, int c, struct hashlist **hashtab, int hashsize);
|
||||
extern void *HashFirst(struct hashlist **hashtab, int hashsize);
|
||||
extern void *HashNext(struct hashlist **hashtab, int hashsize);
|
||||
extern void *HashLookup(char *s, struct hashdict *dict);
|
||||
extern void *HashIntLookup(char *s, int i, struct hashdict *dict);
|
||||
extern void *HashInt2Lookup(char *s, int c, struct hashdict *dict);
|
||||
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);
|
||||
|
||||
+17
-12
@@ -3319,7 +3319,7 @@ int PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print)
|
||||
if (vl2->type == PROP_ENDLIST) break;
|
||||
if (vl2 == NULL) continue;
|
||||
if (vl2->key == NULL) continue;
|
||||
kl2 = (struct property *)HashLookup(vl2->key, tc2->proptab, OBJHASHSIZE);
|
||||
kl2 = (struct property *)HashLookup(vl2->key, &(tc2->propdict));
|
||||
if (kl2 != NULL) break; // Property is required
|
||||
else if ((*matchfunc)(vl2->key, "M")) {
|
||||
if (vl2->type == PROP_INTEGER)
|
||||
@@ -3344,7 +3344,7 @@ int PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print)
|
||||
if (vl1->type == PROP_ENDLIST) break;
|
||||
if (vl1 == NULL) continue;
|
||||
if (vl1->key == NULL) continue;
|
||||
kl1 = (struct property *)HashLookup(vl1->key, tc1->proptab, OBJHASHSIZE);
|
||||
kl1 = (struct property *)HashLookup(vl1->key, &(tc1->propdict));
|
||||
if (kl1 != NULL) break; // Property is required
|
||||
else if ((*matchfunc)(vl1->key, "M")) {
|
||||
if (vl1->type == PROP_INTEGER)
|
||||
@@ -3369,7 +3369,7 @@ int PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print)
|
||||
if (vl1->key == NULL) continue;
|
||||
|
||||
/* Check if this is a "property of interest". */
|
||||
kl1 = (struct property *)HashLookup(vl1->key, tc1->proptab, OBJHASHSIZE);
|
||||
kl1 = (struct property *)HashLookup(vl1->key, &(tc1->propdict));
|
||||
if (kl1 == NULL) continue;
|
||||
|
||||
/* Find the matching property in vl2. With luck, they're in order. */
|
||||
@@ -3386,7 +3386,7 @@ int PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print)
|
||||
if (vl2->key == NULL) continue;
|
||||
|
||||
/* Both device classes must agree on the properties to compare */
|
||||
kl2 = (struct property *)HashLookup(vl2->key, tc2->proptab, OBJHASHSIZE);
|
||||
kl2 = (struct property *)HashLookup(vl2->key, &(tc2->propdict));
|
||||
if (kl2 == NULL) continue;
|
||||
|
||||
/* Watch out for uninitialized entries in cell def */
|
||||
@@ -4476,6 +4476,11 @@ int reorderpins(struct hashlist *p, int file)
|
||||
}
|
||||
ob = ob->next;
|
||||
ob2 = ob2->next;
|
||||
if (ob == NULL) {
|
||||
Fprintf(stderr, "Instance of %s has only %d of %d ports\n",
|
||||
tc2->name, i + 1, numports);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ob = firstpin;
|
||||
@@ -4488,9 +4493,10 @@ int reorderpins(struct hashlist *p, int file)
|
||||
ob->node = nodes[i];
|
||||
ob->name = names[i];
|
||||
}
|
||||
HashPtrInstall(ob->name, ob, ptr->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(ob->name, ob, &(ptr->objdict));
|
||||
ob = ob->next;
|
||||
names[i] = NULL;
|
||||
if (ob == NULL) break; // Error message already output
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -4566,12 +4572,11 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata)
|
||||
lob = obn;
|
||||
|
||||
// Hash the new pin record for "LookupObject()"
|
||||
HashPtrInstall(obn->name, obn, ptr->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(obn->name, obn, &(ptr->objdict));
|
||||
|
||||
if (tob == tc->cell) {
|
||||
// Rehash the instance in insttab
|
||||
HashPtrInstall(firstpin->instance.name, firstpin,
|
||||
ptr->insttab, OBJHASHSIZE);
|
||||
// Rehash the instance in instdict
|
||||
HashPtrInstall(firstpin->instance.name, firstpin, &(ptr->instdict));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -4595,7 +4600,7 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata)
|
||||
obn->next = NULL;
|
||||
lob->next = obn;
|
||||
lob = obn;
|
||||
HashPtrInstall(obn->name, obn, ptr->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(obn->name, obn, &(ptr->objdict));
|
||||
}
|
||||
|
||||
// We messed with the node name list, so have to re-cache them
|
||||
@@ -4888,7 +4893,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2)
|
||||
ob1 = obn;
|
||||
hasproxy1 = 1;
|
||||
|
||||
HashPtrInstall(obn->name, obn, tc1->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(obn->name, obn, &(tc1->objdict));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4946,7 +4951,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2)
|
||||
ob2 = obn;
|
||||
hasproxy2 = 1;
|
||||
|
||||
HashPtrInstall(obn->name, obn, tc2->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(obn->name, obn, &(tc2->objdict));
|
||||
}
|
||||
|
||||
else if (ob1 != NULL && ob1->type == PORT) {
|
||||
|
||||
+147
-74
@@ -54,7 +54,7 @@ extern int errno; /* Defined in stdlib.h */
|
||||
static char staticstrings[MAX_STATIC_STRINGS][200];
|
||||
static int laststring;
|
||||
|
||||
extern struct hashlist **spiceparams; /* From spice.c */
|
||||
extern struct hashdict spiceparams; /* From spice.c */
|
||||
|
||||
char *Str(char *format, ...)
|
||||
{
|
||||
@@ -168,12 +168,18 @@ struct tokstack *CopyTokStack(struct tokstack *stack)
|
||||
/* value was successfully converted, 0 if there was no value to */
|
||||
/* convert (empty string), and -1 if unable to convert the */
|
||||
/* string to a value (e.g., unknown parameter name). */
|
||||
/* */
|
||||
/* Inheritance is taken from "parprops" (instanced property */
|
||||
/* values) if available, and from parent->propdict if not, or */
|
||||
/* if the property is not instanced. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
int TokGetValue(char *estr, struct nlist *parent, int glob, double *dval)
|
||||
int TokGetValue(char *estr, struct nlist *parent, struct objlist *parprops,
|
||||
int glob, double *dval)
|
||||
{
|
||||
struct property *kl = NULL;
|
||||
int result;
|
||||
struct valuelist *kv;
|
||||
int i, result;
|
||||
|
||||
if (*estr == '\0') return 0;
|
||||
|
||||
@@ -188,32 +194,57 @@ int TokGetValue(char *estr, struct nlist *parent, int glob, double *dval)
|
||||
|
||||
if (glob == TRUE) {
|
||||
/* Check global parameters */
|
||||
if (spiceparams != NULL) {
|
||||
kl = (struct property *)HashLookup(estr,
|
||||
spiceparams, OBJHASHSIZE);
|
||||
if (kl != NULL) {
|
||||
result = ConvertStringToFloat(kl->pdefault.string, dval);
|
||||
return ((result == 0) ? -1 : 1);
|
||||
kl = (struct property *)HashLookup(estr, &spiceparams);
|
||||
if (kl != NULL) {
|
||||
result = ConvertStringToFloat(kl->pdefault.string, dval);
|
||||
return ((result == 0) ? -1 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check local instanced parameters */
|
||||
result = 0;
|
||||
if ((parprops != NULL) && (parprops->type == PROPERTY)) {
|
||||
for (i = 0; ; i++) {
|
||||
kv = &(parprops->instance.props[i]);
|
||||
if (kv->type == PROP_ENDLIST) break;
|
||||
else if ((*matchfunc)(estr, kv->key)) {
|
||||
switch (kv->type) {
|
||||
case PROP_STRING:
|
||||
result = ConvertStringToFloat(kv->value.string, dval);
|
||||
break;
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
*dval = kv->value.dval;
|
||||
result = 1;
|
||||
break;
|
||||
case PROP_INTEGER:
|
||||
*dval = (double)kv->value.ival;
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check local parameters */
|
||||
kl = (struct property *)HashLookup(estr, parent->proptab, OBJHASHSIZE);
|
||||
if (kl != NULL) {
|
||||
switch(kl->type) {
|
||||
case PROP_STRING:
|
||||
result = ConvertStringToFloat(kl->pdefault.string, dval);
|
||||
break;
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
*dval = kl->pdefault.dval;
|
||||
result = 1;
|
||||
break;
|
||||
case PROP_INTEGER:
|
||||
*dval = (double)kl->pdefault.ival;
|
||||
result = 1;
|
||||
break;
|
||||
/* Check local parent parameters */
|
||||
if (result == 0) {
|
||||
kl = (struct property *)HashLookup(estr, &(parent->propdict));
|
||||
if (kl != NULL) {
|
||||
switch(kl->type) {
|
||||
case PROP_STRING:
|
||||
result = ConvertStringToFloat(kl->pdefault.string, dval);
|
||||
break;
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
*dval = kl->pdefault.dval;
|
||||
result = 1;
|
||||
break;
|
||||
case PROP_INTEGER:
|
||||
*dval = (double)kl->pdefault.ival;
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ((result == 0) ? -1 : 1);
|
||||
@@ -231,14 +262,14 @@ int TokGetValue(char *estr, struct nlist *parent, int glob, double *dval)
|
||||
/* single value, then replace the property type. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
int ReduceExpressions(struct objlist *instprop,
|
||||
int ReduceExpressions(struct objlist *instprop, struct objlist *parprops,
|
||||
struct nlist *parent, int glob) {
|
||||
|
||||
struct tokstack *expstack, *stackptr, *lptr, *nptr;
|
||||
struct valuelist *kv;
|
||||
struct property *kl = NULL;
|
||||
char *estr, *tstr, *sstr;
|
||||
int toktype, functype, i, result, modified, numlast;
|
||||
int toktype, functype, i, result, modified, numlast, savetok;
|
||||
double dval;
|
||||
|
||||
if (instprop == NULL) return 0; // Nothing to do
|
||||
@@ -248,7 +279,9 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
|
||||
kv = &(instprop->instance.props[i]);
|
||||
|
||||
if (kv->type == PROP_EXPRESSION) {
|
||||
if (kv->type == PROP_ENDLIST)
|
||||
break;
|
||||
else if (kv->type == PROP_EXPRESSION) {
|
||||
expstack = kv->value.stack;
|
||||
}
|
||||
else if (kv->type == PROP_STRING) {
|
||||
@@ -272,7 +305,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
}
|
||||
/* Not a number, so must be arithmetic */
|
||||
*tstr = '\0';
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
PushTok(TOK_PLUS, NULL, &expstack);
|
||||
@@ -292,7 +325,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
}
|
||||
/* Not a number, so must be arithmetic */
|
||||
*tstr = '\0';
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
PushTok(TOK_MINUS, NULL, &expstack);
|
||||
@@ -313,7 +346,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
|
||||
case '/':
|
||||
*tstr = '\0';
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
PushTok(TOK_DIVIDE, NULL, &expstack);
|
||||
@@ -323,7 +356,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
|
||||
case '*':
|
||||
*tstr = '\0';
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
PushTok(TOK_MULTIPLY, NULL, &expstack);
|
||||
@@ -342,7 +375,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
else {
|
||||
/* Treat as a parenthetical grouping */
|
||||
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
PushTok(TOK_FUNC_OPEN, NULL, &expstack);
|
||||
@@ -353,8 +386,15 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
|
||||
case ')':
|
||||
*tstr = '\0';
|
||||
|
||||
if (expstack == NULL) break;
|
||||
switch (expstack->toktype) {
|
||||
savetok = expstack->toktype;
|
||||
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
|
||||
switch (savetok) {
|
||||
case TOK_FUNC_THEN:
|
||||
PushTok(TOK_FUNC_ELSE, NULL, &expstack);
|
||||
break;
|
||||
@@ -368,7 +408,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
|
||||
case '\'':
|
||||
*tstr = '\0';
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
PushTok(TOK_SGL_QUOTE, NULL, &expstack);
|
||||
@@ -378,7 +418,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
|
||||
case '"':
|
||||
*tstr = '\0';
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
PushTok(TOK_DBL_QUOTE, NULL, &expstack);
|
||||
@@ -388,7 +428,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
|
||||
case '{':
|
||||
*tstr = '\0';
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
PushTok(TOK_GROUP_OPEN, NULL, &expstack);
|
||||
@@ -398,7 +438,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
|
||||
case '}':
|
||||
*tstr = '\0';
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
PushTok(TOK_GROUP_CLOSE, NULL, &expstack);
|
||||
estr = tstr + 1;
|
||||
@@ -408,7 +448,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
case '!':
|
||||
if (*(tstr + 1) == '=') {
|
||||
*tstr = '\0';
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
PushTok(TOK_NE, NULL, &expstack);
|
||||
@@ -419,7 +459,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
case '=':
|
||||
if (*(tstr + 1) == '=') {
|
||||
*tstr = '\0';
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
PushTok(TOK_EQ, NULL, &expstack);
|
||||
@@ -429,7 +469,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
|
||||
case '>':
|
||||
*tstr = '\0';
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
|
||||
@@ -445,7 +485,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
|
||||
case '<':
|
||||
*tstr = '\0';
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
|
||||
@@ -461,7 +501,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
|
||||
case ',':
|
||||
*tstr = '\0';
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
if (expstack == NULL) break;
|
||||
@@ -486,7 +526,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
}
|
||||
tstr++;
|
||||
}
|
||||
result = TokGetValue(estr, parent, glob, &dval);
|
||||
result = TokGetValue(estr, parent, parprops, glob, &dval);
|
||||
if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack);
|
||||
else if (result == -1) PushTok(TOK_STRING, estr, &expstack);
|
||||
|
||||
@@ -757,7 +797,7 @@ int ReduceExpressions(struct objlist *instprop,
|
||||
switch (stackptr->toktype) {
|
||||
case TOK_STRING:
|
||||
result = TokGetValue(stackptr->data.string, parent,
|
||||
glob, &dval);
|
||||
parprops, glob, &dval);
|
||||
if (result == 1) {
|
||||
stackptr->toktype = TOK_DOUBLE;
|
||||
FREE(stackptr->data.string);
|
||||
@@ -834,19 +874,17 @@ PropertyDelete(char *name, int fnum, char *key)
|
||||
|
||||
/* key == NULL means delete all properties. */
|
||||
|
||||
RecurseHashTable(tc->proptab, OBJHASHSIZE, freeprop);
|
||||
HashKill(tc->proptab, OBJHASHSIZE);
|
||||
FREE(tc->proptab);
|
||||
tc->proptab = (struct hashlist **)CALLOC(OBJHASHSIZE,
|
||||
sizeof(struct hashlist *));
|
||||
RecurseHashTable(&(tc->propdict), freeprop);
|
||||
HashKill(&(tc->propdict));
|
||||
InitializeHashTable(&(tc->propdict), OBJHASHSIZE);
|
||||
}
|
||||
else {
|
||||
kl = (struct property *)HashLookup(key, tc->proptab, OBJHASHSIZE);
|
||||
kl = (struct property *)HashLookup(key, &(tc->propdict));
|
||||
if (kl != NULL) {
|
||||
if (kl->type == PROP_STRING || kl->type == PROP_EXPRESSION)
|
||||
FREE(kl->pdefault.string);
|
||||
FREE(kl->key);
|
||||
HashDelete(key, tc->proptab, OBJHASHSIZE);
|
||||
HashDelete(key, &(tc->propdict));
|
||||
}
|
||||
else {
|
||||
Printf("No property %s found for device %s\n", key, name);
|
||||
@@ -879,7 +917,7 @@ PropertyTolerance(char *name, int fnum, char *key, int ival, double dval)
|
||||
return -1;
|
||||
}
|
||||
|
||||
kl = (struct property *)HashLookup(key, tc->proptab, OBJHASHSIZE);
|
||||
kl = (struct property *)HashLookup(key, &(tc->propdict));
|
||||
if (kl == NULL) {
|
||||
Printf("No property %s found for device %s\n", key, name);
|
||||
return -1;
|
||||
@@ -900,6 +938,40 @@ PropertyTolerance(char *name, int fnum, char *key, int ival, double dval)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Set the merge type of a property in the master cell record. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
PropertyMerge(char *name, int fnum, char *key, int merge_type)
|
||||
{
|
||||
struct property *kl = NULL;
|
||||
struct nlist *tc;
|
||||
int result;
|
||||
|
||||
if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
|
||||
result = PropertyMerge(name, Circuit1->file, key, merge_type);
|
||||
result = PropertyMerge(name, Circuit2->file, key, merge_type);
|
||||
return result;
|
||||
}
|
||||
|
||||
tc = LookupCellFile(name, fnum);
|
||||
if (tc == NULL) {
|
||||
Printf("No device %s found for PropertyTolerance()\n", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
kl = (struct property *)HashLookup(key, &(tc->propdict));
|
||||
if (kl == NULL) {
|
||||
Printf("No property %s found for device %s\n", key, name);
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
kl->merge = merge_type;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Add a new value property to the indicated cell */
|
||||
/* Value properties are used for resistors and capacitors in SPICE */
|
||||
@@ -923,18 +995,18 @@ struct property *PropertyValue(char *name, int fnum, char *key,
|
||||
tc = LookupCellFile(name, fnum);
|
||||
if (tc == NULL)
|
||||
Printf("No device %s found for PropertyValue()\n", name);
|
||||
else if ((kl = (struct property *)HashLookup(key, tc->proptab,
|
||||
OBJHASHSIZE)) != NULL) {
|
||||
else if ((kl = (struct property *)HashLookup(key, &(tc->propdict))) != NULL) {
|
||||
Printf("Device %s already has property named \"%s\"\n", name, key);
|
||||
}
|
||||
else {
|
||||
kl = NewProperty();
|
||||
kl->key = strsave(key);
|
||||
kl->idx = 0;
|
||||
kl->merge = MERGE_NONE;
|
||||
kl->type = PROP_VALUE;
|
||||
kl->slop.dval = slop;
|
||||
kl->pdefault.dval = pdefault;
|
||||
HashPtrInstall(kl->key, kl, tc->proptab, OBJHASHSIZE);
|
||||
HashPtrInstall(kl->key, kl, &(tc->propdict));
|
||||
}
|
||||
return kl;
|
||||
}
|
||||
@@ -958,18 +1030,18 @@ struct property *PropertyDouble(char *name, int fnum, char *key,
|
||||
tc = LookupCellFile(name, fnum);
|
||||
if (tc == NULL)
|
||||
Printf("No device %s found for PropertyDouble()\n", name);
|
||||
else if ((kl = (struct property *)HashLookup(key, tc->proptab,
|
||||
OBJHASHSIZE)) != NULL) {
|
||||
else if ((kl = (struct property *)HashLookup(key, &(tc->propdict))) != NULL) {
|
||||
Printf("Device %s already has property named \"%s\"\n", name, key);
|
||||
}
|
||||
else {
|
||||
kl = NewProperty();
|
||||
kl->key = strsave(key);
|
||||
kl->idx = 0;
|
||||
kl->merge = MERGE_NONE;
|
||||
kl->type = PROP_DOUBLE;
|
||||
kl->slop.dval = slop;
|
||||
kl->pdefault.dval = pdefault;
|
||||
HashPtrInstall(kl->key, kl, tc->proptab, OBJHASHSIZE);
|
||||
HashPtrInstall(kl->key, kl, &(tc->propdict));
|
||||
}
|
||||
return kl;
|
||||
}
|
||||
@@ -991,18 +1063,18 @@ struct property *PropertyInteger(char *name, int fnum, char *key,
|
||||
tc = LookupCellFile(name, fnum);
|
||||
if (tc == NULL)
|
||||
Printf("No device %s found for PropertyInteger()\n", name);
|
||||
else if ((kl = (struct property *)HashLookup(key, tc->proptab,
|
||||
OBJHASHSIZE)) != NULL) {
|
||||
else if ((kl = (struct property *)HashLookup(key, &(tc->propdict))) != NULL) {
|
||||
Printf("Device %s already has property named \"%s\"\n", name, key);
|
||||
}
|
||||
else {
|
||||
kl = NewProperty();
|
||||
kl->key = strsave(key);
|
||||
kl->idx = 0;
|
||||
kl->merge = MERGE_NONE;
|
||||
kl->type = PROP_INTEGER;
|
||||
kl->slop.ival = slop;
|
||||
kl->pdefault.ival = pdefault;
|
||||
HashPtrInstall(kl->key, kl, tc->proptab, OBJHASHSIZE);
|
||||
HashPtrInstall(kl->key, kl, &(tc->propdict));
|
||||
}
|
||||
return kl;
|
||||
}
|
||||
@@ -1024,21 +1096,21 @@ struct property *PropertyString(char *name, int fnum, char *key, int range,
|
||||
tc = LookupCellFile(name, fnum);
|
||||
if (tc == NULL)
|
||||
Printf("No device %s found for PropertyString()\n", name);
|
||||
else if ((kl = (struct property *)HashLookup(key, tc->proptab,
|
||||
OBJHASHSIZE)) != NULL) {
|
||||
else if ((kl = (struct property *)HashLookup(key, &(tc->propdict))) != NULL) {
|
||||
Printf("Device %s already has property named \"%s\"\n", name, key);
|
||||
}
|
||||
else {
|
||||
kl = NewProperty();
|
||||
kl->key = strsave(key);
|
||||
kl->idx = 0;
|
||||
kl->merge = MERGE_NONE;
|
||||
kl->type = PROP_STRING;
|
||||
kl->slop.ival = (range >= 0) ? range : 0;
|
||||
if (pdefault != NULL)
|
||||
kl->pdefault.string = strsave(pdefault);
|
||||
else
|
||||
kl->pdefault.string = NULL;
|
||||
HashPtrInstall(kl->key, kl, tc->proptab, OBJHASHSIZE);
|
||||
HashPtrInstall(kl->key, kl, &(tc->propdict));
|
||||
}
|
||||
return kl;
|
||||
}
|
||||
@@ -1975,7 +2047,7 @@ struct objlist *LinkProperties(char *model, struct keyvalue *topptr)
|
||||
/* If there is a matching cell, make sure that the property */
|
||||
/* key exists. If not, create it and flag a warning. */
|
||||
|
||||
kl = (struct property *)HashLookup(newkv->key, cell->proptab, OBJHASHSIZE);
|
||||
kl = (struct property *)HashLookup(newkv->key, &(cell->propdict));
|
||||
if (kl == NULL) {
|
||||
/* Ideally, for devices, one should check against all */
|
||||
/* known standard properties. That's a pain, so */
|
||||
@@ -1988,10 +2060,11 @@ struct objlist *LinkProperties(char *model, struct keyvalue *topptr)
|
||||
kl = NewProperty();
|
||||
kl->key = strsave(newkv->key);
|
||||
kl->idx = 0;
|
||||
kl->merge = MERGE_NONE;
|
||||
kl->type = PROP_STRING;
|
||||
kl->slop.ival = 0;
|
||||
kl->pdefault.string = NULL;
|
||||
HashPtrInstall(kl->key, kl, cell->proptab, OBJHASHSIZE);
|
||||
HashPtrInstall(kl->key, kl, &(cell->propdict));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2183,7 +2256,7 @@ struct nlist *resolveprops(struct hashlist *p, void *clientdata)
|
||||
for (i = 0;; i++) {
|
||||
vl = &(ob->instance.props[i]);
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
prop = (struct property *)HashLookup(vl->key, tc->proptab, OBJHASHSIZE);
|
||||
prop = (struct property *)HashLookup(vl->key, &(tc->propdict));
|
||||
|
||||
/* Warning: prop should never be null, but condition */
|
||||
/* should be handled. */
|
||||
@@ -2238,7 +2311,7 @@ void ResolveProperties(char *name1, int file1, char *name2, int file2)
|
||||
/* index. If the property does not exist in the second cell, then */
|
||||
/* create it. */
|
||||
|
||||
kl1 = (struct property *)HashFirst(tp1->proptab, OBJHASHSIZE);
|
||||
kl1 = (struct property *)HashFirst(&(tp1->propdict));
|
||||
/* If indexes are not zero, then properties have already been matched. */
|
||||
if (kl1 == NULL) return; /* Cell has no properties */
|
||||
if (kl1->idx != 0) return;
|
||||
@@ -2247,7 +2320,7 @@ void ResolveProperties(char *name1, int file1, char *name2, int file2)
|
||||
while (kl1 != NULL) {
|
||||
kl1->idx = i;
|
||||
|
||||
kl2 = (struct property *)HashLookup(kl1->key, tp2->proptab, OBJHASHSIZE);
|
||||
kl2 = (struct property *)HashLookup(kl1->key, &(tp2->propdict));
|
||||
if (kl2 == NULL) {
|
||||
/* No such property in tp2 */
|
||||
switch (kl1->type) {
|
||||
@@ -2270,16 +2343,16 @@ void ResolveProperties(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
}
|
||||
if (kl2 != NULL) kl2->idx = i;
|
||||
kl1 = (struct property *)HashNext(tp1->proptab, OBJHASHSIZE);
|
||||
kl1 = (struct property *)HashNext(&(tp1->propdict));
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Now check tp2 for properties not in tp1 */
|
||||
|
||||
kl2 = (struct property *)HashFirst(tp2->proptab, OBJHASHSIZE);
|
||||
kl2 = (struct property *)HashFirst(&(tp2->propdict));
|
||||
|
||||
while (kl2 != NULL) {
|
||||
kl1 = (struct property *)HashLookup(kl2->key, tp1->proptab, OBJHASHSIZE);
|
||||
kl1 = (struct property *)HashLookup(kl2->key, &(tp1->propdict));
|
||||
if (kl1 == NULL) {
|
||||
/* No such property in tp1 */
|
||||
switch (kl2->type) {
|
||||
@@ -2302,7 +2375,7 @@ void ResolveProperties(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
}
|
||||
if (kl1 != NULL) kl1->idx = i;
|
||||
kl2 = (struct property *)HashNext(tp1->proptab, OBJHASHSIZE);
|
||||
kl2 = (struct property *)HashNext(&(tp1->propdict));
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -37,13 +37,14 @@ extern struct property *PropertyString(char *name, int fnum, char *key,
|
||||
extern int PropertyDelete(char *name, int fnum, char *key);
|
||||
extern int PropertyTolerance(char *name, int fnum, char *key, int ival,
|
||||
double dval);
|
||||
extern int PropertyMerge(char *name, int fnum, char *key, int merge_type);
|
||||
extern void ResolveProperties(char *name1, int file1, char *name2, int file2);
|
||||
extern void CopyProperties(struct objlist *obj_to, struct objlist *obj_from);
|
||||
extern int PromoteProperty(struct property *, struct valuelist *);
|
||||
extern int SetPropertyDefault(struct property *, struct valuelist *);
|
||||
extern struct objlist *LinkProperties(char *model, struct keyvalue *topptr);
|
||||
extern int ReduceExpressions(struct objlist *instprop, struct nlist *parent,
|
||||
int glob);
|
||||
extern int ReduceExpressions(struct objlist *instprop, struct objlist *parprops,
|
||||
struct nlist *parent, int glob);
|
||||
extern void Node(char *name);
|
||||
extern void Global(char *name);
|
||||
extern void UniqueGlobal(char *name);
|
||||
|
||||
+45
-58
@@ -251,18 +251,18 @@ void PrintMemoryStats(void)
|
||||
|
||||
|
||||
#define CELLHASHSIZE 1000
|
||||
static struct hashlist *cell_hashtab[CELLHASHSIZE];
|
||||
static struct hashdict cell_dict;
|
||||
|
||||
void InitCellHashTable(void)
|
||||
{
|
||||
hashfunc = hash;
|
||||
matchfunc = match;
|
||||
InitializeHashTable(cell_hashtab, CELLHASHSIZE);
|
||||
hashfunc = hash;
|
||||
matchfunc = match;
|
||||
InitializeHashTable(&cell_dict, CELLHASHSIZE);
|
||||
}
|
||||
|
||||
struct nlist *LookupCell(char *s)
|
||||
{
|
||||
return((struct nlist *)HashLookup(s, cell_hashtab, CELLHASHSIZE));
|
||||
return((struct nlist *)HashLookup(s, &cell_dict));
|
||||
}
|
||||
|
||||
/* Similar hash lookup to the above, but will check if the matching */
|
||||
@@ -274,7 +274,7 @@ struct nlist *LookupCellFile(char *s, int f)
|
||||
struct nlist *he;
|
||||
|
||||
if (f == -1) return LookupCell(s);
|
||||
return HashIntLookup(s, f, cell_hashtab, CELLHASHSIZE);
|
||||
return HashIntLookup(s, f, &cell_dict);
|
||||
}
|
||||
|
||||
struct nlist *InstallInCellHashTable(char *name, int fnum)
|
||||
@@ -291,34 +291,23 @@ struct nlist *InstallInCellHashTable(char *name, int fnum)
|
||||
if (p == NULL) return(NULL);
|
||||
if ((p->name = strsave(name)) == NULL) goto fail;
|
||||
p->file = fnum;
|
||||
if ((p->objtab = (struct hashlist **)CALLOC(OBJHASHSIZE,
|
||||
sizeof(struct hashlist *))) == NULL) goto fail;
|
||||
if ((p->insttab = (struct hashlist **)CALLOC(OBJHASHSIZE,
|
||||
sizeof(struct hashlist *))) == NULL) goto fail;
|
||||
if ((p->proptab = (struct hashlist **)CALLOC(OBJHASHSIZE,
|
||||
sizeof(struct hashlist *))) == NULL) goto fail;
|
||||
InitializeHashTable(&(p->objdict), OBJHASHSIZE);
|
||||
InitializeHashTable(&(p->instdict), OBJHASHSIZE);
|
||||
InitializeHashTable(&(p->propdict), OBJHASHSIZE);
|
||||
p->permutes = NULL;
|
||||
|
||||
// Hash size 0 indicates to hash function that no binning is being done
|
||||
p->classhash = (*hashfunc)(name, 0);
|
||||
|
||||
ptr = HashIntPtrInstall(name, fnum, p, cell_hashtab, CELLHASHSIZE);
|
||||
ptr = HashIntPtrInstall(name, fnum, p, &cell_dict);
|
||||
if (ptr == NULL) return(NULL);
|
||||
return(p);
|
||||
fail:
|
||||
if (p->name != NULL) FREE(p->name);
|
||||
if (p->objtab != NULL) {
|
||||
HashKill(p->objtab, OBJHASHSIZE);
|
||||
FREE(p->objtab);
|
||||
}
|
||||
if (p->insttab != NULL) {
|
||||
HashKill(p->insttab, OBJHASHSIZE);
|
||||
FREE(p->insttab);
|
||||
}
|
||||
if (p->proptab != NULL) {
|
||||
HashKill(p->proptab, OBJHASHSIZE);
|
||||
FREE(p->proptab);
|
||||
}
|
||||
HashKill(&(p->objdict));
|
||||
HashKill(&(p->instdict));
|
||||
RecurseHashTable(&(p->propdict), freeprop);
|
||||
HashKill(&(p->propdict));
|
||||
FREE(p);
|
||||
return(NULL);
|
||||
}
|
||||
@@ -341,9 +330,9 @@ void CellRehash(char *name, char *newname, int file)
|
||||
FREE(tp->name);
|
||||
tp->name = strsave(newname);
|
||||
|
||||
ptr = HashIntPtrInstall(newname, file, (void *)tp, cell_hashtab, CELLHASHSIZE);
|
||||
ptr = HashIntPtrInstall(newname, file, (void *)tp, &cell_dict);
|
||||
if (ptr != NULL)
|
||||
HashIntDelete(name, file, cell_hashtab, CELLHASHSIZE);
|
||||
HashIntDelete(name, file, &cell_dict);
|
||||
|
||||
// Change the classhash to reflect the new name
|
||||
tp->classhash = (*hashfunc)(newname, 0);
|
||||
@@ -365,7 +354,7 @@ int deleteclass(struct hashlist *p, int file)
|
||||
nob = ob->next;
|
||||
if ((ob->type == FIRSTPIN) && (ob->model.class != NULL)) {
|
||||
if ((*matchfunc)(ob->model.class, OldCell->name)) {
|
||||
HashDelete(ob->instance.name, ptr->insttab, OBJHASHSIZE);
|
||||
HashDelete(ob->instance.name, &(ptr->instdict));
|
||||
while (1) {
|
||||
FreeObjectAndHash(ob, ptr);
|
||||
ob = nob;
|
||||
@@ -482,22 +471,13 @@ void CellDelete(char *name, int fnum)
|
||||
return;
|
||||
}
|
||||
|
||||
HashIntDelete(name, fnum, cell_hashtab, CELLHASHSIZE);
|
||||
HashIntDelete(name, fnum, &cell_dict);
|
||||
/* now make sure that we free all the fields of the nlist struct */
|
||||
if (tp->name != NULL) FREE(tp->name);
|
||||
if (tp->objtab != NULL) {
|
||||
HashKill(tp->objtab, OBJHASHSIZE);
|
||||
FREE(tp->objtab);
|
||||
}
|
||||
if (tp->insttab != NULL) {
|
||||
HashKill(tp->insttab, OBJHASHSIZE);
|
||||
FREE(tp->insttab);
|
||||
}
|
||||
if (tp->proptab != NULL) {
|
||||
RecurseHashTable(tp->proptab, OBJHASHSIZE, freeprop);
|
||||
HashKill(tp->proptab, OBJHASHSIZE);
|
||||
FREE(tp->proptab);
|
||||
}
|
||||
HashKill(&(tp->objdict));
|
||||
HashKill(&(tp->instdict));
|
||||
RecurseHashTable(&(tp->propdict), freeprop);
|
||||
HashKill(&(tp->propdict));
|
||||
FreeNodeNames(tp);
|
||||
ob = tp->cell;
|
||||
while (ob != NULL) {
|
||||
@@ -548,8 +528,8 @@ void PrintCellHashTable(int full, int filenum)
|
||||
|
||||
TopFile = filenum;
|
||||
|
||||
bins = RecurseHashTable(cell_hashtab, CELLHASHSIZE, CountHashTableBinsUsed);
|
||||
total = RecurseHashTable(cell_hashtab, CELLHASHSIZE, CountHashTableEntries);
|
||||
bins = RecurseHashTable(&cell_dict, CountHashTableBinsUsed);
|
||||
total = RecurseHashTable(&cell_dict, CountHashTableEntries);
|
||||
if (full != 2)
|
||||
Printf("Hash table: %d of %d bins used; %d cells total (%.2f per bin)\n",
|
||||
bins, CELLHASHSIZE, total, (bins == 0) ? 0 :
|
||||
@@ -557,7 +537,7 @@ void PrintCellHashTable(int full, int filenum)
|
||||
|
||||
OldDebug = Debug;
|
||||
Debug = full;
|
||||
RecurseHashTable(cell_hashtab, CELLHASHSIZE, PrintCellHashTableElement);
|
||||
RecurseHashTable(&cell_dict, PrintCellHashTableElement);
|
||||
Debug = OldDebug;
|
||||
#ifndef TCL_NETGEN
|
||||
if (full == 2) Printf("\n");
|
||||
@@ -566,12 +546,12 @@ void PrintCellHashTable(int full, int filenum)
|
||||
|
||||
struct nlist *FirstCell(void)
|
||||
{
|
||||
return((struct nlist *)HashFirst(cell_hashtab, CELLHASHSIZE));
|
||||
return((struct nlist *)HashFirst(&cell_dict));
|
||||
}
|
||||
|
||||
struct nlist *NextCell(void)
|
||||
{
|
||||
return((struct nlist *)HashNext(cell_hashtab, CELLHASHSIZE));
|
||||
return((struct nlist *)HashNext(&cell_dict));
|
||||
}
|
||||
|
||||
static int ClearDumpedElement(struct hashlist *np)
|
||||
@@ -585,17 +565,17 @@ static int ClearDumpedElement(struct hashlist *np)
|
||||
|
||||
void ClearDumpedList(void)
|
||||
{
|
||||
RecurseHashTable(cell_hashtab, CELLHASHSIZE, ClearDumpedElement);
|
||||
RecurseHashTable(&cell_dict, ClearDumpedElement);
|
||||
}
|
||||
|
||||
int RecurseCellHashTable(int (*foo)(struct hashlist *np))
|
||||
{
|
||||
return RecurseHashTable(cell_hashtab, CELLHASHSIZE, foo);
|
||||
return RecurseHashTable(&cell_dict, foo);
|
||||
}
|
||||
|
||||
int RecurseCellFileHashTable(int (*foo)(struct hashlist *, int), int value)
|
||||
{
|
||||
return RecurseHashTableValue(cell_hashtab, CELLHASHSIZE, foo, value);
|
||||
return RecurseHashTableValue(&cell_dict, foo, value);
|
||||
}
|
||||
|
||||
/* Yet another version, passing one parameter that is a pointer */
|
||||
@@ -603,7 +583,7 @@ int RecurseCellFileHashTable(int (*foo)(struct hashlist *, int), int value)
|
||||
struct nlist *RecurseCellHashTable2(struct nlist *(*foo)(struct hashlist *,
|
||||
void *), void *pointer)
|
||||
{
|
||||
return RecurseHashTablePointer(cell_hashtab, CELLHASHSIZE, foo, pointer);
|
||||
return RecurseHashTablePointer(&cell_dict, foo, pointer);
|
||||
}
|
||||
|
||||
/************************** WILD-CARD STUFF *******************************/
|
||||
@@ -863,7 +843,7 @@ int ListLength(char *list_template)
|
||||
|
||||
|
||||
|
||||
struct objlist *CopyObjList(struct objlist *oldlist)
|
||||
struct objlist *CopyObjList(struct objlist *oldlist, unsigned char doforall)
|
||||
/* copies list pointed to by oldlist, creating
|
||||
a list whose head pointer is returned */
|
||||
{
|
||||
@@ -900,6 +880,13 @@ struct objlist *CopyObjList(struct objlist *oldlist)
|
||||
tail->next = newob;
|
||||
tail = newob;
|
||||
tmp = tmp->next;
|
||||
|
||||
// If "doforall" is 0, then only copy one object; otherwise,
|
||||
// copy to the end of the list.
|
||||
if (!doforall) {
|
||||
if ((tmp == NULL) || ((tmp->type <= FIRSTPIN) && (tmp->type != PROPERTY)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (head);
|
||||
}
|
||||
@@ -914,13 +901,13 @@ struct objlist *CopyObjList(struct objlist *oldlist)
|
||||
|
||||
struct objlist *LookupObject(char *name, struct nlist *WhichCell)
|
||||
{
|
||||
return((struct objlist *)HashLookup(name, WhichCell->objtab, OBJHASHSIZE));
|
||||
return((struct objlist *)HashLookup(name, &(WhichCell->objdict)));
|
||||
}
|
||||
|
||||
struct objlist *LookupInstance(char *name, struct nlist *WhichCell)
|
||||
/* searches for exact match of instance 'name' in cell 'WhichCell' */
|
||||
{
|
||||
return((struct objlist *)HashLookup(name, WhichCell->insttab, OBJHASHSIZE));
|
||||
return((struct objlist *)HashLookup(name, &(WhichCell->instdict)));
|
||||
}
|
||||
|
||||
|
||||
@@ -939,7 +926,7 @@ void AddToCurrentCell(struct objlist *ob)
|
||||
|
||||
/* add to object hash table for this cell */
|
||||
if (CurrentCell != NULL) {
|
||||
HashPtrInstall(ob->name, ob, CurrentCell->objtab, OBJHASHSIZE);
|
||||
HashPtrInstall(ob->name, ob, &(CurrentCell->objdict));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -966,13 +953,13 @@ void AddToCurrentCellNoHash(struct objlist *ob)
|
||||
void AddInstanceToCurrentCell(struct objlist *ob)
|
||||
{
|
||||
/* add to instance hash table for this cell */
|
||||
HashPtrInstall(ob->instance.name, ob, CurrentCell->insttab, OBJHASHSIZE);
|
||||
HashPtrInstall(ob->instance.name, ob, &(CurrentCell->instdict));
|
||||
}
|
||||
|
||||
void FreeObject(struct objlist *ob)
|
||||
{
|
||||
/* This just frees the object record. Beware of pointer left */
|
||||
/* in the objtab hash table. Hash table records should be */
|
||||
/* in the objlist hash table. Hash table records should be */
|
||||
/* removed first. */
|
||||
|
||||
if (ob->name != NULL) FreeString(ob->name);
|
||||
@@ -1013,7 +1000,7 @@ void FreeObject(struct objlist *ob)
|
||||
|
||||
void FreeObjectAndHash(struct objlist *ob, struct nlist *ptr)
|
||||
{
|
||||
HashDelete(ob->name, ptr->objtab, OBJHASHSIZE);
|
||||
HashDelete(ob->name, &(ptr->objdict));
|
||||
FreeObject(ob);
|
||||
}
|
||||
|
||||
|
||||
+20
-4
@@ -3,6 +3,10 @@
|
||||
#ifndef _OBJLIST_H
|
||||
#define _OBJLIST_H
|
||||
|
||||
#ifndef _HASH_H
|
||||
#include "hash.h"
|
||||
#endif
|
||||
|
||||
#define SEPARATOR "/"
|
||||
#define INSTANCE_DELIMITER "#"
|
||||
#define PORT_DELIMITER "."
|
||||
@@ -99,10 +103,22 @@ struct valuelist {
|
||||
|
||||
/* Part 3: Keys & Defaults (kept in the cell record as a hash table) */
|
||||
|
||||
#define MERGE_NONE 0 /* Property does not change when devices merge */
|
||||
#define MERGE_ADD 1 /* Properties sum with device merge */
|
||||
#define MERGE_ADD_CRIT 2 /* Properties sum with device merge */
|
||||
#define MERGE_PAR 3 /* Properties add in parallel with device merge */
|
||||
#define MERGE_PAR_CRIT 4 /* Properties add in parallel with device merge */
|
||||
|
||||
/* Note: A "critical" merge means that the property causes the number of */
|
||||
/* devices to change. e.g., transistor width is critical; transistor drain */
|
||||
/* area sums when devices are merged, but does not change the number of devices.*/
|
||||
/* More than one property can be critical. e.g., width and number of fingers. */
|
||||
|
||||
struct property {
|
||||
char *key; /* name of the property */
|
||||
unsigned char idx; /* index into valuelist */
|
||||
unsigned char type; /* string, integer, double, value, expression */
|
||||
unsigned char merge; /* how property changes when devices are merged */
|
||||
union {
|
||||
char *string;
|
||||
double dval;
|
||||
@@ -172,9 +188,9 @@ struct nlist {
|
||||
unsigned long classhash; /* randomized hash value for cell class */
|
||||
struct Permutation *permutes; /* list of permuting pins */
|
||||
struct objlist *cell;
|
||||
struct hashlist **objtab; /* hash table of object names */
|
||||
struct hashlist **insttab; /* hash table of instance names */
|
||||
struct hashlist **proptab; /* hash table of property keys */
|
||||
struct hashdict objdict; /* hash table of object names */
|
||||
struct hashdict instdict; /* hash table of instance names */
|
||||
struct hashdict propdict; /* hash table of property keys */
|
||||
struct objlist **nodename_cache;
|
||||
long nodename_cache_maxnodenum; /* largest node number in cache */
|
||||
void *embedding; /* this will be cast to the appropriate data structure */
|
||||
@@ -216,7 +232,7 @@ extern int ListLength(char *list_template);
|
||||
extern struct nlist *LookupPrematchedClass(struct nlist *, int);
|
||||
extern struct objlist *LookupObject(char *name, struct nlist *WhichCell);
|
||||
extern struct objlist *LookupInstance(char *name, struct nlist *WhichCell);
|
||||
extern struct objlist *CopyObjList(struct objlist *oldlist);
|
||||
extern struct objlist *CopyObjList(struct objlist *oldlist, unsigned char doforall);
|
||||
extern void UpdateNodeNumbers(struct objlist *lst, int from, int to);
|
||||
|
||||
/* Function pointer to List or ListExact, allowing regular expressions */
|
||||
|
||||
+24
-21
@@ -40,7 +40,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "print.h"
|
||||
|
||||
// Global storage for parameters from .PARAM
|
||||
struct hashlist **spiceparams;
|
||||
struct hashdict spiceparams;
|
||||
|
||||
void SpiceSubCell(struct nlist *tp, int IsSubCell)
|
||||
{
|
||||
@@ -358,6 +358,12 @@ int renamepins(struct hashlist *p, int file)
|
||||
obp = ob;
|
||||
for (ob2 = tc->cell; ob2 != NULL; ob2 = ob2->next) {
|
||||
if (ob2->type != PORT) break;
|
||||
else if ((obp->type < FIRSTPIN) || (obp->type == FIRSTPIN && obp != ob)) {
|
||||
Fprintf(stderr, "Pin count mismatch between cell and instance of %s\n",
|
||||
tc->name);
|
||||
InputParseError(stderr);
|
||||
break;
|
||||
}
|
||||
if (!matchnocase(ob2->name, obp->name + strlen(obp->instance.name) + 1)) {
|
||||
// Printf("Cell %s pin correspondence: %s vs. %s\n",
|
||||
// tc->name, obp->name, ob2->name);
|
||||
@@ -778,7 +784,7 @@ skip_ends:
|
||||
kl->type = PROP_STRING;
|
||||
kl->slop.ival = 0;
|
||||
kl->pdefault.string = strsave(eqptr + 1);
|
||||
HashPtrInstall(nexttok, kl, spiceparams, OBJHASHSIZE);
|
||||
HashPtrInstall(nexttok, kl, &spiceparams);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -854,7 +860,7 @@ skip_ends:
|
||||
if (multi) snprintf(instname, 255, "%s%s.%d", model, inst, ndev);
|
||||
Cell(instname, model, collector, base, emitter);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, CurrentCell, TRUE);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
ndev--;
|
||||
}
|
||||
DeleteProperties(&kvlist);
|
||||
@@ -921,8 +927,8 @@ skip_ends:
|
||||
Port("gate");
|
||||
Port("source");
|
||||
Port("bulk");
|
||||
PropertyDouble(model, filenum, "length", 0.01, 0.0);
|
||||
PropertyDouble(model, filenum, "width", 0.01, 0.0);
|
||||
PropertyDouble(model, filenum, "L", 0.01, 0.0);
|
||||
PropertyDouble(model, filenum, "W", 0.01, 0.0);
|
||||
SetClass(CLASS_FET);
|
||||
EndCell();
|
||||
ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */
|
||||
@@ -940,7 +946,7 @@ skip_ends:
|
||||
if (multi) snprintf(instname, 255, "%s%s.%d", model, inst, ndev);
|
||||
Cell(instname, model, drain, gate, source, bulk);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, CurrentCell, TRUE);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
ndev--;
|
||||
}
|
||||
DeleteProperties(&kvlist);
|
||||
@@ -1043,7 +1049,7 @@ skip_ends:
|
||||
else
|
||||
Cap((*CellStackPtr)->cellname, instname, ctop, cbot);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, CurrentCell, TRUE);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
ndev--;
|
||||
}
|
||||
DeleteProperties(&kvlist);
|
||||
@@ -1145,7 +1151,7 @@ skip_ends:
|
||||
else
|
||||
Res((*CellStackPtr)->cellname, instname, rtop, rbot);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, CurrentCell, TRUE);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
ndev--;
|
||||
}
|
||||
DeleteProperties(&kvlist);
|
||||
@@ -1209,7 +1215,7 @@ skip_ends:
|
||||
if (multi) snprintf(instname, 255, "%s%s.%d", model, inst, ndev);
|
||||
Cell(instname, model, anode, cathode);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, CurrentCell, TRUE);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
ndev--;
|
||||
}
|
||||
DeleteProperties(&kvlist);
|
||||
@@ -1301,7 +1307,7 @@ skip_ends:
|
||||
XLine((*CellStackPtr)->cellname, instname, node1, node2,
|
||||
node3, node4);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, CurrentCell, TRUE);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
ndev--;
|
||||
}
|
||||
DeleteProperties(&kvlist);
|
||||
@@ -1391,7 +1397,7 @@ skip_ends:
|
||||
else
|
||||
Inductor((*CellStackPtr)->cellname, instname, end_a, end_b);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, CurrentCell, TRUE);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
ndev--;
|
||||
}
|
||||
DeleteProperties(&kvlist);
|
||||
@@ -1451,7 +1457,7 @@ skip_ends:
|
||||
}
|
||||
Cell(instname, model, pos, neg);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, CurrentCell, TRUE);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
DeleteProperties(&kvlist);
|
||||
}
|
||||
else if (toupper(nexttok[0]) == 'I') { /* current source */
|
||||
@@ -1504,7 +1510,7 @@ skip_ends:
|
||||
}
|
||||
Cell(instname, model, pos, neg);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, CurrentCell, TRUE);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
DeleteProperties(&kvlist);
|
||||
}
|
||||
else if (toupper(nexttok[0]) == 'E') { /* controlled voltage source */
|
||||
@@ -1568,7 +1574,7 @@ skip_ends:
|
||||
}
|
||||
Cell(instname, model, pos, neg, ctrlp, ctrln);
|
||||
pobj = LinkProperties(model, kvlist);
|
||||
ReduceExpressions(pobj, CurrentCell, TRUE);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
DeleteProperties(&kvlist);
|
||||
}
|
||||
|
||||
@@ -1714,7 +1720,7 @@ skip_ends:
|
||||
}
|
||||
Instance(subcktname, instancename);
|
||||
pobj = LinkProperties(subcktname, kvlist);
|
||||
ReduceExpressions(pobj, CurrentCell, TRUE);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
ndev--;
|
||||
|
||||
/* (Diagnostic) */
|
||||
@@ -1844,8 +1850,7 @@ char *ReadSpiceTop(char *fname, int *fnum, int blackbox)
|
||||
matchintfunc = matchfilenocase;
|
||||
hashfunc = hashnocase;
|
||||
|
||||
spiceparams = (struct hashlist **)CALLOC(OBJHASHSIZE,
|
||||
sizeof(struct hashlist *));
|
||||
InitializeHashTable(&spiceparams, OBJHASHSIZE);
|
||||
|
||||
/* All spice files should start with a comment line, */
|
||||
/* but we won't depend upon it. Any comment line */
|
||||
@@ -1857,10 +1862,8 @@ char *ReadSpiceTop(char *fname, int *fnum, int blackbox)
|
||||
// Cleanup
|
||||
while (CellStack != NULL) PopStack(&CellStack);
|
||||
|
||||
RecurseHashTable(spiceparams, OBJHASHSIZE, freeprop);
|
||||
HashKill(spiceparams, OBJHASHSIZE);
|
||||
FREE(spiceparams);
|
||||
spiceparams = NULL;
|
||||
RecurseHashTable(&spiceparams, freeprop);
|
||||
HashKill(&spiceparams);
|
||||
|
||||
// Important: If the file is a library, containing subcircuit
|
||||
// definitions but no components, then it needs to be registered
|
||||
|
||||
+2
-2
@@ -36,7 +36,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#define XILINXHASHSIZE 99
|
||||
static long xilinxhashbase = 0xA00;
|
||||
static struct hashlist *xilinxnametab[XILINXHASHSIZE];
|
||||
static struct hashdict xilinxnamedict;
|
||||
static FILE *xilinxfile;
|
||||
|
||||
char *gndnet = "0";
|
||||
@@ -156,7 +156,7 @@ Xilinx(cellname, filename)
|
||||
return;
|
||||
}
|
||||
ClearDumpedList();
|
||||
InitializeHashTable(xilinxnametab, XILINXHASHSIZE);
|
||||
InitializeHashTable(&xilinxnamedict, XILINXHASHSIZE);
|
||||
if (LookupCell(cellname) != NULL)
|
||||
xilinxCell(cellname);
|
||||
CloseFile(FileName);
|
||||
|
||||
@@ -65,7 +65,7 @@ CPP = gcc -E -x c
|
||||
CXX = @CXX@
|
||||
|
||||
CPPFLAGS = -I. -I${NETGENDIR}
|
||||
DFLAGS = -DCAD_DIR=\"${LIBDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"[email protected]\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"50\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG
|
||||
DFLAGS = -DCAD_DIR=\"${LIBDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"[email protected]\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"54\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG
|
||||
CFLAGS = -g -m64 -fPIC -fPIC
|
||||
|
||||
DEPEND_FILE = Depend
|
||||
|
||||
+9
-8
@@ -33,6 +33,7 @@ PATH: /sbin
|
||||
PATH: /usr/bin
|
||||
PATH: /usr/sbin
|
||||
PATH: /usr/local/bin
|
||||
PATH: /home/tim/src/timberwolf-6.3/bin
|
||||
|
||||
|
||||
## ----------- ##
|
||||
@@ -125,7 +126,7 @@ configure: failed program was:
|
||||
| #define PACKAGE_BUGREPORT "[email protected]"
|
||||
| #define PACKAGE_URL ""
|
||||
| #define NETGEN_VERSION "1.5"
|
||||
| #define NETGEN_REVISION "50"
|
||||
| #define NETGEN_REVISION "54"
|
||||
| /* end confdefs.h. */
|
||||
| #include <ac_nonexistent.h>
|
||||
configure:3382: result: gcc -E
|
||||
@@ -146,7 +147,7 @@ configure: failed program was:
|
||||
| #define PACKAGE_BUGREPORT "[email protected]"
|
||||
| #define PACKAGE_URL ""
|
||||
| #define NETGEN_VERSION "1.5"
|
||||
| #define NETGEN_REVISION "50"
|
||||
| #define NETGEN_REVISION "54"
|
||||
| /* end confdefs.h. */
|
||||
| #include <ac_nonexistent.h>
|
||||
configure:3445: checking for library containing strerror
|
||||
@@ -261,7 +262,7 @@ configure: failed program was:
|
||||
| #define PACKAGE_BUGREPORT "[email protected]"
|
||||
| #define PACKAGE_URL ""
|
||||
| #define NETGEN_VERSION "1.5"
|
||||
| #define NETGEN_REVISION "50"
|
||||
| #define NETGEN_REVISION "54"
|
||||
| #define STDC_HEADERS 1
|
||||
| #define HAVE_SYS_TYPES_H 1
|
||||
| #define HAVE_SYS_STAT_H 1
|
||||
@@ -302,7 +303,7 @@ configure: failed program was:
|
||||
| #define PACKAGE_BUGREPORT "[email protected]"
|
||||
| #define PACKAGE_URL ""
|
||||
| #define NETGEN_VERSION "1.5"
|
||||
| #define NETGEN_REVISION "50"
|
||||
| #define NETGEN_REVISION "54"
|
||||
| #define STDC_HEADERS 1
|
||||
| #define HAVE_SYS_TYPES_H 1
|
||||
| #define HAVE_SYS_STAT_H 1
|
||||
@@ -382,7 +383,7 @@ configure: failed program was:
|
||||
| #define PACKAGE_BUGREPORT "[email protected]"
|
||||
| #define PACKAGE_URL ""
|
||||
| #define NETGEN_VERSION "1.5"
|
||||
| #define NETGEN_REVISION "50"
|
||||
| #define NETGEN_REVISION "54"
|
||||
| #define STDC_HEADERS 1
|
||||
| #define HAVE_SYS_TYPES_H 1
|
||||
| #define HAVE_SYS_STAT_H 1
|
||||
@@ -454,7 +455,7 @@ configure: failed program was:
|
||||
| #define PACKAGE_BUGREPORT "[email protected]"
|
||||
| #define PACKAGE_URL ""
|
||||
| #define NETGEN_VERSION "1.5"
|
||||
| #define NETGEN_REVISION "50"
|
||||
| #define NETGEN_REVISION "54"
|
||||
| #define STDC_HEADERS 1
|
||||
| #define HAVE_SYS_TYPES_H 1
|
||||
| #define HAVE_SYS_STAT_H 1
|
||||
@@ -621,7 +622,7 @@ CC='gcc'
|
||||
CFLAGS='-g -m64 -fPIC'
|
||||
CPP='gcc -E -x c'
|
||||
CPPFLAGS=''
|
||||
DEFS='-DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"[email protected]\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"50\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1'
|
||||
DEFS='-DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"[email protected]\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"54\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1'
|
||||
DEPEND_FLAG='-MM'
|
||||
ECHO_C=''
|
||||
ECHO_N='printf'
|
||||
@@ -734,7 +735,7 @@ unused=''
|
||||
#define PACKAGE_BUGREPORT "[email protected]"
|
||||
#define PACKAGE_URL ""
|
||||
#define NETGEN_VERSION "1.5"
|
||||
#define NETGEN_REVISION "50"
|
||||
#define NETGEN_REVISION "54"
|
||||
#define STDC_HEADERS 1
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
@@ -657,7 +657,7 @@ S["ECHO_T"]=""
|
||||
S["ECHO_N"]="-n"
|
||||
S["ECHO_C"]=""
|
||||
S["DEFS"]="-DPACKAGE_NAME=\\\"netgen\\\" -DPACKAGE_TARNAME=\\\"netgen\\\" -DPACKAGE_VERSION=\\\"1.3\\\" -DPACKAGE_STRING=\\\"netgen\\ 1.3\\\" -DPACKAGE_BUGREPORT=\\\"eda-dev@open"\
|
||||
"circuitdesign.com\\\" -DPACKAGE_URL=\\\"\\\" -DNETGEN_VERSION=\\\"1.5\\\" -DNETGEN_REVISION=\\\"50\\\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -"\
|
||||
"circuitdesign.com\\\" -DPACKAGE_URL=\\\"\\\" -DNETGEN_VERSION=\\\"1.5\\\" -DNETGEN_REVISION=\\\"54\\\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -"\
|
||||
"DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -D"\
|
||||
"SIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHA"\
|
||||
"VE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1"
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ CPP = gcc -E -x c
|
||||
CXX = @CXX@
|
||||
|
||||
CPPFLAGS = -I. -I${NETGENDIR}
|
||||
DFLAGS = -DCAD_DIR=\"${LIBDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"[email protected]\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"50\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG
|
||||
DFLAGS = -DCAD_DIR=\"${LIBDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"[email protected]\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"54\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG
|
||||
CFLAGS = -g -m64 -fPIC -fPIC
|
||||
|
||||
DEPEND_FILE = Depend
|
||||
|
||||
+62
-9
@@ -2970,6 +2970,7 @@ _netcmp_equate(ClientData clientData,
|
||||
/* add --- add new property */
|
||||
/* remove --- delete existing property */
|
||||
/* tolerance --- set property tolerance */
|
||||
/* merge --- set property merge behavior */
|
||||
/* Formerly: (none) */
|
||||
/* Results: */
|
||||
/* Side Effects: */
|
||||
@@ -2987,10 +2988,10 @@ _netcmp_property(ClientData clientData,
|
||||
int ival, argstart;
|
||||
|
||||
char *options[] = {
|
||||
"add", "create", "remove", "delete", "tolerance", NULL
|
||||
"add", "create", "remove", "delete", "tolerance", "merge", NULL
|
||||
};
|
||||
enum OptionIdx {
|
||||
ADD_IDX, CREATE_IDX, REMOVE_IDX, DELETE_IDX, TOLERANCE_IDX
|
||||
ADD_IDX, CREATE_IDX, REMOVE_IDX, DELETE_IDX, TOLERANCE_IDX, MERGE_IDX
|
||||
};
|
||||
int result, index, idx2;
|
||||
|
||||
@@ -3001,6 +3002,13 @@ _netcmp_property(ClientData clientData,
|
||||
INTEGER_IDX, DOUBLE_IDX, VALUE_IDX, STRING_IDX
|
||||
};
|
||||
|
||||
char *mergeoptions[] = {
|
||||
"none", "add", "add_critical", "par", "par_critical", NULL
|
||||
};
|
||||
enum MergeOptionIdx {
|
||||
NONE_IDX, ADD_ONLY_IDX, ADD_CRIT_IDX, PAR_ONLY_IDX, PAR_CRIT_IDX
|
||||
};
|
||||
|
||||
if (objc < 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "valid_cellname ?option?");
|
||||
return TCL_ERROR;
|
||||
@@ -3012,7 +3020,7 @@ _netcmp_property(ClientData clientData,
|
||||
/* Print all properties of the cell as key/type/tolerance triplets */
|
||||
tobj1 = Tcl_NewListObj(0, NULL);
|
||||
|
||||
kl = (struct property *)HashFirst(tp->proptab, OBJHASHSIZE);
|
||||
kl = (struct property *)HashFirst(&(tp->propdict));
|
||||
while (kl != NULL) {
|
||||
tobj2 = Tcl_NewListObj(0, NULL);
|
||||
|
||||
@@ -3039,7 +3047,7 @@ _netcmp_property(ClientData clientData,
|
||||
|
||||
Tcl_ListObjAppendElement(interp, tobj1, tobj2);
|
||||
|
||||
kl = (struct property *)HashNext(tp->proptab, OBJHASHSIZE);
|
||||
kl = (struct property *)HashNext(&(tp->propdict));
|
||||
}
|
||||
Tcl_SetObjResult(interp, tobj1);
|
||||
}
|
||||
@@ -3175,11 +3183,9 @@ _netcmp_property(ClientData clientData,
|
||||
if (objc == 3) {
|
||||
/* "remove" without additional arguments means */
|
||||
/* delete all properties. */
|
||||
RecurseHashTable(tp->proptab, OBJHASHSIZE, freeprop);
|
||||
HashKill(tp->proptab, OBJHASHSIZE);
|
||||
FREE(tp->proptab);
|
||||
tp->proptab = (struct hashlist **)CALLOC(OBJHASHSIZE,
|
||||
sizeof(struct hashlist *));
|
||||
RecurseHashTable(&(tp->propdict), freeprop);
|
||||
HashKill(&(tp->propdict));
|
||||
InitializeHashTable(&(tp->propdict), OBJHASHSIZE);
|
||||
}
|
||||
else {
|
||||
for (i = 3; i < objc; i++)
|
||||
@@ -3221,6 +3227,53 @@ _netcmp_property(ClientData clientData,
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MERGE_IDX:
|
||||
if (objc == 3) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "{property_key merge_type} ...");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
for (i = 3; i < objc; i++) {
|
||||
// Each value must be a duplet
|
||||
result = Tcl_ListObjLength(interp, objv[i], &llen);
|
||||
if ((result != TCL_OK) || (llen != 2)) {
|
||||
Tcl_SetResult(interp, "Not a {key merge_type} pair list.",
|
||||
NULL);
|
||||
}
|
||||
else {
|
||||
int mergeval;
|
||||
|
||||
result = Tcl_ListObjIndex(interp, objv[i], 0, &tobj1);
|
||||
if (result != TCL_OK) return result;
|
||||
result = Tcl_ListObjIndex(interp, objv[i], 1, &tobj2);
|
||||
if (result != TCL_OK) return result;
|
||||
|
||||
result = Tcl_GetIndexFromObj(interp, tobj2,
|
||||
(CONST84 char **)mergeoptions,
|
||||
"merge_type", 0, &idx2);
|
||||
if (result != TCL_OK) return result;
|
||||
|
||||
switch (idx2) {
|
||||
case NONE_IDX:
|
||||
mergeval = MERGE_NONE;
|
||||
break;
|
||||
case ADD_ONLY_IDX:
|
||||
mergeval = MERGE_ADD;
|
||||
break;
|
||||
case ADD_CRIT_IDX:
|
||||
mergeval = MERGE_ADD_CRIT;
|
||||
break;
|
||||
case PAR_ONLY_IDX:
|
||||
mergeval = MERGE_PAR;
|
||||
break;
|
||||
case PAR_CRIT_IDX:
|
||||
mergeval = MERGE_PAR_CRIT;
|
||||
break;
|
||||
}
|
||||
PropertyMerge(tp->name, fnum, Tcl_GetString(tobj1), mergeval);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return TCL_OK;
|
||||
|
||||
Reference in New Issue
Block a user