|
|
|
@ -4,6 +4,15 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group |
|
|
|
Modified: 2000 AlansFixes |
|
|
|
**********/ |
|
|
|
|
|
|
|
/*------------------------------------------------------------------------------ |
|
|
|
* Added changes supplied by by H.Tanaka with some tidy up of comments, debug |
|
|
|
* statements, and variables. This fixes a problem with nested .subsck elements |
|
|
|
* that accessed .model lines. Code not ideal, but it seems to work okay. |
|
|
|
* Also took opportunity to tidy a few other items (unused variables etc.), plus |
|
|
|
* fix a few spelling errors in the comments, and a memory leak. |
|
|
|
* SJB 25th March 2005 |
|
|
|
*----------------------------------------------------------------------------*/ |
|
|
|
|
|
|
|
/*------------------------------------------------------------------------------ |
|
|
|
* re-written by SDB during 4.2003 to enable SPICE2 POLY statements to be processed |
|
|
|
* properly. This is particularly important for dependent sources, whose argument |
|
|
|
@ -60,16 +69,8 @@ Modified: 2000 AlansFixes |
|
|
|
extern char * nupa_copy(char *s, int linenum); |
|
|
|
extern int nupa_eval(char *s, int linenum); |
|
|
|
extern int nupa_signal(int sig, char *info); |
|
|
|
static char NumParams='y'; |
|
|
|
static char DoGarbage='n'; |
|
|
|
|
|
|
|
#else |
|
|
|
#define nupa_copy(x,y) copy(x) |
|
|
|
#define nupa_eval(x,y) 1 |
|
|
|
#define nupa_signal(x,y) 1 |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
/* ----- static declarations ----- */ |
|
|
|
static struct line * doit(struct line *deck); |
|
|
|
static int translate(struct line *deck, char *formal, char *actual, char *scname, |
|
|
|
@ -81,6 +82,7 @@ static int numnodes(char *name); |
|
|
|
static int numdevs(char *s); |
|
|
|
static bool modtranslate(struct line *deck, char *subname); |
|
|
|
static void devmodtranslate(struct line *deck, char *subname); |
|
|
|
static int inp_numnodes(char c); |
|
|
|
|
|
|
|
/*--------------------------------------------------------------------- |
|
|
|
* table is used in settrans and gettrans -- it holds the netnames used |
|
|
|
@ -99,7 +101,7 @@ static struct tab { |
|
|
|
*--------------------------------------------------------------------*/ |
|
|
|
struct subs { |
|
|
|
char *su_name; /* The .subckt name. */ |
|
|
|
char *su_args; /* The .subckt arguments, space seperated. */ |
|
|
|
char *su_args; /* The .subckt arguments, space separated. */ |
|
|
|
int su_numargs; |
|
|
|
struct line *su_def; /* Pointer to the .subckt definition. */ |
|
|
|
struct subs *su_next; |
|
|
|
@ -116,6 +118,10 @@ static bool nobjthack = FALSE; |
|
|
|
|
|
|
|
static char start[32], sbend[32], invoke[32], model[32]; |
|
|
|
|
|
|
|
#ifdef NUMPARAMS |
|
|
|
static char NumParams='y'; |
|
|
|
#endif |
|
|
|
|
|
|
|
/*-------------------------------------------------------------------*/ |
|
|
|
/* inp_subcktexpand is the top level function which translates */ |
|
|
|
/* .subckts into mainlined code. Note that there are two things */ |
|
|
|
@ -140,13 +146,15 @@ inp_subcktexpand(struct line *deck) |
|
|
|
#ifdef NUMPARAMS |
|
|
|
int ok; |
|
|
|
#endif |
|
|
|
wordlist *wl; |
|
|
|
modnames = NULL; |
|
|
|
|
|
|
|
if(!cp_getvar("substart", VT_STRING, start)) |
|
|
|
(void) strcpy(start, ".subckt"); |
|
|
|
if(!cp_getvar("subend", VT_STRING, sbend)) |
|
|
|
(void) strcpy(sbend, ".ends"); |
|
|
|
if(!cp_getvar("subinvoke", VT_STRING, invoke)) |
|
|
|
(void) strcpy(invoke, "X"); |
|
|
|
(void) strcpy(invoke, "x"); |
|
|
|
if(!cp_getvar("modelcard", VT_STRING, model)) |
|
|
|
(void) strcpy(model, ".model"); |
|
|
|
if(!cp_getvar("modelline", VT_STRING, model)) |
|
|
|
@ -165,11 +173,36 @@ inp_subcktexpand(struct line *deck) |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
/* Let's do a few cleanup things first... Get rid of ( ) around node |
|
|
|
/* Get all the model names so we can deal with BJTs, etc. |
|
|
|
* Stick all the model names into the doubly-linked wordlist modnames. |
|
|
|
*/ |
|
|
|
for (c = deck; c; c = c->li_next) |
|
|
|
if (ciprefix(model, c->li_line)) { |
|
|
|
s = c->li_line; |
|
|
|
txfree(gettok(&s)); // discard the model keyword |
|
|
|
wl = alloc(struct wordlist); |
|
|
|
wl->wl_next = modnames; |
|
|
|
if (modnames) |
|
|
|
modnames->wl_prev = wl; |
|
|
|
modnames = wl; |
|
|
|
wl->wl_word = gettok(&s); /* wl->wl_word now holds name of model */ |
|
|
|
}/*model name finding routine*/ |
|
|
|
|
|
|
|
#ifdef TRACE |
|
|
|
{ |
|
|
|
wordlist * w; |
|
|
|
printf("Models found:\n"); |
|
|
|
for(w = modnames; w; w = w->wl_next) |
|
|
|
printf("%s\n",w->wl_word); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
/* Let's do a few cleanup things... Get rid of ( ) around node |
|
|
|
* lists... |
|
|
|
*/ |
|
|
|
for (c = deck; c; c = c->li_next) { /* iterate on lines in deck */ |
|
|
|
if (prefix(start, c->li_line)) { /* if we find .subckt . . . */ |
|
|
|
if (ciprefix(start, c->li_line)) { /* if we find .subckt . . . */ |
|
|
|
#ifdef TRACE |
|
|
|
/* SDB debug statement */ |
|
|
|
printf("In inp_subcktexpand, found a .subckt: %s\n", c->li_line); |
|
|
|
@ -212,6 +245,12 @@ inp_subcktexpand(struct line *deck) |
|
|
|
#endif |
|
|
|
ll = doit(deck); |
|
|
|
|
|
|
|
// SJB: free up the modnames linked list now we are done with it |
|
|
|
if(modnames != NULL) { |
|
|
|
wl_free(modnames); |
|
|
|
modnames = NULL; |
|
|
|
} |
|
|
|
|
|
|
|
/* Now check to see if there are still subckt instances undefined... */ |
|
|
|
if (ll!=NULL) for (c = ll; c; c = c->li_next) |
|
|
|
if (ciprefix(invoke, c->li_line)) { |
|
|
|
@ -258,30 +297,29 @@ doit(struct line *deck) |
|
|
|
char *s, *t, *scname, *subname; |
|
|
|
int nest, numpasses = MAXNEST, i; |
|
|
|
bool gotone; |
|
|
|
wordlist *wl; |
|
|
|
wordlist *tmodnames = modnames; |
|
|
|
wordlist *tsubmod = submod; |
|
|
|
struct subs *ts = subs; |
|
|
|
int error; |
|
|
|
|
|
|
|
/* Save all the old stuff... */ |
|
|
|
modnames = NULL; |
|
|
|
subs = NULL; |
|
|
|
submod = NULL; |
|
|
|
|
|
|
|
#ifdef TRACE |
|
|
|
/* SDB debug statement */ |
|
|
|
printf("In doit, about to start first pass through deck.\n"); |
|
|
|
for(c=deck;c; c=c->li_next) |
|
|
|
printf(" %s\n",c->li_line); |
|
|
|
#endif |
|
|
|
|
|
|
|
/* First pass: xtract all the .subckts and stick pointers to them into sss. */ |
|
|
|
for (last = deck, lc = NULL; last; ) { |
|
|
|
if (prefix(sbend, last->li_line)) { /* if line == .ends */ |
|
|
|
if (ciprefix(sbend, last->li_line)) { /* if line == .ends */ |
|
|
|
fprintf(cp_err, "Error: misplaced %s line: %s\n", sbend, |
|
|
|
last->li_line); |
|
|
|
return (NULL); |
|
|
|
} |
|
|
|
else if (prefix(start, last->li_line)) { /* if line == .subckt */ |
|
|
|
else if (ciprefix(start, last->li_line)) { /* if line == .subckt */ |
|
|
|
if (last->li_next == NULL) { /* first check that next line is non null */ |
|
|
|
fprintf(cp_err, "Error: no %s line.\n", sbend); |
|
|
|
return (NULL); |
|
|
|
@ -296,7 +334,7 @@ doit(struct line *deck) |
|
|
|
* .subckt card, and lcc will point to the location of the .ends card. |
|
|
|
*/ |
|
|
|
for (nest = 0, c = last->li_next; c; c = c->li_next) { |
|
|
|
if (prefix(sbend, c->li_line)) { /* found a .ends */ |
|
|
|
if (ciprefix(sbend, c->li_line)) { /* found a .ends */ |
|
|
|
if (!nest) |
|
|
|
break; /* nest = 0 means we have balanced .subckt and .ends */ |
|
|
|
else { |
|
|
|
@ -304,7 +342,7 @@ doit(struct line *deck) |
|
|
|
lcc = c; /* (lcc points to the position of the .ends) */ |
|
|
|
continue; /* then continue looping */ |
|
|
|
} |
|
|
|
} else if (prefix(start, c->li_line)) /* if .subckt, increment nesting */ |
|
|
|
} else if (ciprefix(start, c->li_line)) /* if .subckt, increment nesting */ |
|
|
|
nest++; |
|
|
|
lcc = c; /* lcc points to current pos of c */ |
|
|
|
} /* for (nest = 0 . . . */ |
|
|
|
@ -382,25 +420,11 @@ doit(struct line *deck) |
|
|
|
return (NULL); |
|
|
|
subs = ks; /* ks has held pointer to start of subcircuits list. */ |
|
|
|
|
|
|
|
|
|
|
|
/* Get all the model names so we can deal with BJT's. |
|
|
|
* Stick all the model names into the doubly-linked wordlist wl. |
|
|
|
*/ |
|
|
|
for (c = deck; c; c = c->li_next) |
|
|
|
if (prefix(model, c->li_line)) { |
|
|
|
s = c->li_line; |
|
|
|
txfree(gettok(&s)); |
|
|
|
wl = alloc(struct wordlist); |
|
|
|
wl->wl_next = modnames; |
|
|
|
if (modnames) |
|
|
|
modnames->wl_prev = wl; |
|
|
|
modnames = wl; |
|
|
|
wl->wl_word = gettok(&s); /* wl->wl_word now holds name of model */ |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef TRACE |
|
|
|
/* SDB debug statement */ |
|
|
|
printf("In doit, about to start second pass through deck.\n"); |
|
|
|
for(c=deck;c; c=c->li_next) |
|
|
|
printf(" %s\n",c->li_line); |
|
|
|
#endif |
|
|
|
|
|
|
|
error = 0; |
|
|
|
@ -521,6 +545,19 @@ doit(struct line *deck) |
|
|
|
return (NULL); |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef TRACE |
|
|
|
/* Added by H.Tanaka to display converted deck */ |
|
|
|
printf("Converted deck\n"); |
|
|
|
for (c = deck; c; c = c->li_next){ |
|
|
|
printf( "%s\n",c->li_line); |
|
|
|
} |
|
|
|
{ |
|
|
|
wordlist * w; |
|
|
|
printf("Models:\n"); |
|
|
|
for(w = modnames; w; w = w->wl_next) |
|
|
|
printf("%s\n",w->wl_word); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
if (error) |
|
|
|
return NULL; /* error message already reported; should free( ) */ |
|
|
|
@ -942,10 +979,9 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub |
|
|
|
|
|
|
|
/* Next iterate over all nodes (netnames) found and translate them. */ |
|
|
|
nnodes = numnodes(c->li_line); |
|
|
|
|
|
|
|
while (nnodes-- > 0) { |
|
|
|
name = gettok_node(&s); |
|
|
|
if (name == NULL) { |
|
|
|
if (name == NULL ) { |
|
|
|
fprintf(cp_err, "Error: too few nodes: %s\n", |
|
|
|
c->li_line); |
|
|
|
goto quit; |
|
|
|
@ -970,7 +1006,7 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub |
|
|
|
} /* while (nnodes-- . . . . */ |
|
|
|
|
|
|
|
/* Now translate any devices (i.e. controlling sources). |
|
|
|
* This may be supurfluous because we handle dependent |
|
|
|
* This may be superfluous because we handle dependent |
|
|
|
* source devices above . . . . |
|
|
|
*/ |
|
|
|
nnodes = numdevs(c->li_line); |
|
|
|
@ -998,7 +1034,6 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub |
|
|
|
tfree(t); |
|
|
|
} /* while (nnodes--. . . . */ |
|
|
|
|
|
|
|
|
|
|
|
/* Now we finish off the line. For most components (R, C, etc), |
|
|
|
* this involves adding the component value to the buffer. |
|
|
|
* We also scan through the line for v(something) and |
|
|
|
@ -1244,7 +1279,7 @@ numnodes(char *name) |
|
|
|
|
|
|
|
/* Added this code for variable number of nodes on BSIM3SOI devices */ |
|
|
|
/* The consequence of this code is that the value returned by the */ |
|
|
|
/* inp_numnodes(c) call must be regarded as "maximun number of nodes */ |
|
|
|
/* inp_numnodes(c) call must be regarded as "maximum number of nodes */ |
|
|
|
/* for a given device type. */ |
|
|
|
/* Paolo Nenzi Jan-2001 */ |
|
|
|
|
|
|
|
@ -1266,17 +1301,16 @@ numnodes(char *name) |
|
|
|
} /* while . . . . */ |
|
|
|
|
|
|
|
/* Note: node checks must be done on #_of_node-1 because the */ |
|
|
|
/* "while" cicle increments the counter even when a model is */ |
|
|
|
/* "while" cycle increments the counter even when a model is */ |
|
|
|
/* recognized. This code may be better! */ |
|
|
|
|
|
|
|
if (i < 5) { |
|
|
|
fprintf(cp_err, "Error: too few nodes for MOS: %s\n", name); |
|
|
|
return(0); |
|
|
|
} |
|
|
|
return(i-1); /* compesate the unnecessary inrement in the while cicle */ |
|
|
|
return(i-1); /* compensate the unnecessary increment in the while cycle */ |
|
|
|
} /* if (c=='m' . . . */ |
|
|
|
|
|
|
|
|
|
|
|
if (nobjthack || (c != 'q')) |
|
|
|
return (n); |
|
|
|
|
|
|
|
@ -1360,7 +1394,7 @@ modtranslate(struct line *deck, char *subname) |
|
|
|
(void) strcpy(model, ".model"); |
|
|
|
gotone = FALSE; |
|
|
|
for (c = deck; c; c = c->li_next) { /* iterate through model def . . . */ |
|
|
|
if (prefix(model, c->li_line)) { |
|
|
|
if (ciprefix(model, c->li_line)) { |
|
|
|
gotone = TRUE; |
|
|
|
t = c->li_line; |
|
|
|
|
|
|
|
@ -1432,9 +1466,12 @@ static void |
|
|
|
devmodtranslate(struct line *deck, char *subname) |
|
|
|
{ |
|
|
|
struct line *s; |
|
|
|
char *buffer, *name, *next_name, *t, c; |
|
|
|
char *buffer, *name, *t, c; |
|
|
|
wordlist *wlsub; |
|
|
|
bool found; |
|
|
|
#ifdef XSPICE |
|
|
|
char *next_name; |
|
|
|
#endif /* XSPICE */ |
|
|
|
|
|
|
|
for (s = deck; s; s = s->li_next) { |
|
|
|
t = s->li_line; |
|
|
|
@ -1640,7 +1677,7 @@ devmodtranslate(struct line *deck, char *subname) |
|
|
|
|
|
|
|
/* Changed gettok() to gettok_node() on 12.2.2003 by SDB |
|
|
|
to enable parsing lines like "S1 10 11 (80,51) SLATCH1" |
|
|
|
which occurr in real Analog Devices SPICE models. |
|
|
|
which occur in real Analog Devices SPICE models. |
|
|
|
*/ |
|
|
|
case 'o': /* what is this element? -- SDB */ |
|
|
|
case 's': |
|
|
|
@ -1745,7 +1782,7 @@ devmodtranslate(struct line *deck, char *subname) |
|
|
|
* else, but... Note that we pretend that dependent sources and mutual |
|
|
|
* inductors have more nodes than they really do... |
|
|
|
*----------------------------------------------------------------------*/ |
|
|
|
int |
|
|
|
static int |
|
|
|
inp_numnodes(char c) |
|
|
|
{ |
|
|
|
if (isupper(c)) |
|
|
|
|