Extended the prematching phase to include matching of devices
based on properties that can be traded with number of devices, such as MOSFET width, by merging. This initial implementation is somewhat limited, only dealing with properties that merge by summing. Only devices that do not match at all in the other circuit will be considered for merging. The feature includes a command option "property ... merge ..." that allows control over which devices can and cannot be merged.
This commit is contained in:
parent
15d10f1d93
commit
758b5a249a
232
base/flatten.c
232
base/flatten.c
|
|
@ -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;
|
||||
|
|
@ -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 */
|
||||
|
|
@ -466,28 +469,19 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
|
|||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1304,6 +1298,88 @@ typedef struct ecomplist {
|
|||
ECompListPtr next;
|
||||
} ECompList;
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* 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
|
||||
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. */
|
||||
|
|
@ -1353,6 +1429,8 @@ SurveyDevice(struct nlist *tc, struct hashdict *devdict,
|
|||
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;
|
||||
|
|
@ -1811,6 +1889,9 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
// 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) {
|
||||
|
|
@ -1818,13 +1899,63 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
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 (kl2->merge == MERGE_ADD_CRIT || kl2->merge == MERGE_PAR_CRIT)
|
||||
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->cell1->propdict));
|
||||
kl2 = (struct property *)HashNext(&(ecomp->cell2->propdict));
|
||||
}
|
||||
if (kl1 != NULL || kl2 != NULL) {
|
||||
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
|
||||
|
||||
|
|
@ -1833,20 +1964,65 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
|||
// Populate the device hash table
|
||||
|
||||
SurveyDevice(tc1, &devdict, ecomp->cell1, kl1, file1, file2, 0);
|
||||
SurveyDevice(tc2, &devdict, ecomp->cell2, kl2, 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 != dcomp->num2) {
|
||||
/* XXX WIP WIP WIP XXX */
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -4491,6 +4496,7 @@ int reorderpins(struct hashlist *p, int file)
|
|||
HashPtrInstall(ob->name, ob, &(ptr->objdict));
|
||||
ob = ob->next;
|
||||
names[i] = NULL;
|
||||
if (ob == NULL) break; // Error message already output
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
117
base/netgen.c
117
base/netgen.c
|
|
@ -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;
|
||||
|
||||
|
|
@ -195,22 +201,50 @@ int TokGetValue(char *estr, struct nlist *parent, int glob, double *dval)
|
|||
}
|
||||
}
|
||||
|
||||
/* Check local parameters */
|
||||
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;
|
||||
/* 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 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);
|
||||
|
|
@ -228,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
|
||||
|
|
@ -245,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) {
|
||||
|
|
@ -269,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);
|
||||
|
|
@ -289,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);
|
||||
|
|
@ -310,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);
|
||||
|
|
@ -320,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);
|
||||
|
|
@ -339,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);
|
||||
|
|
@ -350,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;
|
||||
|
|
@ -365,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);
|
||||
|
|
@ -375,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);
|
||||
|
|
@ -385,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);
|
||||
|
|
@ -395,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;
|
||||
|
|
@ -405,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);
|
||||
|
|
@ -416,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);
|
||||
|
|
@ -426,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);
|
||||
|
||||
|
|
@ -442,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);
|
||||
|
||||
|
|
@ -458,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;
|
||||
|
|
@ -483,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);
|
||||
|
||||
|
|
@ -754,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);
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ 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);
|
||||
|
|
|
|||
|
|
@ -843,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 */
|
||||
{
|
||||
|
|
@ -880,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -232,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 */
|
||||
|
|
|
|||
26
base/spice.c
26
base/spice.c
|
|
@ -860,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);
|
||||
|
|
@ -927,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 */
|
||||
|
|
@ -946,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);
|
||||
|
|
@ -1049,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);
|
||||
|
|
@ -1151,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);
|
||||
|
|
@ -1215,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);
|
||||
|
|
@ -1307,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);
|
||||
|
|
@ -1397,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);
|
||||
|
|
@ -1457,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 */
|
||||
|
|
@ -1510,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 */
|
||||
|
|
@ -1574,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);
|
||||
}
|
||||
|
||||
|
|
@ -1720,7 +1720,7 @@ skip_ends:
|
|||
}
|
||||
Instance(subcktname, instancename);
|
||||
pobj = LinkProperties(subcktname, kvlist);
|
||||
ReduceExpressions(pobj, CurrentCell, TRUE);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
ndev--;
|
||||
|
||||
/* (Diagnostic) */
|
||||
|
|
|
|||
Loading…
Reference in New Issue