2000-04-27 22:03:57 +02:00
|
|
|
/**********
|
|
|
|
|
Copyright 1990 Regents of the University of California. All rights reserved.
|
|
|
|
|
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
|
2000-09-03 11:00:08 +02:00
|
|
|
Modified: 2000 AlansFixes
|
2005-05-30 22:28:29 +02:00
|
|
|
$Id$
|
2000-04-27 22:03:57 +02:00
|
|
|
**********/
|
|
|
|
|
|
2010-01-15 23:05:23 +01:00
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
* encapsulated string assembly in translate() and finishLine()
|
|
|
|
|
* this string facility (bxx_buffer) mainly abstracts away buffer allocation.
|
|
|
|
|
* this fixes a buffer overflow in finishLine, caused by lengthy descriptions
|
|
|
|
|
* of the kind:
|
|
|
|
|
* B1 1 2 I=v(1)+v(2)+v(3)+...
|
|
|
|
|
* Larice, 22nd Aug 2009
|
|
|
|
|
*----------------------------------------------------------------------------*/
|
|
|
|
|
|
2005-04-04 12:38:45 +02:00
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
* 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
|
|
|
|
|
*----------------------------------------------------------------------------*/
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
* 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
|
|
|
|
|
* list changes when POLY is used.
|
|
|
|
|
* Major changes include:
|
|
|
|
|
* -- Added lots of comments which (hopefully) elucidate the steps taken
|
|
|
|
|
* by the program during its processing.
|
|
|
|
|
* -- Re-wrote translate, which does the processing of each card.
|
|
|
|
|
* Please direct comments/questions/complaints to Stuart Brorson:
|
|
|
|
|
* mailto:sdb@cloud9.net
|
|
|
|
|
*-----------------------------------------------------------------------------*/
|
|
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/*
|
|
|
|
|
* Expand subcircuits. This is very spice-dependent. Bug fixes by Norbert
|
|
|
|
|
* Jeske on 10/5/85.
|
|
|
|
|
*/
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/*======================================================================*
|
|
|
|
|
* Expand all subcircuits in the deck. This handles imbedded .subckt
|
|
|
|
|
* definitions. The variables substart, subend, and subinvoke can be used
|
|
|
|
|
* to redefine the controls used. The syntax is invariant though.
|
|
|
|
|
* NOTE: the deck must be passed without the title line.
|
|
|
|
|
* What we do is as follows: first make one pass through the circuit
|
|
|
|
|
* and collect all of the subcircuits. Then, whenever a line that starts
|
|
|
|
|
* with 'x' is found, copy the subcircuit associated with that name and
|
|
|
|
|
* splice it in. A few of the problems: the nodes in the spliced-in
|
|
|
|
|
* stuff must be unique, so when we copy it, append "subcktname:" to
|
|
|
|
|
* each node. If we are in a nested subcircuit, use foo:bar:...:node.
|
|
|
|
|
* Then we have to systematically change all references to the renamed
|
|
|
|
|
* nodes. On top of that, we have to know how many args BJT's have,
|
|
|
|
|
* so we have to keep track of model names.
|
|
|
|
|
*======================================================================*/
|
2010-03-20 16:32:23 +01:00
|
|
|
/*#define TRACE*/
|
2000-04-27 22:03:57 +02:00
|
|
|
#include "ngspice.h"
|
|
|
|
|
#include "cpdefs.h"
|
|
|
|
|
#include "ftedefs.h"
|
|
|
|
|
#include "fteinp.h"
|
|
|
|
|
|
2010-01-15 23:05:23 +01:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
#ifdef XSPICE
|
|
|
|
|
/* gtri - add - wbk - 11/9/90 - include MIF function prototypes */
|
|
|
|
|
#include "mifproto.h"
|
|
|
|
|
/* gtri - end - wbk - 11/9/90 */
|
|
|
|
|
#endif
|
|
|
|
|
|
2000-06-27 18:09:02 +02:00
|
|
|
#include "subckt.h"
|
|
|
|
|
#include "variable.h"
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2005-05-30 22:28:29 +02:00
|
|
|
#include "numparam/numpaif.h"
|
2003-09-25 19:21:28 +02:00
|
|
|
|
2009-04-05 14:26:19 +02:00
|
|
|
extern void line_free_x(struct line * deck, bool recurse);
|
|
|
|
|
#define line_free(line,flag) { line_free_x(line,flag); line = NULL; }
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/* ----- static declarations ----- */
|
2000-04-27 22:03:57 +02:00
|
|
|
static struct line * doit(struct line *deck);
|
|
|
|
|
static int translate(struct line *deck, char *formal, char *actual, char *scname,
|
|
|
|
|
char *subname);
|
2010-01-15 23:05:23 +01:00
|
|
|
struct bxx_buffer;
|
|
|
|
|
static void finishLine(struct bxx_buffer *dst, char *src, char *scname);
|
2000-04-27 22:03:57 +02:00
|
|
|
static int settrans(char *formal, char *actual, char *subname);
|
2010-01-15 23:05:23 +01:00
|
|
|
static char * gettrans(const char *name, const char *name_end);
|
2000-04-27 22:03:57 +02:00
|
|
|
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);
|
2005-04-04 12:38:45 +02:00
|
|
|
static int inp_numnodes(char c);
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/*---------------------------------------------------------------------
|
|
|
|
|
* table is used in settrans and gettrans -- it holds the netnames used
|
|
|
|
|
* in the .subckt definition (t_old), and in the subcircuit invocation
|
|
|
|
|
* (t_new)
|
|
|
|
|
*--------------------------------------------------------------------*/
|
|
|
|
|
static struct tab {
|
|
|
|
|
char *t_old;
|
|
|
|
|
char *t_new;
|
|
|
|
|
} table[512]; /* That had better be enough. */
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/*---------------------------------------------------------------------
|
|
|
|
|
* subs is the linked list which holds the .subckt definitions
|
|
|
|
|
* found during processing.
|
|
|
|
|
*--------------------------------------------------------------------*/
|
2000-04-27 22:03:57 +02:00
|
|
|
struct subs {
|
2003-07-23 21:36:39 +02:00
|
|
|
char *su_name; /* The .subckt name. */
|
2005-04-04 12:38:45 +02:00
|
|
|
char *su_args; /* The .subckt arguments, space separated. */
|
2000-04-27 22:03:57 +02:00
|
|
|
int su_numargs;
|
2003-07-23 21:36:39 +02:00
|
|
|
struct line *su_def; /* Pointer to the .subckt definition. */
|
2000-04-27 22:03:57 +02:00
|
|
|
struct subs *su_next;
|
|
|
|
|
} ;
|
2005-02-08 22:07:37 +01:00
|
|
|
|
|
|
|
|
|
2004-06-21 11:58:25 +02:00
|
|
|
/* submod is the list of original model names, modnames is the
|
|
|
|
|
* list of translated names (i.e. after subckt expansion)
|
|
|
|
|
*/
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
static wordlist *modnames, *submod;
|
|
|
|
|
static struct subs *subs = NULL;
|
|
|
|
|
static bool nobjthack = FALSE;
|
2005-04-24 23:17:31 +02:00
|
|
|
/* flag indicating use of the experimental numparams library */
|
|
|
|
|
static bool use_numparams = FALSE;
|
2005-04-04 12:38:45 +02:00
|
|
|
|
2005-04-24 23:17:31 +02:00
|
|
|
static char start[32], sbend[32], invoke[32], model[32];
|
|
|
|
|
|
2005-05-06 09:11:02 +02:00
|
|
|
static char node[128][128];
|
|
|
|
|
static int numgnode;
|
|
|
|
|
|
2009-08-17 22:13:51 +02:00
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
|
inp_subcktexpand is the top level function which translates
|
|
|
|
|
.subckts into mainlined code. Note that there are several things
|
|
|
|
|
we need to do: 1. Find all .subckt definitions & stick them
|
|
|
|
|
into a list. 2. Find all subcircuit invocations (refdes X)
|
|
|
|
|
and replace them with the .subckt definition stored earlier.
|
|
|
|
|
3. Do parameter substitution.
|
|
|
|
|
|
|
|
|
|
The algorithm is as follows:
|
|
|
|
|
1. Define some aliases for .subckt, .ends, etc.
|
|
|
|
|
2. First numparam pass: substitute paramterized tokens by
|
|
|
|
|
intermediate values 1000000001 etc.
|
|
|
|
|
3. Make a list node[] of global nodes
|
|
|
|
|
4. Clean up parens around netnames
|
|
|
|
|
5. Call doit, which does the actual translation.
|
|
|
|
|
6. Second numparam pass: Do final substitution
|
|
|
|
|
7. Check the results & return.
|
|
|
|
|
inp_subcktexpand takes as argument a pointer to deck, and
|
|
|
|
|
it returns a pointer to the same deck after the new subcircuits
|
|
|
|
|
are spliced in.
|
2009-08-22 20:12:17 +02:00
|
|
|
-------------------------------------------------------------------*/
|
2000-04-27 22:03:57 +02:00
|
|
|
struct line *
|
|
|
|
|
inp_subcktexpand(struct line *deck)
|
|
|
|
|
{
|
|
|
|
|
struct line *ll, *c;
|
|
|
|
|
char *s;
|
2010-07-03 19:55:44 +02:00
|
|
|
int ok = 0;
|
2005-05-06 09:11:02 +02:00
|
|
|
char *t;
|
|
|
|
|
int i;
|
2005-04-04 12:38:45 +02:00
|
|
|
wordlist *wl;
|
|
|
|
|
modnames = NULL;
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2010-07-17 22:48:20 +02:00
|
|
|
if(!cp_getvar("substart", CP_STRING, start))
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) strcpy(start, ".subckt");
|
2010-07-17 22:48:20 +02:00
|
|
|
if(!cp_getvar("subend", CP_STRING, sbend))
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) strcpy(sbend, ".ends");
|
2010-07-17 22:48:20 +02:00
|
|
|
if(!cp_getvar("subinvoke", CP_STRING, invoke))
|
2005-04-04 12:38:45 +02:00
|
|
|
(void) strcpy(invoke, "x");
|
2010-07-17 22:48:20 +02:00
|
|
|
if(!cp_getvar("modelcard", CP_STRING, model))
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) strcpy(model, ".model");
|
2010-07-17 22:48:20 +02:00
|
|
|
if(!cp_getvar("modelline", CP_STRING, model))
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) strcpy(model, ".model");
|
2010-07-20 20:52:19 +02:00
|
|
|
nobjthack = cp_getvar("nobjthack", CP_BOOL, NULL);
|
2005-04-24 23:17:31 +02:00
|
|
|
|
2010-07-20 20:52:19 +02:00
|
|
|
use_numparams = cp_getvar("numparams", CP_BOOL, NULL);
|
2005-04-24 23:17:31 +02:00
|
|
|
|
2007-10-08 23:10:34 +02:00
|
|
|
use_numparams = TRUE;
|
|
|
|
|
|
2003-09-25 19:21:28 +02:00
|
|
|
/* deck has .control sections already removed, but not comments */
|
2005-04-24 23:17:31 +02:00
|
|
|
if ( use_numparams ) {
|
2005-04-17 00:45:32 +02:00
|
|
|
|
2008-05-12 17:52:59 +02:00
|
|
|
#ifdef TRACE
|
2007-10-08 23:10:34 +02:00
|
|
|
fprintf(stderr,"Numparams is processing this deck:\n");
|
2005-04-17 00:45:32 +02:00
|
|
|
c=deck;
|
|
|
|
|
while( c!=NULL) {
|
2007-10-08 23:10:34 +02:00
|
|
|
fprintf(stderr,"%3d:%s\n",c->li_linenum, c->li_line);
|
2005-04-17 00:45:32 +02:00
|
|
|
c= c->li_next;
|
|
|
|
|
}
|
2008-05-12 17:52:59 +02:00
|
|
|
#endif /* TRACE */
|
2007-10-08 23:10:34 +02:00
|
|
|
|
2005-04-24 23:17:31 +02:00
|
|
|
ok = nupa_signal( NUPADECKCOPY, NULL);
|
2007-10-08 23:10:34 +02:00
|
|
|
/* get the subckt/model names from the deck */
|
2005-04-24 23:17:31 +02:00
|
|
|
c=deck;
|
|
|
|
|
while ( c != NULL) { /* first Numparam pass */
|
2007-10-08 23:10:34 +02:00
|
|
|
if ( ciprefix( ".subckt", c->li_line ) )
|
|
|
|
|
nupa_scan(c->li_line, c->li_linenum, TRUE);
|
|
|
|
|
if ( ciprefix( ".model", c->li_line ) )
|
|
|
|
|
nupa_scan(c->li_line, c->li_linenum, FALSE);
|
2005-04-24 23:17:31 +02:00
|
|
|
c= c->li_next;
|
|
|
|
|
}
|
2003-09-25 19:21:28 +02:00
|
|
|
c=deck;
|
2009-04-05 20:31:25 +02:00
|
|
|
while ( c != NULL) { /* first Numparam pass */
|
2003-09-25 19:21:28 +02:00
|
|
|
c->li_line = nupa_copy(c->li_line, c->li_linenum);
|
|
|
|
|
c= c->li_next;
|
|
|
|
|
}
|
2007-10-08 23:10:34 +02:00
|
|
|
/* now copy instances */
|
2005-04-17 00:45:32 +02:00
|
|
|
|
2008-05-12 17:52:59 +02:00
|
|
|
#ifdef TRACE
|
2007-10-08 23:10:34 +02:00
|
|
|
fprintf(stderr,"Numparams transformed deck:\n");
|
2005-04-17 00:45:32 +02:00
|
|
|
c=deck;
|
|
|
|
|
while( c!=NULL) {
|
2007-10-08 23:10:34 +02:00
|
|
|
fprintf(stderr,"%3d:%s\n",c->li_linenum, c->li_line);
|
2005-04-17 00:45:32 +02:00
|
|
|
c= c->li_next;
|
|
|
|
|
}
|
2008-05-12 17:52:59 +02:00
|
|
|
#endif /* TRACE */
|
2005-04-17 00:45:32 +02:00
|
|
|
|
2005-04-24 23:17:31 +02:00
|
|
|
}
|
2003-09-25 19:21:28 +02:00
|
|
|
|
2005-04-04 12:38:45 +02:00
|
|
|
/* 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;
|
2005-05-06 09:11:02 +02:00
|
|
|
txfree(gettok(&s)); /* discard the model keyword */
|
2005-04-04 12:38:45 +02:00
|
|
|
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);
|
|
|
|
|
}
|
2005-04-24 23:17:31 +02:00
|
|
|
#endif /* TRACE */
|
2005-04-04 12:38:45 +02:00
|
|
|
|
2005-05-06 09:11:02 +02:00
|
|
|
/* Added by H.Tanaka to find global nodes */
|
|
|
|
|
for(i=0;i<128;i++) strcpy(node[i],"");/* Clear global node holder */
|
|
|
|
|
for (c = deck; c; c = c->li_next) {
|
2010-01-17 15:49:42 +01:00
|
|
|
if (ciprefix(".global", c->li_line)) {
|
|
|
|
|
s = c->li_line;
|
|
|
|
|
txfree(gettok(&s));
|
|
|
|
|
numgnode=0;
|
|
|
|
|
while(*s) {
|
|
|
|
|
i=0;
|
|
|
|
|
t=s;
|
|
|
|
|
for (/*s*/; *s && !isspace(*s); s++) i++;
|
|
|
|
|
strncpy(node[numgnode],t,i);
|
|
|
|
|
if(i>0 && t[i-1] != '\0')
|
|
|
|
|
node[numgnode][i] = '\0';
|
|
|
|
|
while (isspace(*s)) s++;
|
|
|
|
|
numgnode++;
|
|
|
|
|
} /* node[] holds name of global node */
|
2005-05-06 09:11:02 +02:00
|
|
|
#ifdef TRACE
|
2010-01-17 15:49:42 +01:00
|
|
|
printf("***Global node option has been found.***\n");
|
|
|
|
|
for(i=0;i<numgnode;i++)
|
|
|
|
|
printf("***Global node no.%d is %s.***\n",i,node[i]);
|
|
|
|
|
printf("\n");
|
2005-05-06 09:11:02 +02:00
|
|
|
#endif /* TRACE */
|
2010-01-17 15:49:42 +01:00
|
|
|
c->li_line[0] = '*'; /* comment it out */
|
|
|
|
|
}/* if(ciprefix.. */
|
2005-05-06 09:11:02 +02:00
|
|
|
} /* for(c=deck.. */
|
2005-04-04 12:38:45 +02:00
|
|
|
|
2010-05-16 13:55:07 +02:00
|
|
|
/* 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 */
|
2010-05-16 18:31:03 +02:00
|
|
|
|
|
|
|
|
char *s = c->li_line;
|
|
|
|
|
|
|
|
|
|
if(*s == '*') /* skip comment */
|
2010-05-16 13:55:07 +02:00
|
|
|
continue;
|
|
|
|
|
|
2010-05-16 18:31:03 +02:00
|
|
|
if (ciprefix(start, s)) { /* if we find .subckt . . . */
|
2004-01-10 22:39:36 +01:00
|
|
|
#ifdef TRACE
|
2010-05-16 18:31:03 +02:00
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In inp_subcktexpand, found a .subckt: %s\n", s);
|
|
|
|
|
#endif
|
|
|
|
|
while (*s && *s != '(') /* search opening paren */
|
|
|
|
|
s++;
|
|
|
|
|
|
|
|
|
|
if (*s == '(') {
|
|
|
|
|
int level = 0;
|
|
|
|
|
do {
|
|
|
|
|
/* strip outer parens '(' ')', just the first pair */
|
|
|
|
|
if(*s == '(' && level++ == 0) {
|
|
|
|
|
*s = ' ';
|
|
|
|
|
}
|
|
|
|
|
if(*s == ')' && --level == 0) {
|
|
|
|
|
*s = ' ';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} while(*s++);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (*s=='.') {
|
|
|
|
|
continue; /* skip .commands */
|
2010-05-16 13:55:07 +02:00
|
|
|
}
|
2010-05-16 18:31:03 +02:00
|
|
|
else { /* any other line . . . */
|
|
|
|
|
while (*s && !isspace(*s)) /* skip first token */
|
|
|
|
|
s++;
|
|
|
|
|
while (*s && isspace(*s)) /* skip whitespace */
|
2010-05-16 13:55:07 +02:00
|
|
|
s++;
|
2010-05-16 18:31:03 +02:00
|
|
|
|
2010-05-16 13:55:07 +02:00
|
|
|
if (*s == '(') {
|
2010-05-16 18:31:03 +02:00
|
|
|
int level = 0;
|
|
|
|
|
do {
|
|
|
|
|
/* strip outer parens '(' ')', just the first pair, why ? */
|
|
|
|
|
if(*s == '(' && level++ == 0) {
|
|
|
|
|
*s = ' ';
|
|
|
|
|
}
|
|
|
|
|
if(*s == ')' && --level == 0) {
|
|
|
|
|
*s = ' ';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} while(*s++);
|
2010-05-16 13:55:07 +02:00
|
|
|
} /* if (*s == '(' . . . */
|
|
|
|
|
} /* any other line */
|
2003-07-23 21:36:39 +02:00
|
|
|
} /* for (c = deck . . . */
|
|
|
|
|
|
|
|
|
|
/* doit does the actual splicing in of the .subckt . . . */
|
2004-01-10 22:39:36 +01:00
|
|
|
#ifdef TRACE
|
|
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In inp_subcktexpand, about to call doit.\n");
|
2005-04-24 23:17:31 +02:00
|
|
|
#endif /* TRACE */
|
2000-04-27 22:03:57 +02:00
|
|
|
ll = doit(deck);
|
|
|
|
|
|
2005-05-06 09:11:02 +02:00
|
|
|
/* SJB: free up the modnames linked list now we are done with it */
|
2005-04-04 12:38:45 +02:00
|
|
|
if(modnames != NULL) {
|
|
|
|
|
wl_free(modnames);
|
|
|
|
|
modnames = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-07 16:49:51 +01:00
|
|
|
/* Count numbers of line in deck after expansion */
|
|
|
|
|
if (ll!=NULL) {
|
|
|
|
|
dynMaxckt = 0; /* number of lines in deck after expansion */
|
|
|
|
|
for (c = ll; c; c = c->li_next)
|
|
|
|
|
dynMaxckt++;
|
|
|
|
|
}
|
2000-09-03 11:00:08 +02:00
|
|
|
/* Now check to see if there are still subckt instances undefined... */
|
2009-03-07 16:49:51 +01:00
|
|
|
if (ll!=NULL) {
|
|
|
|
|
for (c = ll; c; c = c->li_next) {
|
|
|
|
|
if (ciprefix(invoke, c->li_line)) {
|
|
|
|
|
fprintf(cp_err, "Error: unknown subckt: %s\n", c->li_line);
|
|
|
|
|
if ( use_numparams ) {
|
2009-10-04 13:48:37 +02:00
|
|
|
ok = ok && nupa_signal(NUPAEVALDONE, NULL);
|
2009-03-07 16:49:51 +01:00
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-04-24 23:17:31 +02:00
|
|
|
if ( use_numparams ) {
|
2003-09-25 19:21:28 +02:00
|
|
|
/* the NUMPARAM final line translation pass */
|
|
|
|
|
ok= ok && nupa_signal(NUPASUBDONE, NULL);
|
|
|
|
|
c= ll;
|
2005-04-17 00:45:32 +02:00
|
|
|
while (c != NULL) {
|
2010-06-19 20:23:32 +02:00
|
|
|
/* 'param' .meas statements can have dependencies on measurement values */
|
|
|
|
|
/* need to skip evaluating here and evaluate after other .meas statements */
|
|
|
|
|
if ( ciprefix( ".meas", c->li_line ) ) {
|
|
|
|
|
if ( !strstr( c->li_line, "param" ) )
|
|
|
|
|
nupa_eval( c->li_line, c->li_linenum, c->li_linenum_orig);
|
|
|
|
|
} else {
|
|
|
|
|
nupa_eval( c->li_line, c->li_linenum, c->li_linenum_orig);
|
|
|
|
|
}
|
|
|
|
|
c= c->li_next;
|
2005-04-17 00:45:32 +02:00
|
|
|
}
|
2008-05-12 17:52:59 +02:00
|
|
|
#ifdef TRACE
|
2007-10-08 23:10:34 +02:00
|
|
|
fprintf(stderr,"Numparams converted deck:\n");
|
2005-04-17 00:45:32 +02:00
|
|
|
c=ll;
|
|
|
|
|
while( c!=NULL) {
|
2007-10-08 23:10:34 +02:00
|
|
|
fprintf(stderr,"%3d:%s\n",c->li_linenum, c->li_line);
|
2005-04-17 00:45:32 +02:00
|
|
|
c= c->li_next;
|
2003-09-25 19:21:28 +02:00
|
|
|
}
|
2008-05-12 17:52:59 +02:00
|
|
|
#endif /* TRACE */
|
2009-04-05 20:31:25 +02:00
|
|
|
|
2009-11-09 10:15:21 +01:00
|
|
|
/*nupa_list_params(stdout);*/
|
2007-10-08 23:10:34 +02:00
|
|
|
nupa_copy_inst_dico();
|
2009-04-05 20:31:25 +02:00
|
|
|
ok= ok && nupa_signal(NUPAEVALDONE, NULL);
|
2003-09-25 19:21:28 +02:00
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
return (ll); /* return the spliced deck. */
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
#define MAXNEST 21
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
|
/* doit does the actual substitution of .subckts. */
|
|
|
|
|
/* It takes two passes: the first extracts .subckts */
|
|
|
|
|
/* and sticks pointer to them into the linked list sss. It does */
|
|
|
|
|
/* the extraction recursively. Then, it look for subcircuit */
|
|
|
|
|
/* invocations and substitutes the stored .subckt into */
|
|
|
|
|
/* the main circuit file. */
|
|
|
|
|
/* It takes as argument a pointer to the deck, and returns a */
|
|
|
|
|
/* pointer to the deck after the subcircuit has been spliced in. */
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
2000-04-27 22:03:57 +02:00
|
|
|
static struct line *
|
|
|
|
|
doit(struct line *deck)
|
|
|
|
|
{
|
|
|
|
|
struct line *c, *last, *lc, *lcc;
|
2003-09-25 19:21:28 +02:00
|
|
|
struct line *savenext;
|
2009-10-04 13:48:37 +02:00
|
|
|
struct subs *sssfree = (struct subs *) NULL, *sss = (struct subs *) NULL, *ks; /* *sss and *ks temporarily hold decks to substitute */
|
2000-04-27 22:03:57 +02:00
|
|
|
char *s, *t, *scname, *subname;
|
|
|
|
|
int nest, numpasses = MAXNEST, i;
|
|
|
|
|
bool gotone;
|
|
|
|
|
wordlist *tmodnames = modnames;
|
|
|
|
|
wordlist *tsubmod = submod;
|
|
|
|
|
struct subs *ts = subs;
|
|
|
|
|
int error;
|
|
|
|
|
|
|
|
|
|
/* Save all the old stuff... */
|
|
|
|
|
subs = NULL;
|
|
|
|
|
submod = NULL;
|
|
|
|
|
|
2004-01-10 22:39:36 +01:00
|
|
|
#ifdef TRACE
|
|
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In doit, about to start first pass through deck.\n");
|
2005-04-04 12:38:45 +02:00
|
|
|
for(c=deck;c; c=c->li_next)
|
|
|
|
|
printf(" %s\n",c->li_line);
|
2004-01-10 22:39:36 +01:00
|
|
|
#endif
|
2003-07-23 21:36:39 +02:00
|
|
|
/* First pass: xtract all the .subckts and stick pointers to them into sss. */
|
|
|
|
|
for (last = deck, lc = NULL; last; ) {
|
2007-10-08 23:10:34 +02:00
|
|
|
|
2005-04-04 12:38:45 +02:00
|
|
|
if (ciprefix(sbend, last->li_line)) { /* if line == .ends */
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err, "Error: misplaced %s line: %s\n", sbend,
|
|
|
|
|
last->li_line);
|
|
|
|
|
return (NULL);
|
2003-07-23 21:36:39 +02:00
|
|
|
}
|
2005-04-04 12:38:45 +02:00
|
|
|
else if (ciprefix(start, last->li_line)) { /* if line == .subckt */
|
2003-07-23 21:36:39 +02:00
|
|
|
if (last->li_next == NULL) { /* first check that next line is non null */
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err, "Error: no %s line.\n", sbend);
|
|
|
|
|
return (NULL);
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
lcc = NULL;
|
2000-04-27 22:03:57 +02:00
|
|
|
wl_free(submod);
|
|
|
|
|
submod = NULL;
|
|
|
|
|
gotone = FALSE;
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* Here we loop through the deck looking for .subckt and .ends cards.
|
|
|
|
|
* At the end of this section, last will point to the location of the
|
|
|
|
|
* .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) {
|
2005-04-04 12:38:45 +02:00
|
|
|
if (ciprefix(sbend, c->li_line)) { /* found a .ends */
|
2000-04-27 22:03:57 +02:00
|
|
|
if (!nest)
|
2003-07-23 21:36:39 +02:00
|
|
|
break; /* nest = 0 means we have balanced .subckt and .ends */
|
2000-04-27 22:03:57 +02:00
|
|
|
else {
|
2003-07-23 21:36:39 +02:00
|
|
|
nest--; /* decrement nesting, and assign lcc to the current card */
|
|
|
|
|
lcc = c; /* (lcc points to the position of the .ends) */
|
|
|
|
|
continue; /* then continue looping */
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2005-04-04 12:38:45 +02:00
|
|
|
} else if (ciprefix(start, c->li_line)) /* if .subckt, increment nesting */
|
2000-04-27 22:03:57 +02:00
|
|
|
nest++;
|
2003-07-23 21:36:39 +02:00
|
|
|
lcc = c; /* lcc points to current pos of c */
|
|
|
|
|
} /* for (nest = 0 . . . */
|
|
|
|
|
|
|
|
|
|
/* Check to see if we have looped through remainder of deck without finding .ends */
|
|
|
|
|
if (!c) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err, "Error: no %s line.\n", sbend);
|
2003-07-23 21:36:39 +02:00
|
|
|
return (NULL);
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
|
2009-04-05 14:26:19 +02:00
|
|
|
sssfree = sss = alloc(struct subs);
|
2003-07-23 21:36:39 +02:00
|
|
|
if (!lcc) /* if lcc is null, then no .ends was found. */
|
2000-04-27 22:03:57 +02:00
|
|
|
lcc = last;
|
2005-04-24 23:17:31 +02:00
|
|
|
if ( use_numparams==FALSE )
|
2003-07-23 21:36:39 +02:00
|
|
|
lcc->li_next = NULL; /* shouldn't we free some memory here????? */
|
|
|
|
|
|
|
|
|
|
/* At this point, last points to the .subckt card, and lcc points to the .ends card */
|
|
|
|
|
|
|
|
|
|
/* what does this do!??!?! */
|
2000-04-27 22:03:57 +02:00
|
|
|
if (lc)
|
|
|
|
|
lc->li_next = c->li_next;
|
|
|
|
|
else
|
|
|
|
|
deck = c->li_next;
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* Now put the .subckt definition found into sss */
|
|
|
|
|
sss->su_def = last->li_next;
|
|
|
|
|
s = last->li_line;
|
|
|
|
|
txfree(gettok(&s));
|
2000-04-27 22:03:57 +02:00
|
|
|
sss->su_name = gettok(&s);
|
|
|
|
|
sss->su_args = copy(s);
|
2003-07-23 21:36:39 +02:00
|
|
|
/* count the number of args in the .subckt line */
|
2000-04-27 22:03:57 +02:00
|
|
|
for (sss->su_numargs = 0, i = 0; s[i]; ) {
|
|
|
|
|
while (isspace(s[i]))
|
|
|
|
|
i++;
|
|
|
|
|
if (s[i]) {
|
|
|
|
|
sss->su_numargs++;
|
|
|
|
|
while (s[i] && !isspace(s[i]))
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
sss->su_next = subs;
|
|
|
|
|
subs = sss; /* Now that sss is built, assign it to subs */
|
2000-04-27 22:03:57 +02:00
|
|
|
last = c->li_next;
|
|
|
|
|
lcc = subs->su_def;
|
2003-09-25 19:21:28 +02:00
|
|
|
|
|
|
|
|
/*gp */ c->li_next = NULL; /* Numparam needs line c */
|
|
|
|
|
c->li_line[0] = '*'; /* comment it out */
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
else { /* line is neither .ends nor .subckt. */
|
|
|
|
|
/* make lc point to this card, and advance last to next card. */
|
|
|
|
|
lc = last;
|
2000-04-27 22:03:57 +02:00
|
|
|
last = last->li_next;
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
} /* for (last = deck . . . . */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* At this point, sss holds the .subckt definition found, subs holds
|
|
|
|
|
* all .subckt defs found, including this one,
|
|
|
|
|
* last points to the NULL at the end of the deck,
|
|
|
|
|
* lc points to the last non-.subckt or .ends card,
|
|
|
|
|
* and lcc points to the .ends card
|
|
|
|
|
*/
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
if (!sss) /* if sss == FALSE, we have found no subckts. Just return. */
|
2000-04-27 22:03:57 +02:00
|
|
|
return (deck);
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/* Otherwise, expand sub-subcircuits recursively. */
|
|
|
|
|
for (ks = sss = subs; sss; sss = sss->su_next) /* iterate through the list of subcircuits */
|
2000-04-27 22:03:57 +02:00
|
|
|
if (!(sss->su_def = doit(sss->su_def)))
|
|
|
|
|
return (NULL);
|
2003-07-23 21:36:39 +02:00
|
|
|
subs = ks; /* ks has held pointer to start of subcircuits list. */
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2004-01-10 22:39:36 +01:00
|
|
|
#ifdef TRACE
|
|
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In doit, about to start second pass through deck.\n");
|
2005-04-04 12:38:45 +02:00
|
|
|
for(c=deck;c; c=c->li_next)
|
|
|
|
|
printf(" %s\n",c->li_line);
|
2004-01-10 22:39:36 +01:00
|
|
|
#endif
|
|
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
error = 0;
|
2003-07-23 21:36:39 +02:00
|
|
|
/* Second pass: do the replacements. */
|
|
|
|
|
do { /* while (!error && numpasses-- && gotone) */
|
2000-04-27 22:03:57 +02:00
|
|
|
gotone = FALSE;
|
|
|
|
|
for (c = deck, lc = NULL; c; ) {
|
2003-07-23 21:36:39 +02:00
|
|
|
if (ciprefix(invoke, c->li_line)) { /* found reference to .subckt (i.e. component with refdes X) */
|
2007-10-08 23:10:34 +02:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
char *tofree, *tofree2;
|
|
|
|
|
gotone = TRUE;
|
|
|
|
|
t = tofree = s = copy(c->li_line); /* s & t hold copy of component line */
|
|
|
|
|
|
|
|
|
|
/* make scname point to first non-whitepace chars after refdes invocation
|
|
|
|
|
* e.g. if invocation is Xreference, *scname = reference
|
|
|
|
|
*/
|
|
|
|
|
tofree2 = scname = gettok(&s);
|
2007-10-08 23:10:34 +02:00
|
|
|
/*scname += strlen(invoke); */
|
2000-04-27 22:03:57 +02:00
|
|
|
while ((*scname == ' ') || (*scname == '\t') ||
|
|
|
|
|
(*scname == ':'))
|
|
|
|
|
scname++;
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* Now set s to point to last non-space chars in line (i.e.
|
|
|
|
|
* the name of the model invoked
|
|
|
|
|
*/
|
2000-04-27 22:03:57 +02:00
|
|
|
while(*s)
|
|
|
|
|
s++;
|
|
|
|
|
s--;
|
|
|
|
|
while ((*s == ' ') || (*s == '\t'))
|
|
|
|
|
*s-- = '\0';
|
|
|
|
|
while ((*s != ' ') && (*s != '\t'))
|
|
|
|
|
s--;
|
|
|
|
|
s++;
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* iterate through .subckt list and look for .subckt name invoked */
|
|
|
|
|
for (sss = subs; sss; sss = sss->su_next)
|
2000-04-27 22:03:57 +02:00
|
|
|
if (eq(sss->su_name, s))
|
|
|
|
|
break;
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/* At this point, sss points to the .subckt invoked,
|
|
|
|
|
* and scname points to the netnames
|
|
|
|
|
* involved.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If no .subckt is found, don't complain -- this might be an
|
|
|
|
|
* instance of a subckt that is defined above at higher level.
|
2000-04-27 22:03:57 +02:00
|
|
|
*/
|
|
|
|
|
if (!sss) {
|
|
|
|
|
lc = c;
|
|
|
|
|
c = c->li_next;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Now we have to replace this line with the
|
|
|
|
|
* macro definition.
|
|
|
|
|
*/
|
2003-07-23 21:36:39 +02:00
|
|
|
subname = copy(sss->su_name);
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/* make lcc point to a copy of the .subckt definition */
|
|
|
|
|
lcc = inp_deckcopy(sss->su_def);
|
|
|
|
|
|
|
|
|
|
/* Change the names of .models found in .subckts . . . */
|
2004-01-10 22:39:36 +01:00
|
|
|
if (modtranslate(lcc, scname)) /* this translates the model name in the .model line */
|
2005-02-08 22:07:37 +01:00
|
|
|
devmodtranslate(lcc, scname); /* This translates the model name on all components in the deck */
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
s = sss->su_args;
|
2003-07-23 21:36:39 +02:00
|
|
|
txfree(gettok(&t)); /* Throw out the subcircuit refdes */
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/* now invoke translate, which handles the remainder of the
|
|
|
|
|
* translation.
|
|
|
|
|
*/
|
2000-04-27 22:03:57 +02:00
|
|
|
if (!translate(lcc, s, t, scname, subname))
|
|
|
|
|
error = 1;
|
2003-07-23 21:36:39 +02:00
|
|
|
tfree(subname);
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
/* Now splice the decks together. */
|
2003-09-25 19:21:28 +02:00
|
|
|
savenext = c->li_next;
|
2005-04-24 23:17:31 +02:00
|
|
|
if ( use_numparams==FALSE ) {
|
|
|
|
|
/* old style: c will drop a dangling pointer: memory leak */
|
|
|
|
|
if (lc)
|
|
|
|
|
lc->li_next = lcc;
|
|
|
|
|
else
|
|
|
|
|
deck = lcc;
|
2003-09-25 19:21:28 +02:00
|
|
|
} else {
|
|
|
|
|
/* ifdef NUMPARAMS, keep the invoke line as a comment */
|
|
|
|
|
c->li_next = lcc;
|
|
|
|
|
c->li_line[0] = '*'; /* comment it out */
|
|
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
while (lcc->li_next != NULL)
|
|
|
|
|
lcc = lcc->li_next;
|
|
|
|
|
lcc->li_next = c->li_next;
|
2003-09-25 19:21:28 +02:00
|
|
|
lcc->li_next = savenext;
|
2000-04-27 22:03:57 +02:00
|
|
|
c = lcc->li_next;
|
|
|
|
|
lc = lcc;
|
2003-07-23 21:36:39 +02:00
|
|
|
tfree(tofree);
|
|
|
|
|
tfree(tofree2);
|
|
|
|
|
} /* if (ciprefix(invoke, c->li_line)) . . . */
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
lc = c;
|
|
|
|
|
c = c->li_next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while (!error && numpasses-- && gotone);
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
if (!numpasses) {
|
|
|
|
|
fprintf(cp_err, "Error: infinite subckt recursion\n");
|
|
|
|
|
return (NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-04 12:38:45 +02:00
|
|
|
#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
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
|
return NULL; /* error message already reported; should free( ) */
|
|
|
|
|
|
|
|
|
|
subs = ts;
|
|
|
|
|
modnames = tmodnames;
|
|
|
|
|
submod = tsubmod;
|
2009-04-05 14:26:19 +02:00
|
|
|
/*
|
|
|
|
|
struct subs {
|
|
|
|
|
char *su_name;
|
|
|
|
|
char *su_args;
|
|
|
|
|
int su_numargs;
|
|
|
|
|
struct line *su_def;
|
|
|
|
|
struct subs *su_next;
|
|
|
|
|
} ;
|
|
|
|
|
*/
|
|
|
|
|
while(sssfree) {
|
|
|
|
|
struct subs *sss2 = sssfree;
|
|
|
|
|
sssfree = sssfree->su_next;
|
|
|
|
|
tfree(sss2->su_name);
|
|
|
|
|
tfree(sss2->su_args);
|
|
|
|
|
line_free(sss2->su_def, TRUE);
|
|
|
|
|
tfree(sss2);
|
|
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
return (deck);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
|
/* Copy a deck, including the actual lines. */
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
2000-04-27 22:03:57 +02:00
|
|
|
struct line *
|
|
|
|
|
inp_deckcopy(struct line *deck)
|
|
|
|
|
{
|
|
|
|
|
struct line *d = NULL, *nd = NULL;
|
|
|
|
|
|
|
|
|
|
while (deck) {
|
|
|
|
|
if (nd) {
|
|
|
|
|
d->li_next = alloc(struct line);
|
|
|
|
|
d = d->li_next;
|
|
|
|
|
} else
|
|
|
|
|
nd = d = alloc(struct line);
|
|
|
|
|
d->li_linenum = deck->li_linenum;
|
|
|
|
|
d->li_line = copy(deck->li_line);
|
|
|
|
|
if (deck->li_error)
|
2007-10-08 23:10:34 +02:00
|
|
|
d->li_error = copy(deck->li_error);
|
2000-04-27 22:03:57 +02:00
|
|
|
d->li_actual = inp_deckcopy(deck->li_actual);
|
|
|
|
|
deck = deck->li_next;
|
|
|
|
|
}
|
|
|
|
|
return (nd);
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-15 23:05:23 +01:00
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
|
* struct bxx_buffer,
|
|
|
|
|
* a string assembly facility.
|
|
|
|
|
*
|
|
|
|
|
* usage:
|
|
|
|
|
*
|
|
|
|
|
* struct bxx_buffer thing;
|
|
|
|
|
* bxx_init(&thing);
|
|
|
|
|
* ...
|
|
|
|
|
* while(...) {
|
|
|
|
|
* bxx_rewind(&thing);
|
|
|
|
|
* ...
|
|
|
|
|
* bxx_putc(&thing, ...)
|
|
|
|
|
* bxx_printf(&thing, ...)
|
|
|
|
|
* bxx_put_cstring(&thing, ...)
|
|
|
|
|
* bxx_put_substring(&thing, ...)
|
|
|
|
|
* ...
|
|
|
|
|
* strcpy(bxx_buffer(&thing)
|
|
|
|
|
* }
|
|
|
|
|
* ..
|
|
|
|
|
* bxx_free(&thing)
|
|
|
|
|
*
|
|
|
|
|
* main aspect:
|
|
|
|
|
* reallocates/extends its buffer itself.
|
|
|
|
|
*
|
|
|
|
|
* note:
|
|
|
|
|
* during asssembly the internal buffer is
|
|
|
|
|
* not necessarily '\0' terminated.
|
|
|
|
|
* but will be when bxx_buffer() is invoked
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
struct bxx_buffer
|
|
|
|
|
{
|
|
|
|
|
char *dst;
|
|
|
|
|
char *limit;
|
|
|
|
|
char *buffer;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* must be a power of 2 */
|
|
|
|
|
static const int bxx_chunksize = 1024;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bxx_init(struct bxx_buffer *t)
|
|
|
|
|
{
|
|
|
|
|
/* assert(0 == (bxx_chunksize & (bxx_chunksize - 1))); */
|
|
|
|
|
|
2010-07-01 21:52:23 +02:00
|
|
|
t->buffer = (char*) tmalloc(bxx_chunksize);
|
2010-01-15 23:05:23 +01:00
|
|
|
|
|
|
|
|
t->dst = t->buffer;
|
|
|
|
|
t->limit = t->buffer + bxx_chunksize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bxx_free(struct bxx_buffer *t)
|
|
|
|
|
{
|
|
|
|
|
tfree(t->buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bxx_rewind(struct bxx_buffer *t)
|
|
|
|
|
{
|
|
|
|
|
t->dst = t->buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bxx_extend(struct bxx_buffer *t, int howmuch)
|
|
|
|
|
{
|
|
|
|
|
int pos = t->dst - t->buffer;
|
|
|
|
|
int len = t->limit - t->buffer;
|
|
|
|
|
|
|
|
|
|
/* round up */
|
|
|
|
|
howmuch += (bxx_chunksize - 1);
|
|
|
|
|
howmuch &= ~(bxx_chunksize - 1);
|
|
|
|
|
|
2010-07-01 21:52:23 +02:00
|
|
|
t->buffer = (char*) trealloc(t->buffer, len += howmuch);
|
2010-01-15 23:05:23 +01:00
|
|
|
|
|
|
|
|
t->dst = t->buffer + pos;
|
|
|
|
|
t->limit = t->buffer + len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bxx_printf(struct bxx_buffer *t, const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
2010-09-07 22:07:57 +02:00
|
|
|
for (;;) {
|
2010-02-25 22:43:03 +01:00
|
|
|
int ret;
|
|
|
|
|
int size = t->limit - t->dst;
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
ret = vsnprintf(t->dst, size, fmt, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
if(ret == -1) {
|
2010-01-15 23:05:23 +01:00
|
|
|
bxx_extend(t, bxx_chunksize);
|
|
|
|
|
} else if(ret >= size) {
|
|
|
|
|
bxx_extend(t, ret - size + 1);
|
|
|
|
|
} else {
|
|
|
|
|
t->dst += ret;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
va_end(ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline char
|
|
|
|
|
bxx_putc(struct bxx_buffer *t, char c)
|
|
|
|
|
{
|
|
|
|
|
if(t->dst >= t->limit)
|
|
|
|
|
bxx_extend(t, 1);
|
|
|
|
|
return *(t->dst)++ = c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bxx_put_cstring(struct bxx_buffer *t, const char *cstring)
|
|
|
|
|
{
|
|
|
|
|
while(*cstring)
|
|
|
|
|
bxx_putc(t, *cstring++);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bxx_put_substring(struct bxx_buffer *t, const char *str, const char *end)
|
|
|
|
|
{
|
|
|
|
|
while(str < end)
|
|
|
|
|
bxx_putc(t, *str++);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
bxx_buffer(struct bxx_buffer *t)
|
|
|
|
|
{
|
|
|
|
|
if((t->dst == t->buffer) || (t->dst[-1] != '\0'))
|
|
|
|
|
bxx_putc(t, '\0');
|
|
|
|
|
return t->buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/*------------------------------------------------------------------------------------------*
|
|
|
|
|
* Translate all of the device names and node names in the .subckt deck. They are
|
2000-04-27 22:03:57 +02:00
|
|
|
* pre-pended with subname:, unless they are in the formal list, in which case
|
|
|
|
|
* they are replaced with the corresponding entry in the actual list.
|
|
|
|
|
* The one special case is node 0 -- this is always ground and we don't
|
|
|
|
|
* touch it.
|
2003-07-23 21:36:39 +02:00
|
|
|
*
|
|
|
|
|
* Variable name meanings:
|
|
|
|
|
* *deck = pointer to subcircuit definition (lcc) (struct line)
|
|
|
|
|
* formal = copy of the .subckt definition line (e.g. ".subckt subcircuitname 1 2 3") (string)
|
|
|
|
|
* actual = copy of the .subcircuit invocation line (e.g. "Xexample 4 5 6 subcircuitname") (string)
|
|
|
|
|
* scname = refdes (- first letter) used at invocation (e.g. "example") (string)
|
|
|
|
|
* subname = copy of the subcircuit name
|
|
|
|
|
*-------------------------------------------------------------------------------------------*/
|
2000-04-27 22:03:57 +02:00
|
|
|
static int
|
|
|
|
|
translate(struct line *deck, char *formal, char *actual, char *scname, char *subname)
|
|
|
|
|
{
|
|
|
|
|
struct line *c;
|
2010-01-15 23:05:23 +01:00
|
|
|
struct bxx_buffer buffer;
|
|
|
|
|
char *next_name, dev_type, *name, *s, *t, ch, *nametofree, *paren_ptr, *new_str;
|
|
|
|
|
int nnodes, i, dim;
|
2003-07-23 21:36:39 +02:00
|
|
|
int rtn=0;
|
|
|
|
|
|
2010-01-15 23:05:23 +01:00
|
|
|
bxx_init(&buffer);
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/* settrans builds the table holding the translated netnames. */
|
2000-04-27 22:03:57 +02:00
|
|
|
i = settrans(formal, actual, subname);
|
|
|
|
|
if (i < 0) {
|
2010-10-07 23:43:40 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
|
"Too few parameters for subcircuit type \"%s\" (instance: x%s)\n",
|
|
|
|
|
subname, scname);
|
|
|
|
|
goto quit;
|
2000-04-27 22:03:57 +02:00
|
|
|
} else if (i > 0) {
|
2010-10-07 23:43:40 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
|
"Too many parameters for subcircuit type \"%s\" (instance: x%s)\n",
|
|
|
|
|
subname, scname);
|
|
|
|
|
goto quit;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/* now iterate through the .subckt deck and translate the cards. */
|
|
|
|
|
for (c = deck; c; c = c->li_next) {
|
2010-10-07 23:43:40 +02:00
|
|
|
dev_type = *(c->li_line);
|
2007-10-08 23:10:34 +02:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
#ifdef TRACE
|
2010-10-07 23:43:40 +02:00
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("\nIn translate, examining line (dev_type: %c, subname: %s, instance: %s) %s \n", dev_type, subname, scname, c->li_line );
|
2003-07-23 21:36:39 +02:00
|
|
|
#endif
|
|
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
if ( ciprefix( ".ic", c->li_line ) || ciprefix( ".nodeset", c->li_line ) ) {
|
|
|
|
|
paren_ptr = s = c->li_line;
|
|
|
|
|
while ( ( paren_ptr = strstr( paren_ptr, "(" ) ) ) {
|
|
|
|
|
*paren_ptr = '\0';
|
|
|
|
|
paren_ptr++;
|
|
|
|
|
name = paren_ptr;
|
2007-10-09 09:19:45 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
if ( !( paren_ptr = strstr( paren_ptr, ")" ) ) ) {
|
|
|
|
|
*(name-1) = '(';
|
|
|
|
|
fprintf(cp_err, "Error: missing closing ')' for .ic|.nodeset statement %s\n", c->li_line);
|
|
|
|
|
goto quit;
|
|
|
|
|
}
|
|
|
|
|
*paren_ptr = '\0';
|
|
|
|
|
t = gettrans(name, NULL);
|
|
|
|
|
|
|
|
|
|
if (t) {
|
|
|
|
|
new_str = (char*) tmalloc( strlen(s) + strlen(t) + strlen(paren_ptr+1) + 3 );
|
|
|
|
|
sprintf( new_str, "%s(%s)%s", s, t, paren_ptr+1 );
|
|
|
|
|
} else {
|
|
|
|
|
new_str = (char*) tmalloc( strlen(s) + strlen(scname) + strlen(name) + strlen(paren_ptr+1) + 4 );
|
|
|
|
|
sprintf( new_str, "%s(%s.%s)%s", s, scname, name, paren_ptr+1 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
paren_ptr = new_str + strlen(s) + 1;
|
|
|
|
|
|
|
|
|
|
tfree(s);
|
|
|
|
|
s = new_str;
|
|
|
|
|
}
|
|
|
|
|
c->li_line = s;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
/* Rename the device. */
|
2003-07-23 21:36:39 +02:00
|
|
|
switch (dev_type) {
|
2010-10-07 23:43:40 +02:00
|
|
|
case '\0':
|
|
|
|
|
case '*': case '$':
|
|
|
|
|
case '.':
|
2003-07-23 21:36:39 +02:00
|
|
|
/* Just a pointer to the line into s and then break */
|
2010-10-07 23:43:40 +02:00
|
|
|
bxx_rewind(&buffer);
|
|
|
|
|
s = c->li_line;
|
|
|
|
|
break;
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
#ifdef XSPICE
|
|
|
|
|
/*=================== case A ====================*/
|
|
|
|
|
/* gtri - add - wbk - 10/23/90 - process A devices specially */
|
|
|
|
|
/* since they have a more involved and variable length node syntax */
|
|
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
case 'a':
|
|
|
|
|
case 'A':
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* translate the instance name according to normal rules */
|
2010-10-07 23:43:40 +02:00
|
|
|
s = c->li_line;
|
|
|
|
|
name = MIFgettok(&s);
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
bxx_rewind(&buffer);
|
|
|
|
|
bxx_printf(&buffer, "a.%s.%s ", scname, name );
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Now translate the nodes, looking ahead one token to recognize */
|
|
|
|
|
/* when we reach the model name which should not be translated */
|
|
|
|
|
/* here. */
|
|
|
|
|
|
|
|
|
|
next_name = MIFgettok(&s);
|
|
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
for (;;) {
|
|
|
|
|
/* rotate the tokens and get the the next one */
|
2003-07-23 21:36:39 +02:00
|
|
|
name = next_name;
|
|
|
|
|
next_name = MIFgettok(&s);
|
|
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
/* if next token is NULL, name holds the model name, so exit */
|
|
|
|
|
if(next_name == NULL)
|
|
|
|
|
break;
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
/* Process the token in name. If it is special, then don't */
|
|
|
|
|
/* translate it. */
|
|
|
|
|
switch(*name) {
|
|
|
|
|
case '[':
|
|
|
|
|
case ']':
|
|
|
|
|
case '~':
|
|
|
|
|
bxx_printf(&buffer, "%s ", name);
|
|
|
|
|
break;
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
case '%':
|
|
|
|
|
bxx_printf(&buffer, "%%");
|
|
|
|
|
/* don't translate the port type identifier */
|
|
|
|
|
name = next_name;
|
|
|
|
|
next_name = MIFgettok(&s);
|
|
|
|
|
bxx_printf(&buffer, "%s ", name);
|
|
|
|
|
break;
|
2004-06-21 11:58:25 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
default:
|
|
|
|
|
|
|
|
|
|
/* must be a node name at this point, so translate it */
|
|
|
|
|
t = gettrans(name, NULL);
|
|
|
|
|
if (t) {
|
|
|
|
|
bxx_printf(&buffer, "%s ", t);
|
|
|
|
|
} else {
|
|
|
|
|
if(name[0]=='v' || name[0]=='V') {
|
|
|
|
|
bxx_printf(&buffer, "v.%s.%s ", scname, name);
|
|
|
|
|
} else {
|
|
|
|
|
bxx_printf(&buffer, "%s.%s ", scname, name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2005-02-08 22:07:37 +01:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
} /* switch */
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
} /* while */
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
/* copy in the last token, which is the model name */
|
|
|
|
|
if(name) {
|
|
|
|
|
bxx_printf(&buffer, "%s ", name);
|
|
|
|
|
}
|
|
|
|
|
/* Set s to null string for compatibility with code */
|
|
|
|
|
/* after switch statement */
|
|
|
|
|
s = "";
|
|
|
|
|
break; /* case 'a' */
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* gtri - end - wbk - 10/23/90 */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*================ case E, F, G, H ================*/
|
|
|
|
|
/* This section handles controlled sources and allows for SPICE2 POLY attributes.
|
|
|
|
|
* This is a new section, added by SDB to handle POLYs in sources. Significant
|
|
|
|
|
* changes were made in here.
|
|
|
|
|
* 4.21.2003 -- SDB. mailto:sdb@cloud9.net
|
|
|
|
|
*/
|
2010-10-07 23:43:40 +02:00
|
|
|
case 'E': case 'e':
|
|
|
|
|
case 'F': case 'f':
|
|
|
|
|
case 'G': case 'g':
|
|
|
|
|
case 'H': case 'h':
|
|
|
|
|
|
|
|
|
|
s = c->li_line; /* s now holds the SPICE line */
|
|
|
|
|
t = name = gettok(&s); /* name points to the refdes */
|
|
|
|
|
if (!name)
|
|
|
|
|
continue;
|
|
|
|
|
if (!*name) {
|
|
|
|
|
tfree(name);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* Here's where we translate the refdes to e.g. F:subcircuitname:57
|
|
|
|
|
* and stick the translated name into buffer.
|
|
|
|
|
*/
|
2010-10-07 23:43:40 +02:00
|
|
|
ch = *name; /* ch identifies the type of component */
|
|
|
|
|
bxx_rewind(&buffer);
|
|
|
|
|
bxx_printf(&buffer, "%c.%s.%s ", ch, scname, name);
|
|
|
|
|
tfree(t);
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* Next iterate over all nodes (netnames) found and translate them. */
|
2010-10-07 23:43:40 +02:00
|
|
|
nnodes = numnodes(c->li_line);
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
while (nnodes-- > 0) {
|
|
|
|
|
name = gettok_node(&s);
|
|
|
|
|
if (name == NULL) {
|
|
|
|
|
fprintf(cp_err, "Error: too few nodes: %s\n",
|
|
|
|
|
c->li_line);
|
|
|
|
|
goto quit;
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* call gettrans and see if netname was used in the invocation */
|
2010-10-07 23:43:40 +02:00
|
|
|
t = gettrans(name, NULL);
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
if (t) { /* the netname was used during the invocation; print it into the buffer */
|
|
|
|
|
bxx_printf(&buffer, "%s ", t);
|
|
|
|
|
}
|
|
|
|
|
else { /* net netname was not used during the invocation; place a
|
|
|
|
|
* translated name into the buffer.*/
|
|
|
|
|
bxx_printf(&buffer, "%s.%s ", scname, name);
|
|
|
|
|
}
|
|
|
|
|
tfree(name);
|
|
|
|
|
} /* while (nnodes-- . . . . */
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Next we handle the POLY (if any) */
|
|
|
|
|
/* get next token */
|
2010-10-07 23:43:40 +02:00
|
|
|
t = s;
|
|
|
|
|
next_name = (char *)gettok_noparens(&t);
|
|
|
|
|
if ( (strcmp(next_name, "POLY") == 0) ||
|
|
|
|
|
(strcmp(next_name, "poly") == 0)) { /* found POLY . . . . */
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
#ifdef TRACE
|
|
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In translate, looking at e, f, g, h found poly\n");
|
|
|
|
|
#endif
|
|
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
/* move pointer ahead of ( */
|
|
|
|
|
if( get_l_paren(&s) == 1 ) {
|
|
|
|
|
fprintf(cp_err, "Error: no left paren after POLY %s\n",
|
|
|
|
|
c->li_line);
|
|
|
|
|
tfree(next_name);
|
|
|
|
|
goto quit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nametofree = gettok_noparens(&s);
|
|
|
|
|
dim = atoi(nametofree); /* convert returned string to int */
|
|
|
|
|
tfree(nametofree);
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
/* move pointer ahead of ) */
|
|
|
|
|
if( get_r_paren(&s) == 1 ) {
|
|
|
|
|
fprintf(cp_err, "Error: no right paren after POLY %s\n",
|
|
|
|
|
c->li_line);
|
|
|
|
|
tfree(next_name);
|
|
|
|
|
goto quit;
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
/* Write POLY(dim) into buffer */
|
|
|
|
|
bxx_printf(&buffer, "POLY( %d ) ", dim);
|
|
|
|
|
|
|
|
|
|
} /* if ( (strcmp(next_name, "POLY") == 0) . . . */
|
|
|
|
|
else
|
|
|
|
|
dim = 1; /* only one controlling source . . . */
|
|
|
|
|
tfree(next_name);
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* Now translate the controlling source/nodes */
|
2010-10-07 23:43:40 +02:00
|
|
|
nnodes = dim * numdevs(c->li_line);
|
|
|
|
|
while (nnodes-- > 0) {
|
|
|
|
|
nametofree = name = gettok_node(&s); /* name points to the returned token */
|
|
|
|
|
if (name == NULL) {
|
|
|
|
|
fprintf(cp_err, "Error: too few devs: %s\n", c->li_line);
|
|
|
|
|
goto quit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( (dev_type == 'f') ||
|
|
|
|
|
(dev_type == 'F') ||
|
|
|
|
|
(dev_type == 'h') ||
|
|
|
|
|
(dev_type == 'H') ) {
|
|
|
|
|
|
|
|
|
|
/* Handle voltage source name */
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
#ifdef TRACE
|
|
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In translate, found type f or h\n");
|
|
|
|
|
#endif
|
|
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
ch = *name; /* ch is the first char of the token. */
|
2007-10-08 23:10:34 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
bxx_printf(&buffer, "%c.%s.%s ", ch, scname, name);
|
|
|
|
|
/* From Vsense and Urefdes creates V.Urefdes.sense */
|
|
|
|
|
}
|
|
|
|
|
else { /* Handle netname */
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
#ifdef TRACE
|
|
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In translate, found type e or g\n");
|
|
|
|
|
#endif
|
|
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
/* call gettrans and see if netname was used in the invocation */
|
|
|
|
|
t = gettrans(name, NULL);
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
if (t) { /* the netname was used during the invocation; print it into the buffer */
|
|
|
|
|
bxx_printf(&buffer, "%s ", t);
|
|
|
|
|
}
|
|
|
|
|
else { /* net netname was not used during the invocation; place a
|
|
|
|
|
* translated name into the buffer.
|
|
|
|
|
*/
|
|
|
|
|
bxx_printf(&buffer, "%s.%s ", scname, name);
|
|
|
|
|
/* From netname and Urefdes creates Urefdes:netname */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
tfree(nametofree);
|
|
|
|
|
} /* while (nnodes--. . . . */
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* Now write out remainder of line (polynomial coeffs) */
|
2010-10-07 23:43:40 +02:00
|
|
|
finishLine(&buffer, s, scname);
|
|
|
|
|
s = "";
|
|
|
|
|
break;
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/*================= Default case ===================*/
|
2010-10-07 23:43:40 +02:00
|
|
|
default: /* this section handles ordinary components */
|
|
|
|
|
s = c->li_line;
|
|
|
|
|
nametofree = name = gettok_node(&s); /* changed to gettok_node to handle netlists with ( , ) */
|
|
|
|
|
if (!name)
|
|
|
|
|
continue;
|
|
|
|
|
if (!*name) {
|
|
|
|
|
tfree(name);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* Here's where we translate the refdes to e.g. R:subcircuitname:57
|
|
|
|
|
* and stick the translated name into buffer.
|
|
|
|
|
*/
|
2010-10-07 23:43:40 +02:00
|
|
|
ch = *name;
|
2010-01-15 23:05:23 +01:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
bxx_rewind(&buffer);
|
2007-10-08 23:10:34 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
if ( ch != 'x' ) {
|
|
|
|
|
bxx_printf(&buffer, "%c.%s.%s ", ch, scname, name);
|
|
|
|
|
} else {
|
|
|
|
|
bxx_printf(&buffer, "%s.%s ", scname, name);
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
tfree(nametofree);
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* Next iterate over all nodes (netnames) found and translate them. */
|
2010-10-07 23:43:40 +02:00
|
|
|
nnodes = numnodes(c->li_line);
|
|
|
|
|
while (nnodes-- > 0) {
|
|
|
|
|
name = gettok_node(&s);
|
|
|
|
|
if (name == NULL ) {
|
|
|
|
|
fprintf(cp_err, "Error: too few nodes: %s\n", c->li_line);
|
|
|
|
|
goto quit;
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* call gettrans and see if netname was used in the invocation */
|
2010-10-07 23:43:40 +02:00
|
|
|
t = gettrans(name, NULL);
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
if (t) { /* the netname was used during the invocation; print it into the buffer */
|
|
|
|
|
bxx_printf(&buffer, "%s ", t);
|
|
|
|
|
}
|
|
|
|
|
else { /* net netname was not used during the invocation; place a
|
|
|
|
|
* translated name into the buffer.
|
|
|
|
|
*/
|
|
|
|
|
bxx_printf(&buffer, "%s.%s ", scname, name);
|
|
|
|
|
}
|
|
|
|
|
tfree(name);
|
|
|
|
|
} /* while (nnodes-- . . . . */
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* Now translate any devices (i.e. controlling sources).
|
2005-04-04 12:38:45 +02:00
|
|
|
* This may be superfluous because we handle dependent
|
2003-07-23 21:36:39 +02:00
|
|
|
* source devices above . . . .
|
|
|
|
|
*/
|
2010-10-07 23:43:40 +02:00
|
|
|
nnodes = numdevs(c->li_line);
|
|
|
|
|
while (nnodes-- > 0) {
|
|
|
|
|
t = name = gettok_node(&s);
|
|
|
|
|
if (name == NULL) {
|
|
|
|
|
fprintf(cp_err, "Error: too few devs: %s\n", c->li_line);
|
|
|
|
|
goto quit;
|
|
|
|
|
}
|
|
|
|
|
ch = *name;
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
if ( ch != 'x' ) {
|
|
|
|
|
bxx_printf(&buffer, "%c.%s.%s ", ch, scname, name);
|
|
|
|
|
} else {
|
|
|
|
|
bxx_printf(&buffer, "%s ", scname);
|
|
|
|
|
}
|
|
|
|
|
tfree(t);
|
|
|
|
|
} /* while (nnodes--. . . . */
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
* i(something)...
|
|
|
|
|
*/
|
2010-10-07 23:43:40 +02:00
|
|
|
finishLine(&buffer, s, scname);
|
|
|
|
|
s = "";
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
} /* switch(c->li_line . . . . */
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
bxx_printf(&buffer, "%s", s);
|
|
|
|
|
tfree(c->li_line);
|
|
|
|
|
c->li_line = copy(bxx_buffer(&buffer));
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
#ifdef TRACE
|
|
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In translate, translated line = %s \n", c->li_line);
|
|
|
|
|
#endif
|
|
|
|
|
|
2010-10-07 23:43:40 +02:00
|
|
|
} /* for (c = deck . . . . */
|
|
|
|
|
rtn = 1;
|
2003-07-23 21:36:39 +02:00
|
|
|
quit:
|
2010-10-07 23:43:40 +02:00
|
|
|
for (i = 0; ; i++) {
|
|
|
|
|
if(!table[i].t_old && !table[i].t_new)
|
|
|
|
|
break;
|
|
|
|
|
FREE(table[i].t_old);
|
|
|
|
|
FREE(table[i].t_new);
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2010-01-15 23:05:23 +01:00
|
|
|
|
|
|
|
|
bxx_free(&buffer);
|
2003-07-23 21:36:39 +02:00
|
|
|
return rtn;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
|
|
|
* finishLine now doesn't handle current or voltage sources.
|
|
|
|
|
* Therefore, it just writes out the final netnames, if required.
|
|
|
|
|
* Changes made by SDB on 4.29.2003.
|
|
|
|
|
*-------------------------------------------------------------------*/
|
2000-04-27 22:03:57 +02:00
|
|
|
static void
|
2010-01-15 23:05:23 +01:00
|
|
|
finishLine(struct bxx_buffer *t, char *src, char *scname)
|
2000-04-27 22:03:57 +02:00
|
|
|
{
|
2010-01-15 23:05:23 +01:00
|
|
|
char *buf, *buf_end, which;
|
2000-04-27 22:03:57 +02:00
|
|
|
char *s;
|
|
|
|
|
int lastwasalpha;
|
|
|
|
|
|
|
|
|
|
lastwasalpha = 0;
|
|
|
|
|
while (*src) {
|
|
|
|
|
/* Find the next instance of "<non-alpha>[vi]<opt spaces>(" in
|
|
|
|
|
* this string.
|
|
|
|
|
*/
|
|
|
|
|
if (((*src != 'v') && (*src != 'V') &&
|
|
|
|
|
(*src != 'i') && (*src != 'I')) ||
|
|
|
|
|
lastwasalpha) {
|
|
|
|
|
lastwasalpha = isalpha(*src);
|
2010-01-15 23:05:23 +01:00
|
|
|
bxx_putc(t, *src++);
|
2000-04-27 22:03:57 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
for (s = src + 1; *s && isspace(*s); s++)
|
|
|
|
|
;
|
|
|
|
|
if (!*s || (*s != '(')) {
|
|
|
|
|
lastwasalpha = isalpha(*src);
|
2010-01-15 23:05:23 +01:00
|
|
|
bxx_putc(t, *src++);
|
2000-04-27 22:03:57 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
lastwasalpha = 0;
|
2010-01-15 23:05:23 +01:00
|
|
|
bxx_putc(t, which = *src);
|
2000-04-27 22:03:57 +02:00
|
|
|
src = s;
|
2010-01-15 23:05:23 +01:00
|
|
|
bxx_putc(t, *src++);
|
2000-04-27 22:03:57 +02:00
|
|
|
while (isspace(*src))
|
|
|
|
|
src++;
|
2010-01-15 23:05:23 +01:00
|
|
|
for (buf = src; *src && !isspace(*src) && *src != ',' && (*src != ')');
|
|
|
|
|
)
|
2000-04-27 22:03:57 +02:00
|
|
|
{
|
2010-01-15 23:05:23 +01:00
|
|
|
src++;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2010-01-15 23:05:23 +01:00
|
|
|
buf_end = src;
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
if ((which == 'v') || (which == 'V'))
|
2010-01-15 23:05:23 +01:00
|
|
|
s = gettrans(buf, buf_end);
|
2000-04-27 22:03:57 +02:00
|
|
|
else
|
|
|
|
|
s = NULL;
|
|
|
|
|
|
|
|
|
|
if (s) {
|
2010-01-15 23:05:23 +01:00
|
|
|
bxx_put_cstring(t, s);
|
2003-07-23 21:36:39 +02:00
|
|
|
}
|
|
|
|
|
else { /* just a normal netname . . . . */
|
2000-04-27 22:03:57 +02:00
|
|
|
/*
|
2010-05-10 23:57:36 +02:00
|
|
|
i(vname) -> i(v.subckt.vname)
|
|
|
|
|
i(ename) -> i(e.subckt.ename)
|
|
|
|
|
i(hname) -> i(h.subckt.hname)
|
2010-10-07 23:43:40 +02:00
|
|
|
i(bname) -> i(b.subckt.hname)
|
2000-04-27 22:03:57 +02:00
|
|
|
*/
|
2005-04-17 00:45:32 +02:00
|
|
|
if ((which == 'i' || which == 'I') &&
|
2010-10-07 23:43:40 +02:00
|
|
|
(buf[0] == 'v' || buf[0] == 'V' || buf[0] == 'e' || buf[0] == 'h'
|
|
|
|
|
|| buf[0] == 'b' || buf[0] == 'B')) {
|
2010-01-15 23:05:23 +01:00
|
|
|
bxx_putc(t, buf[0]);
|
|
|
|
|
bxx_putc(t, '.');
|
2009-01-31 16:17:48 +01:00
|
|
|
/*i = 1; */
|
|
|
|
|
} /* else {
|
2000-04-27 22:03:57 +02:00
|
|
|
i = 0;
|
2009-01-31 16:17:48 +01:00
|
|
|
} */
|
2010-01-15 23:05:23 +01:00
|
|
|
bxx_put_cstring(t, scname);
|
|
|
|
|
bxx_putc(t, '.');
|
|
|
|
|
bxx_put_substring(t, buf, buf_end);
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* translate the reference node, as in the "2" in "v(4,2)" */
|
|
|
|
|
|
|
|
|
|
if ((which == 'v') || (which == 'V')) {
|
|
|
|
|
while (*src && (isspace(*src) || *src == ',')) {
|
|
|
|
|
src++;
|
|
|
|
|
}
|
|
|
|
|
if (*src && *src != ')') {
|
2010-01-15 23:05:23 +01:00
|
|
|
for (buf = src; *src && !isspace(*src) && (*src != ')'); )
|
|
|
|
|
src++;
|
|
|
|
|
s = gettrans(buf, buf_end = src);
|
|
|
|
|
bxx_putc(t, ',');
|
2000-04-27 22:03:57 +02:00
|
|
|
if (s) {
|
2010-01-15 23:05:23 +01:00
|
|
|
bxx_put_cstring(t, s);
|
2000-04-27 22:03:57 +02:00
|
|
|
} else {
|
2010-01-15 23:05:23 +01:00
|
|
|
bxx_put_cstring(t, scname);
|
|
|
|
|
bxx_putc(t, '.');
|
|
|
|
|
bxx_put_substring(t, buf, buf_end);
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/*------------------------------------------------------------------------------*
|
|
|
|
|
* settrans builds the table which holds the old and new netnames.
|
|
|
|
|
* it also compares the number of nets present in the .subckt definition against
|
|
|
|
|
* the number of nets present in the subcircuit invocation. It returns 0 if they
|
|
|
|
|
* match, otherwise, it returns an error.
|
|
|
|
|
*
|
|
|
|
|
* Variable definitions:
|
|
|
|
|
* formal = copy of the .subckt definition line (e.g. ".subckt subcircuitname 1 2 3") (string)
|
|
|
|
|
* actual = copy of the .subcircuit invocation line (e.g. "Xexample 4 5 6 subcircuitname") (string)
|
|
|
|
|
* subname = copy of the subcircuit name
|
|
|
|
|
*------------------------------------------------------------------------------*/
|
2000-04-27 22:03:57 +02:00
|
|
|
static int
|
|
|
|
|
settrans(char *formal, char *actual, char *subname)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
bzero(table,sizeof(*table));
|
|
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
for (i = 0; ; i++) {
|
|
|
|
|
table[i].t_old = gettok(&formal);
|
|
|
|
|
table[i].t_new = gettok(&actual);
|
|
|
|
|
|
|
|
|
|
if (table[i].t_new == NULL) {
|
|
|
|
|
return -1; /* Too few actual / too many formal */
|
|
|
|
|
} else if (table[i].t_old == NULL) {
|
|
|
|
|
if (eq(table[i].t_new, subname))
|
|
|
|
|
break;
|
|
|
|
|
else
|
|
|
|
|
return 1; /* Too many actual / too few formal */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-15 23:05:23 +01:00
|
|
|
/* compare a substring, with a '\0' terminated string
|
|
|
|
|
* the substring itself is required to be free of a '\0'
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
eq_substr(const char* str, const char *end, const char *cstring)
|
|
|
|
|
{
|
|
|
|
|
while(str < end)
|
|
|
|
|
if(*str++ != *cstring++)
|
|
|
|
|
return 0;
|
|
|
|
|
return (*cstring == '\0');
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------------------*
|
|
|
|
|
* gettrans returns the name of the top level net if it is in the list,
|
|
|
|
|
* otherwise it returns NULL.
|
|
|
|
|
*------------------------------------------------------------------------------*/
|
2000-04-27 22:03:57 +02:00
|
|
|
static char *
|
2010-01-15 23:05:23 +01:00
|
|
|
gettrans(const char *name, const char *name_end)
|
2000-04-27 22:03:57 +02:00
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2010-01-15 23:05:23 +01:00
|
|
|
if(!name_end)
|
|
|
|
|
name_end = strchr(name, '\0');
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
#ifdef XSPICE
|
|
|
|
|
/* gtri - wbk - 2/27/91 - don't translate the reserved word 'null' */
|
2010-01-15 23:05:23 +01:00
|
|
|
if (eq_substr(name, name_end, "null"))
|
|
|
|
|
return ("null");
|
2003-07-23 21:36:39 +02:00
|
|
|
/* gtri - end */
|
|
|
|
|
#endif
|
|
|
|
|
|
2005-05-06 09:11:02 +02:00
|
|
|
/* Added by H.Tanaka to translate global nodes */
|
|
|
|
|
for(i=0;i<numgnode;i++)
|
2010-01-15 23:05:23 +01:00
|
|
|
if(eq_substr(name, name_end, node[i]))
|
|
|
|
|
return (node[i]);
|
2005-05-06 09:11:02 +02:00
|
|
|
|
2010-01-15 23:05:23 +01:00
|
|
|
if (eq_substr(name, name_end, "0"))
|
|
|
|
|
return ("0");
|
2000-04-27 22:03:57 +02:00
|
|
|
for (i = 0; table[i].t_old; i++)
|
2010-01-15 23:05:23 +01:00
|
|
|
if (eq_substr(name, name_end, table[i].t_old))
|
2000-04-27 22:03:57 +02:00
|
|
|
return (table[i].t_new);
|
|
|
|
|
return (NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-08 23:45:00 +02:00
|
|
|
/*
|
|
|
|
|
check if current token matches model bin name -- <token>.[0-9]+
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
model_bin_match( char* token, char* model_name )
|
|
|
|
|
{
|
2009-05-10 21:29:13 +02:00
|
|
|
char* dot_char;
|
|
|
|
|
bool flag = FALSE;
|
|
|
|
|
/* continue evaluation if toeken is part of model_name */
|
|
|
|
|
if ( strncmp( model_name, token, strlen(token) ) == 0 ) {
|
|
|
|
|
/* find last dot in model_name */
|
|
|
|
|
if ( (dot_char = strrchr( model_name, '.' )) ) {
|
|
|
|
|
flag = TRUE;
|
|
|
|
|
dot_char++;
|
|
|
|
|
while( *dot_char != '\0' ) {
|
|
|
|
|
if ( !isdigit( *dot_char ) ) {
|
|
|
|
|
flag = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
dot_char++;
|
|
|
|
|
}
|
2007-10-08 23:45:00 +02:00
|
|
|
}
|
2009-05-10 21:29:13 +02:00
|
|
|
}
|
|
|
|
|
return flag;
|
2007-10-08 23:45:00 +02:00
|
|
|
}
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
2000-04-27 22:03:57 +02:00
|
|
|
static int
|
|
|
|
|
numnodes(char *name)
|
|
|
|
|
{
|
2003-07-23 21:36:39 +02:00
|
|
|
/* gtri - comment - wbk - 10/23/90 - Do not modify this routine for */
|
|
|
|
|
/* 'A' type devices since the callers will not know how to find the */
|
|
|
|
|
/* nodes even if they know how many there are. Modify the callers */
|
|
|
|
|
/* instead. */
|
|
|
|
|
/* gtri - end - wbk - 10/23/90 */
|
2000-04-27 22:03:57 +02:00
|
|
|
char c;
|
|
|
|
|
struct subs *sss;
|
|
|
|
|
char *s, *t, buf[4 * BSIZE_SP];
|
|
|
|
|
wordlist *wl;
|
2001-01-24 12:19:39 +01:00
|
|
|
int n, i, gotit;
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
while (*name && isspace(*name))
|
|
|
|
|
name++;
|
|
|
|
|
|
|
|
|
|
c = (isupper(*name) ? tolower(*name) : *name);
|
|
|
|
|
|
|
|
|
|
(void) strncpy(buf, name, sizeof(buf));
|
|
|
|
|
s = buf;
|
|
|
|
|
if (c == 'x') { /* Handle this ourselves. */
|
|
|
|
|
while(*s)
|
|
|
|
|
s++;
|
|
|
|
|
s--;
|
|
|
|
|
while ((*s == ' ') || (*s == '\t'))
|
|
|
|
|
*s-- = '\0';
|
|
|
|
|
while ((*s != ' ') && (*s != '\t'))
|
|
|
|
|
s--;
|
|
|
|
|
s++;
|
|
|
|
|
for (sss = subs; sss; sss = sss->su_next)
|
|
|
|
|
if (eq(sss->su_name, s))
|
|
|
|
|
break;
|
|
|
|
|
if (!sss) {
|
|
|
|
|
fprintf(cp_err, "Error: no such subcircuit: %s\n", s);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
return (sss->su_numargs);
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
n = inp_numnodes(c);
|
2001-01-24 12:19:39 +01:00
|
|
|
|
2010-02-07 19:16:17 +01:00
|
|
|
/* Added this code for variable number of nodes on BSIM3SOI/CPL devices */
|
2001-01-24 12:19:39 +01:00
|
|
|
/* The consequence of this code is that the value returned by the */
|
2005-04-04 12:38:45 +02:00
|
|
|
/* inp_numnodes(c) call must be regarded as "maximum number of nodes */
|
2001-01-24 12:19:39 +01:00
|
|
|
/* for a given device type. */
|
|
|
|
|
/* Paolo Nenzi Jan-2001 */
|
|
|
|
|
|
|
|
|
|
/* I hope that works, this code is very very untested */
|
|
|
|
|
|
2010-02-07 19:16:17 +01:00
|
|
|
if ((c=='m') || (c=='p')) { /* IF this is a mos or cpl */
|
|
|
|
|
i = 0;
|
|
|
|
|
s = buf;
|
|
|
|
|
gotit = 0;
|
|
|
|
|
txfree(gettok(&s)); /* Skip component name */
|
|
|
|
|
while ((i < n) && (*s) && !gotit) {
|
|
|
|
|
t = gettok_node(&s); /* get nodenames . . . */
|
|
|
|
|
for (wl = modnames; wl; wl = wl->wl_next) {
|
|
|
|
|
/* also need to check if binnable device mos model */
|
|
|
|
|
if (eq(t, wl->wl_word) || model_bin_match( t, wl->wl_word ) )
|
|
|
|
|
gotit = 1;
|
|
|
|
|
}
|
|
|
|
|
i++;
|
|
|
|
|
tfree(t);
|
|
|
|
|
} /* while . . . . */
|
|
|
|
|
|
|
|
|
|
/* Note: node checks must be done on #_of_node-1 because the */
|
|
|
|
|
/* "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 or CPL: %s\n", name);
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
return(i-1); /* compensate the unnecessary increment in the while cycle */
|
|
|
|
|
} /* if (c=='m' . . . */
|
2001-01-24 12:19:39 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
if (nobjthack || (c != 'q'))
|
|
|
|
|
return (n);
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
for (s = buf, i = 0; *s && (i < 4); i++)
|
2003-07-23 21:36:39 +02:00
|
|
|
txfree(gettok(&s));
|
|
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
if (i == 3)
|
|
|
|
|
return (3);
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
else if (i < 4) {
|
|
|
|
|
fprintf(cp_err, "Error: too few nodes for BJT: %s\n", name);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Now, is this a model? */
|
|
|
|
|
t = gettok(&s);
|
|
|
|
|
for (wl = modnames; wl; wl = wl->wl_next)
|
2003-07-23 21:36:39 +02:00
|
|
|
if (eq(t, wl->wl_word)) {
|
|
|
|
|
tfree(t);
|
|
|
|
|
return (3);
|
|
|
|
|
}
|
|
|
|
|
tfree(t);
|
2000-04-27 22:03:57 +02:00
|
|
|
return (4);
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
|
|
|
* This function returns the number of controlling voltage sources
|
|
|
|
|
* (for F, H) or controlling nodes (for G, E) attached to a dependent
|
|
|
|
|
* source.
|
|
|
|
|
*-------------------------------------------------------------------*/
|
2000-04-27 22:03:57 +02:00
|
|
|
static int
|
|
|
|
|
numdevs(char *s)
|
|
|
|
|
{
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
while (*s && isspace(*s))
|
|
|
|
|
s++;
|
|
|
|
|
switch (*s) {
|
|
|
|
|
case 'K':
|
|
|
|
|
case 'k':
|
|
|
|
|
return (2);
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/* two nodes per voltage controlled source */
|
|
|
|
|
case 'G':
|
|
|
|
|
case 'g':
|
|
|
|
|
case 'E':
|
|
|
|
|
case 'e':
|
|
|
|
|
return(2);
|
|
|
|
|
|
|
|
|
|
/* one source per current controlled source */
|
|
|
|
|
case 'F':
|
|
|
|
|
case 'f':
|
|
|
|
|
case 'H':
|
|
|
|
|
case 'h':
|
2000-04-27 22:03:57 +02:00
|
|
|
/* 2 lines here added to fix w bug, NCF 1/31/95 */
|
2003-07-23 21:36:39 +02:00
|
|
|
case 'W':
|
|
|
|
|
case 'w':
|
|
|
|
|
return (1);
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/*----------------------------------------------------------------------*
|
2005-02-08 22:07:37 +01:00
|
|
|
* modtranslate -- translates .model lines found in subckt definitions.
|
2003-07-23 21:36:39 +02:00
|
|
|
* Calling arguments are:
|
|
|
|
|
* *deck = pointer to the .subckt definition (linked list)
|
|
|
|
|
* *subname = pointer to the subcircuit name used at the subcircuit invocation (string)
|
|
|
|
|
* Modtranslate returns TRUE if it translated a model name, FALSE
|
|
|
|
|
* otherwise.
|
|
|
|
|
*----------------------------------------------------------------------*/
|
2000-04-27 22:03:57 +02:00
|
|
|
static bool
|
|
|
|
|
modtranslate(struct line *deck, char *subname)
|
|
|
|
|
{
|
|
|
|
|
struct line *c;
|
|
|
|
|
char *buffer, *name, *t, model[4 * BSIZE_SP];
|
|
|
|
|
wordlist *wl, *wlsub;
|
|
|
|
|
bool gotone;
|
|
|
|
|
|
|
|
|
|
(void) strcpy(model, ".model");
|
|
|
|
|
gotone = FALSE;
|
2003-07-23 21:36:39 +02:00
|
|
|
for (c = deck; c; c = c->li_next) { /* iterate through model def . . . */
|
2005-04-04 12:38:45 +02:00
|
|
|
if (ciprefix(model, c->li_line)) {
|
2000-04-27 22:03:57 +02:00
|
|
|
gotone = TRUE;
|
|
|
|
|
t = c->li_line;
|
2004-06-21 11:58:25 +02:00
|
|
|
|
|
|
|
|
#ifdef TRACE
|
|
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In modtranslate, translating line %s\n", t);
|
|
|
|
|
#endif
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
name = gettok(&t); /* at this point, name = .model */
|
2010-07-01 21:52:23 +02:00
|
|
|
buffer = (char*) tmalloc(strlen(name) + strlen(t) +
|
2000-04-27 22:03:57 +02:00
|
|
|
strlen(subname) + 4);
|
2003-07-23 21:36:39 +02:00
|
|
|
(void) sprintf(buffer, "%s ",name); /* at this point, buffer = ".model " */
|
2005-02-08 22:07:37 +01:00
|
|
|
tfree(name);
|
2003-07-23 21:36:39 +02:00
|
|
|
name = gettok(&t); /* name now holds model name */
|
2000-04-27 22:03:57 +02:00
|
|
|
wlsub = alloc(struct wordlist);
|
|
|
|
|
wlsub->wl_next = submod;
|
|
|
|
|
if (submod)
|
|
|
|
|
submod->wl_prev = wlsub;
|
2004-06-21 11:58:25 +02:00
|
|
|
/* here's where we insert the model name into the model name list */
|
2000-04-27 22:03:57 +02:00
|
|
|
submod = wlsub;
|
|
|
|
|
wlsub->wl_word = name;
|
2004-06-21 11:58:25 +02:00
|
|
|
#ifdef TRACE
|
|
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In modtranslate, sticking model name %s into submod\n", wlsub->wl_word);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* now stick the new model name into the model line. */
|
2003-07-23 21:36:39 +02:00
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s:%s ",
|
|
|
|
|
subname, name); /* buffer = "model subname:modelname " */
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) strcat(buffer, t);
|
|
|
|
|
tfree(c->li_line);
|
|
|
|
|
c->li_line = buffer;
|
2004-06-21 11:58:25 +02:00
|
|
|
|
|
|
|
|
#ifdef TRACE
|
|
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In modtranslate, translated line= %s\n", c->li_line);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* this looks like it tries to stick the translated model name into the list of model names */
|
2000-04-27 22:03:57 +02:00
|
|
|
t = c->li_line;
|
2003-07-23 21:36:39 +02:00
|
|
|
txfree(gettok(&t));
|
2000-04-27 22:03:57 +02:00
|
|
|
wl = alloc(struct wordlist);
|
|
|
|
|
wl->wl_next = modnames;
|
|
|
|
|
if (modnames)
|
|
|
|
|
modnames->wl_prev = wl;
|
|
|
|
|
modnames = wl;
|
|
|
|
|
wl->wl_word = gettok(&t);
|
2004-06-21 11:58:25 +02:00
|
|
|
|
|
|
|
|
#ifdef TRACE
|
|
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In modtranslate, sticking model name %s into modnames\n", wl->wl_word);
|
|
|
|
|
#endif
|
|
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return(gotone);
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
2004-01-10 22:39:36 +01:00
|
|
|
* Devmodtranslate scans through the deck, and translates the
|
|
|
|
|
* name of the model in a line held in a .subckt. For example:
|
|
|
|
|
* before: .subckt U1 . . . .
|
|
|
|
|
* Q1 c b e 2N3904
|
|
|
|
|
* after: Q1 c b e U1:2N3904
|
2003-07-23 21:36:39 +02:00
|
|
|
*-------------------------------------------------------------------*/
|
2000-04-27 22:03:57 +02:00
|
|
|
static void
|
|
|
|
|
devmodtranslate(struct line *deck, char *subname)
|
|
|
|
|
{
|
|
|
|
|
struct line *s;
|
2005-04-04 12:38:45 +02:00
|
|
|
char *buffer, *name, *t, c;
|
2000-04-27 22:03:57 +02:00
|
|
|
wordlist *wlsub;
|
|
|
|
|
bool found;
|
2008-01-06 15:09:33 +01:00
|
|
|
char* dot_char;
|
|
|
|
|
int i, j;
|
2005-04-04 12:38:45 +02:00
|
|
|
char *next_name;
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
for (s = deck; s; s = s->li_next) {
|
|
|
|
|
t = s->li_line;
|
2004-01-10 22:39:36 +01:00
|
|
|
#ifdef TRACE
|
2010-01-27 22:26:08 +01:00
|
|
|
/* SDB debug stuff */
|
|
|
|
|
printf("In devmodtranslate, examining line %s.\n", t);
|
2004-01-10 22:39:36 +01:00
|
|
|
#endif
|
|
|
|
|
|
2010-01-27 22:26:08 +01:00
|
|
|
while (*t && isspace(*t))
|
|
|
|
|
t++;
|
|
|
|
|
c = isupper(*t) ? tolower(*t) : *t; /* set c to first char in line. . . . */
|
|
|
|
|
found = FALSE;
|
2010-07-01 21:52:23 +02:00
|
|
|
buffer = (char*) tmalloc(strlen(t) + strlen(subname) + 4);
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2010-01-27 22:26:08 +01:00
|
|
|
switch (c) {
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2005-02-09 18:54:57 +01:00
|
|
|
#ifdef XSPICE
|
|
|
|
|
|
2004-06-21 11:58:25 +02:00
|
|
|
case 'a':
|
|
|
|
|
/* Code for codemodels (dev prefix "A") added by SDB on 6.10.2004.
|
|
|
|
|
* The algorithm is simple. We don't know how many nodes or sources are attached,
|
|
|
|
|
* but the name of the model is always last. Therefore, just iterate through all
|
|
|
|
|
* tokens until the last one is reached. Then translate it.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef TRACE
|
2010-01-27 22:26:08 +01:00
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In devmodtranslate, found codemodel, line= %s\n", t);
|
2004-06-21 11:58:25 +02:00
|
|
|
#endif
|
|
|
|
|
|
2010-01-27 22:26:08 +01:00
|
|
|
/* first do refdes. */
|
|
|
|
|
name = gettok(&t); /* get refdes */
|
|
|
|
|
(void) sprintf(buffer,"%s ",name);
|
|
|
|
|
tfree(name);
|
|
|
|
|
|
|
|
|
|
/* now do remainder of line. */
|
|
|
|
|
next_name = gettok(&t);
|
2010-09-07 22:07:57 +02:00
|
|
|
for (;;) {
|
2010-01-27 22:26:08 +01:00
|
|
|
name = next_name;
|
|
|
|
|
next_name = gettok(&t);
|
|
|
|
|
|
|
|
|
|
if(next_name == NULL) {
|
|
|
|
|
/* if next_name is NULL, we are at the line end.
|
|
|
|
|
* name holds the model name. Therefore, break */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
/* next_name holds something. Write name into the buffer and continue. */
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
tfree(name);
|
|
|
|
|
}
|
|
|
|
|
} /* while */
|
2004-06-21 11:58:25 +02:00
|
|
|
|
|
|
|
|
|
2010-01-27 22:26:08 +01:00
|
|
|
/* Now, is name a subcircuit model?
|
|
|
|
|
* Note that we compare against submod = untranslated names of models.
|
|
|
|
|
*/
|
|
|
|
|
for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) {
|
2004-06-21 11:58:25 +02:00
|
|
|
|
|
|
|
|
#ifdef TRACE
|
2010-01-27 22:26:08 +01:00
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In devmodtranslate, comparing model name against submod list item %s\n", wlsub->wl_word );
|
2004-06-21 11:58:25 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (eq(name, wlsub->wl_word)) {
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s:%s ",
|
|
|
|
|
subname, name);
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
tfree(name);
|
|
|
|
|
|
|
|
|
|
#ifdef TRACE
|
|
|
|
|
/* SDB debug statement */
|
|
|
|
|
printf("In devmodtranslate, translated codemodel line= %s\n", buffer);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
(void) strcat(buffer, t);
|
|
|
|
|
tfree(s->li_line);
|
|
|
|
|
s->li_line = buffer;
|
|
|
|
|
break;
|
2005-02-09 18:54:57 +01:00
|
|
|
|
|
|
|
|
#endif /* XSPICE */
|
2010-01-27 22:26:08 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
case 'r':
|
|
|
|
|
case 'c':
|
2010-01-27 22:26:08 +01:00
|
|
|
name = gettok(&t); /* get refdes */
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) sprintf(buffer,"%s ",name);
|
2010-01-27 22:26:08 +01:00
|
|
|
tfree(name);
|
2004-01-10 22:39:36 +01:00
|
|
|
name = gettok_node(&t); /* get first netname */
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
2010-01-27 22:26:08 +01:00
|
|
|
tfree(name);
|
2004-01-10 22:39:36 +01:00
|
|
|
name = gettok_node(&t); /* get second netname */
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
2010-01-27 22:26:08 +01:00
|
|
|
tfree(name);
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2004-01-10 22:39:36 +01:00
|
|
|
if (*t) { /* if there is a model, process it. . . . */
|
2000-04-27 22:03:57 +02:00
|
|
|
name = gettok(&t);
|
2010-01-27 22:26:08 +01:00
|
|
|
/* Now, is this a subcircuit model? */
|
|
|
|
|
for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) {
|
2000-04-27 22:03:57 +02:00
|
|
|
if (eq(name, wlsub->wl_word)) {
|
2010-01-27 22:26:08 +01:00
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s:%s ",
|
|
|
|
|
subname, name);
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!found)
|
2010-01-27 22:26:08 +01:00
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
tfree(name);
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
found = FALSE;
|
|
|
|
|
if (*t) {
|
|
|
|
|
name = gettok(&t);
|
|
|
|
|
/* Now, is this a subcircuit model? */
|
|
|
|
|
for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) {
|
2010-01-27 22:26:08 +01:00
|
|
|
if (eq(name, wlsub->wl_word)) {
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s:%s ",
|
|
|
|
|
subname, name);
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
if (!found)
|
2010-01-27 22:26:08 +01:00
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
tfree(name);
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(void) strcat(buffer, t);
|
|
|
|
|
tfree(s->li_line);
|
|
|
|
|
s->li_line = buffer;
|
|
|
|
|
break;
|
|
|
|
|
|
2010-01-27 22:26:08 +01:00
|
|
|
case 'd':
|
|
|
|
|
name = gettok(&t); /* get refdes */
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) sprintf(buffer,"%s ",name);
|
2010-01-27 22:26:08 +01:00
|
|
|
tfree(name);
|
2004-01-10 22:39:36 +01:00
|
|
|
name = gettok_node(&t); /* get first attached netname */
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
2010-01-27 22:26:08 +01:00
|
|
|
tfree(name);
|
2004-01-10 22:39:36 +01:00
|
|
|
name = gettok_node(&t); /* get second attached netname */
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
2010-01-27 22:26:08 +01:00
|
|
|
tfree(name);
|
2000-04-27 22:03:57 +02:00
|
|
|
name = gettok(&t);
|
2010-01-27 22:26:08 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Now, is this a subcircuit model? */
|
|
|
|
|
for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) {
|
2010-01-27 22:26:08 +01:00
|
|
|
if (eq(name, wlsub->wl_word)) {
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s:%s ",
|
|
|
|
|
subname, name);
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
2010-01-27 22:26:08 +01:00
|
|
|
tfree(name);
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) strcat(buffer, t);
|
|
|
|
|
tfree(s->li_line);
|
|
|
|
|
s->li_line = buffer;
|
|
|
|
|
break;
|
|
|
|
|
|
2010-01-27 22:26:08 +01:00
|
|
|
/* 3 terminal devices */
|
|
|
|
|
case 'w': /* current controlled switch */
|
|
|
|
|
case 'u': /* urc transmissionline */
|
|
|
|
|
case 'j': /* jfet */
|
|
|
|
|
case 'z': /* hfet, mesa */
|
2000-04-27 22:03:57 +02:00
|
|
|
name = gettok(&t);
|
|
|
|
|
(void) sprintf(buffer,"%s ",name);
|
|
|
|
|
name = gettok(&t);
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
name = gettok(&t);
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
name = gettok(&t);
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
name = gettok(&t);
|
2010-01-27 22:26:08 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Now, is this a subcircuit model? */
|
|
|
|
|
for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) {
|
|
|
|
|
if (eq(name, wlsub->wl_word)) {
|
2010-01-27 22:26:08 +01:00
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s:%s ",
|
|
|
|
|
subname, name);
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
2010-01-27 22:26:08 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
if (!found)
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
(void) strcat(buffer, t);
|
|
|
|
|
tfree(s->li_line);
|
|
|
|
|
s->li_line = buffer;
|
|
|
|
|
break;
|
2010-01-27 22:26:08 +01:00
|
|
|
|
|
|
|
|
/* 4 terminal devices */
|
|
|
|
|
case 'm':
|
|
|
|
|
case 'o': /* ltra */
|
|
|
|
|
case 's': /* vc switch */
|
|
|
|
|
case 'y': /* txl */
|
|
|
|
|
/* Changed gettok() to gettok_node() on 12.2.2003 by SDB
|
|
|
|
|
to enable parsing lines like "S1 10 11 (80,51) SLATCH1"
|
|
|
|
|
which occur in real Analog Devices SPICE models.
|
|
|
|
|
*/
|
|
|
|
|
name = gettok(&t); /* get refdes */
|
|
|
|
|
(void) sprintf(buffer,"%s ",name);
|
|
|
|
|
tfree(name);
|
|
|
|
|
name = gettok_node(&t); /* get first attached netname */
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
tfree(name);
|
|
|
|
|
name = gettok_node(&t); /* get second attached netname */
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
tfree(name);
|
|
|
|
|
name = gettok_node(&t); /* get third attached netname */
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
tfree(name);
|
|
|
|
|
name = gettok_node(&t); /* get fourth attached netname */
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
tfree(name);
|
|
|
|
|
name = gettok(&t);
|
|
|
|
|
|
|
|
|
|
/* Now, is this a subcircuit model? */
|
|
|
|
|
for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) {
|
|
|
|
|
i = strlen(wlsub->wl_word);
|
|
|
|
|
j = 0; /* Now, have we a binned model? */
|
|
|
|
|
if ( (dot_char = strstr( wlsub->wl_word, "." )) ) {
|
|
|
|
|
dot_char++; j++;
|
|
|
|
|
while( *dot_char != '\0' ) {
|
|
|
|
|
if ( !isdigit( *dot_char ) ) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
dot_char++; j++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( strncmp( name, wlsub->wl_word, i - j ) == 0 ) {
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s:%s ",
|
|
|
|
|
subname, name);
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
(void) strcat(buffer, t);
|
|
|
|
|
tfree(s->li_line);
|
|
|
|
|
s->li_line = buffer;
|
|
|
|
|
tfree(name);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* 3-5 terminal devices */
|
|
|
|
|
case 'q':
|
|
|
|
|
name = gettok(&t); /* get refdes */
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) sprintf(buffer,"%s ",name);
|
2010-01-27 22:26:08 +01:00
|
|
|
tfree(name);
|
2004-01-10 22:39:36 +01:00
|
|
|
name = gettok_node(&t); /* get first attached netname */
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
2010-01-27 22:26:08 +01:00
|
|
|
tfree(name);
|
2004-01-10 22:39:36 +01:00
|
|
|
name = gettok_node(&t); /* get second attached netname */
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
2010-01-27 22:26:08 +01:00
|
|
|
tfree(name);
|
2004-01-10 22:39:36 +01:00
|
|
|
name = gettok_node(&t); /* get third attached netname */
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
2010-01-27 22:26:08 +01:00
|
|
|
tfree(name);
|
2004-01-10 22:39:36 +01:00
|
|
|
name = gettok_node(&t); /* this can be either a model name or a node name. */
|
2010-01-27 22:26:08 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Now, is this a subcircuit model? */
|
|
|
|
|
for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) {
|
2009-11-09 10:15:21 +01:00
|
|
|
if (eq(name, wlsub->wl_word)) { /* a three terminal bjt */
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s:%s ",
|
|
|
|
|
subname, name);
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
2009-11-09 10:15:21 +01:00
|
|
|
if (!found) {
|
|
|
|
|
if (*t) { /* There is another token - perhaps a model */
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
2010-01-27 22:26:08 +01:00
|
|
|
tfree(name);
|
2009-11-09 10:15:21 +01:00
|
|
|
name = gettok(&t);
|
|
|
|
|
/* Now, is this a subcircuit model? */
|
|
|
|
|
for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) {
|
|
|
|
|
if (eq(name, wlsub->wl_word)) { /* a four terminal bjt */
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer),
|
|
|
|
|
"%s:%s ", subname, name);
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#ifdef ADMS
|
|
|
|
|
if (!found) {
|
|
|
|
|
if (*t) { /* There is another token - perhaps a model */
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
2010-01-27 22:26:08 +01:00
|
|
|
tfree(name);
|
2009-11-09 10:15:21 +01:00
|
|
|
name = gettok(&t);
|
|
|
|
|
/* Now, is this a subcircuit model? */
|
|
|
|
|
for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) {
|
|
|
|
|
if (eq(name, wlsub->wl_word)) { /* a five terminal bjt */
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer),
|
|
|
|
|
"%s:%s ", subname, name);
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if (!found) /* Fallback w/o subckt name before */
|
2000-04-27 22:03:57 +02:00
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
2009-11-09 10:15:21 +01:00
|
|
|
tfree(name);
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
found = FALSE;
|
|
|
|
|
|
|
|
|
|
(void) strcat(buffer, t);
|
|
|
|
|
tfree(s->li_line);
|
|
|
|
|
s->li_line = buffer;
|
|
|
|
|
break;
|
|
|
|
|
|
2010-02-07 19:16:17 +01:00
|
|
|
/* 4-18 terminal devices */
|
2010-01-27 22:26:08 +01:00
|
|
|
case 'p': /* cpl */
|
|
|
|
|
name = gettok(&t); /* get refdes */
|
|
|
|
|
(void) sprintf(buffer,"%s ",name);
|
|
|
|
|
tfree(name);
|
|
|
|
|
|
|
|
|
|
/* now do remainder of line. */
|
|
|
|
|
next_name = gettok(&t);
|
2010-09-07 22:07:57 +02:00
|
|
|
for (;;) {
|
2010-01-27 22:26:08 +01:00
|
|
|
name = next_name;
|
|
|
|
|
next_name = gettok(&t);
|
|
|
|
|
if((next_name == NULL) ||
|
2010-02-07 19:16:17 +01:00
|
|
|
(strstr(next_name, "len") != NULL)) {
|
|
|
|
|
/* if next_name is NULL or len or length, we are at the line end.
|
2010-01-27 22:26:08 +01:00
|
|
|
* name holds the model name. Therefore, break */
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
/* next_name holds something. Write name into the buffer and continue. */
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
tfree(name);
|
|
|
|
|
}
|
|
|
|
|
} /* while */
|
|
|
|
|
|
|
|
|
|
/* Now, is this a subcircuit model? */
|
|
|
|
|
for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) {
|
|
|
|
|
if (eq(name, wlsub->wl_word)) {
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s:%s ",
|
|
|
|
|
subname, name);
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
(void) sprintf(buffer + strlen(buffer), "%s ", name);
|
|
|
|
|
(void) strcat(buffer, t);
|
|
|
|
|
tfree(s->li_line);
|
|
|
|
|
s->li_line = buffer;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2000-04-27 22:03:57 +02:00
|
|
|
tfree(buffer);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/*----------------------------------------------------------------------*
|
|
|
|
|
* inp_numnodes returns the number of nodes (netnames) attached to the
|
|
|
|
|
* component.
|
|
|
|
|
* This is a spice-dependent thing. It should probably go somewhere
|
2000-04-27 22:03:57 +02:00
|
|
|
* else, but... Note that we pretend that dependent sources and mutual
|
|
|
|
|
* inductors have more nodes than they really do...
|
2003-07-23 21:36:39 +02:00
|
|
|
*----------------------------------------------------------------------*/
|
2005-04-04 12:38:45 +02:00
|
|
|
static int
|
2000-04-27 22:03:57 +02:00
|
|
|
inp_numnodes(char c)
|
|
|
|
|
{
|
|
|
|
|
if (isupper(c))
|
|
|
|
|
c = tolower(c);
|
|
|
|
|
switch (c) {
|
|
|
|
|
case ' ':
|
|
|
|
|
case '\t':
|
|
|
|
|
case '.':
|
|
|
|
|
case 'x':
|
2007-10-08 23:10:34 +02:00
|
|
|
case '*': case '$':
|
2000-04-27 22:03:57 +02:00
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
case 'b': return (2);
|
|
|
|
|
case 'c': return (2);
|
|
|
|
|
case 'd': return (2);
|
2003-07-23 21:36:39 +02:00
|
|
|
case 'e': return (2); /* changed from 4 to 2 by SDB on 4.22.2003 to enable POLY */
|
2000-04-27 22:03:57 +02:00
|
|
|
case 'f': return (2);
|
2003-07-23 21:36:39 +02:00
|
|
|
case 'g': return (2); /* changed from 4 to 2 by SDB on 4.22.2003 to enable POLY */
|
2000-04-27 22:03:57 +02:00
|
|
|
case 'h': return (2);
|
|
|
|
|
case 'i': return (2);
|
|
|
|
|
case 'j': return (3);
|
|
|
|
|
case 'k': return (0);
|
|
|
|
|
case 'l': return (2);
|
2001-01-24 12:19:39 +01:00
|
|
|
case 'm': return (7); /* This means that 7 is the maximun number of nodes */
|
2000-04-27 22:03:57 +02:00
|
|
|
case 'o': return (4);
|
2010-02-07 19:16:17 +01:00
|
|
|
case 'p': return (18);/* 16 lines + 2 gnd is the maximum number of nodes for CPL */
|
2006-02-21 16:25:23 +01:00
|
|
|
case 'q': return (5);
|
2000-04-27 22:03:57 +02:00
|
|
|
case 'r': return (2);
|
|
|
|
|
case 's': return (4);
|
|
|
|
|
case 't': return (4);
|
|
|
|
|
case 'u': return (3);
|
|
|
|
|
case 'v': return (2);
|
2010-01-27 22:26:08 +01:00
|
|
|
case 'w': return (2); /* change 3 to 2 here to fix w bug, NCF 1/31/95 */
|
|
|
|
|
case 'y': return (4);
|
2000-04-27 22:03:57 +02:00
|
|
|
case 'z': return (3);
|
|
|
|
|
|
|
|
|
|
default:
|
2010-01-27 22:26:08 +01:00
|
|
|
fprintf(cp_err, "Warning: unknown device type: %c\n", c);
|
|
|
|
|
return (2);
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
}
|