📄 subckt.c
字号:
/**********Copyright 1990 Regents of the University of California. All rights reserved.Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group Modified: 2000 AlansFixes$Id: subckt.c,v 1.21 2005/05/30 20:28:35 sjborley Exp $**********//*------------------------------------------------------------------------------ * 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 * 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 *-----------------------------------------------------------------------------*//* * Expand subcircuits. This is very spice-dependent. Bug fixes by Norbert * Jeske on 10/5/85. *//*======================================================================* * 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. *======================================================================*/#include "ngspice.h"#include "cpdefs.h"#include "ftedefs.h"#include "fteinp.h"#ifdef XSPICE/* gtri - add - wbk - 11/9/90 - include MIF function prototypes */#include "mifproto.h"/* gtri - end - wbk - 11/9/90 */#endif#include "subckt.h"#include "variable.h"#ifdef NUMPARAMS/* Uncomment to turn on tracing for the Numparam *//*#define TRACE_NUMPARAMS*/#include "numparam/numpaif.h"#endif/* ----- static declarations ----- */static struct line * doit(struct line *deck);static int translate(struct line *deck, char *formal, char *actual, char *scname, char *subname);static void finishLine(char *dst, char *src, char *scname);static int settrans(char *formal, char *actual, char *subname);static char * gettrans(char *name);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 * 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. *//*--------------------------------------------------------------------- * subs is the linked list which holds the .subckt definitions * found during processing. *--------------------------------------------------------------------*/struct subs { char *su_name; /* The .subckt name. */ char *su_args; /* The .subckt arguments, space separated. */ int su_numargs; struct line *su_def; /* Pointer to the .subckt definition. */ struct subs *su_next;} ;/* submod is the list of original model names, modnames is the * list of translated names (i.e. after subckt expansion) */static wordlist *modnames, *submod;static struct subs *subs = NULL;static bool nobjthack = FALSE;#ifdef NUMPARAMS/* flag indicating use of the experimental numparams library */static bool use_numparams = FALSE; #endif /* NUMPARAMS */static char start[32], sbend[32], invoke[32], model[32];#ifdef GLOBAL_NODEstatic char node[128][128];static int numgnode;#endif /* GLOBAL_NODE *//*-------------------------------------------------------------------*//* inp_subcktexpand is the top level function which translates *//* .subckts into mainlined code. Note that there are two 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. *//* *//* The algorithm is as follows: *//* 1. Define some aliases for .subckt, .ends, etc. *//* 2. Clean up parens around netnames *//* 3. Call doit, which does the actual translation. *//* 4. 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. *//*-------------------------------------------------------------------*/struct line *inp_subcktexpand(struct line *deck){ struct line *ll, *c; char *s;#ifdef NUMPARAMS int ok;#endif /* NUMPARAMS */#ifdef GLOBAL_NODE char *t; int i;#endif /* GLOBAL_NODE */ 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"); if(!cp_getvar("modelcard", VT_STRING, model)) (void) strcpy(model, ".model"); if(!cp_getvar("modelline", VT_STRING, model)) (void) strcpy(model, ".model"); (void) cp_getvar("nobjthack", VT_BOOL, (char *) &nobjthack); #ifdef NUMPARAMS (void) cp_getvar("numparams", VT_BOOL, (char *) &use_numparams); /* deck has .control sections already removed, but not comments */ if ( use_numparams ) { #ifdef TRACE_NUMPARAMS printf("Numparams is processing this deck:\n"); c=deck; while( c!=NULL) { printf("%3d:%s\n",c->li_linenum, c->li_line); c= c->li_next; }#endif /* TRACE_NUMPARAMS */ ok = nupa_signal( NUPADECKCOPY, NULL); c=deck; while ( c != NULL) { /* first Numparam pass */ nupa_scan(c->li_line, c->li_linenum); c= c->li_next; } c=deck; while ( c != NULL) { /* first Numparam pass */ c->li_line = nupa_copy(c->li_line, c->li_linenum); c= c->li_next; } #ifdef TRACE_NUMPARAMS printf("Numparams transformed deck:\n"); c=deck; while( c!=NULL) { printf("%3d:%s\n",c->li_linenum, c->li_line); c= c->li_next; }#endif /* TRACE_NUMPARAMS */ }#endif /* NUMPARAMS */ /* 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 /* TRACE *//* Added by H.Tanaka to find global nodes */#ifdef GLOBAL_NODE for(i=0;i<128;i++) strcpy(node[i],"");/* Clear global node holder */ for (c = deck; c; c = c->li_next) { 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); while (isspace(*s)) s++; numgnode++; } /* node[] holds name of global node */#ifdef TRACE 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");#endif /* TRACE */ c->li_line[0] = '*'; /* comment it out */ }/* if(ciprefix.. */ } /* for(c=deck.. */#endif /* GLOBAL_NODE */ /* 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 (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);#endif /* TRACE */ for (s = c->li_line; *s && (*s != '('); s++) /* Iterate charwise along line until ( is found */ ; if (*s) { while (s[0] && (s[1] != ')')) { s[0] = s[1]; s++; } while (s[1]) { s[0] = s[2]; s++; } } /* if (*s) . . . */ } else { for (s = c->li_line; *s && !isspace(*s); s++) /* Iterate charwise along line until space is found */ ; while (isspace(*s)) s++; if (*s == '(') { while (s[0] && (s[1] != ')')) { s[0] = s[1]; s++; } while (s[1]) { s[0] = s[2]; s++; } /* while */ } /* if (*s == '(' . . . */ } } /* for (c = deck . . . */ /* doit does the actual splicing in of the .subckt . . . */#ifdef TRACE /* SDB debug statement */ printf("In inp_subcktexpand, about to call doit.\n");#endif /* TRACE */ 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)) { fprintf(cp_err, "Error: unknown subckt: %s\n", c->li_line);#ifdef NUMPARAMS if ( use_numparams ) { ok= ok && nupa_signal(NUPAEVALDONE, NULL); }#endif /* NUMPARAMS */ return NULL; } #ifdef NUMPARAMS if ( use_numparams ) { /* the NUMPARAM final line translation pass */ ok= ok && nupa_signal(NUPASUBDONE, NULL); c= ll; while (c != NULL) { ok= ok && nupa_eval( c->li_line, c->li_linenum); c= c->li_next; }#ifdef TRACE_NUMPARAMS printf("Numparams converted deck:\n"); c=ll; while( c!=NULL) { printf("%3d:%s\n",c->li_linenum, c->li_line); c= c->li_next; }#endif /* TRACE_NUMPARAMS */ ok= ok && nupa_signal(NUPAEVALDONE, NULL); }#endif /* NUMPARAMS */ return (ll); /* return the spliced deck. */}#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. *//*-------------------------------------------------------------------*/static struct line *doit(struct line *deck){ struct line *c, *last, *lc, *lcc;#ifdef NUMPARAMS struct line *savenext;#endif /* NUMPARAMS */ struct subs *sss = (struct subs *) NULL, *ks; /* *sss and *ks temporarily hold decks to substitute */ 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;#ifdef TRACE /* SDB debug statement */ printf("In doit, about to start first pass through deck.\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -