📄 spiceif.c
字号:
/* RCS Info: $Revision: 1.8 $ on $Date: 92/09/18 14:08:14 $ * $Source: //carob/xspice/src/sim/FTE/RCS/spiceif.c,v $ * Copyright (c) 1985 Wayne A. Christopher, U. C. Berkeley CAD Group * * Interface routines. These are specific to spice. The only changes to FTE * that should be needed to make FTE work with a different simulator is * to rewrite this file. What each routine is expected to do can be * found in the programmer's manual. This file should be the only one * that includes spice header files. */#include "prefix.h"#include "CPdefs.h"#include "FTEdefs.h"#include "FTEinp.h"#ifndef CMS#include "FTEconstant.h"#else /* CMS */#include "FTEconst.h"#endif /* CMS */#include "INPdefs.h"#ifndef CMS#include "IFerrmsgs.h"#else /* CMS */#include "IFerrmsg.h"#endif /* CMS */#include "IFsim.h"#include "util.h"/* gtri - add - wbk - 11/9/90 - include MIF function prototypes */#include "MIFproto.h"/* gtri - end - wbk - 11/9/90 *//* gtri - evt - wbk - 5/20/91 - Add stuff for user-defined nodes */#include "EVTproto.h"#include "EVTudn.h"/* gtri - end - wbk - 5/20/91 - Add stuff for user-defined nodes */#include "suffix.h"/* for HLP */char *hlp_filelist[] = {"NUTMEG", "SPICE", "" };bool if_isnutmeg = false;static IFvalue *doask();static int finddev();static IFparm * parmlookup();static struct variable *parmtovar();/* Stuff from INP and DEV... *//* Input a single deck, and return a pointer to the circuit. */char *if_inpdeck(deck, tab) struct line *deck; char **tab;{ GENERIC *ckt; int err, i, j; struct line *ll; IFuid taskUid; IFuid optUid; int which = -1; for (i = 0, ll = deck; ll; ll = ll->li_next) i++; *tab = (char *) INPtabInit(i); ft_curckt->ci_symtab = *tab; if ((err = (*(ft_sim->newCircuit))(&ckt)) != OK) { ft_sperror(err, "CKTinit"); return (NULL); } err = IFnewUid(ckt,&taskUid,(IFuid)NULL,"default",UID_TASK,(GENERIC**)NULL); if(err) { ft_sperror(err,"newUid"); return(NULL); } err = (*(ft_sim->newTask))(ckt,(GENERIC**)&(ft_curckt->ci_defTask),taskUid); if(err) { ft_sperror(err,"newTask"); return(NULL); } for(j=0;j<ft_sim->numAnalyses;j++) { if(strcmp(ft_sim->analyses[j]->name,"options")==0) { which = j; break; } } if(which != -1) { err = IFnewUid(ckt,&optUid,(IFuid)NULL,"options",UID_ANALYSIS, (GENERIC**)NULL); if(err) { ft_sperror(err,"newUid"); return(NULL); } err = (*(ft_sim->newAnalysis))(ft_curckt->ci_ckt,which,optUid, (GENERIC**)&(ft_curckt->ci_defOpt), (GENERIC*)ft_curckt->ci_defTask); if(err) { ft_sperror(err,"createOptions"); return(NULL); } ft_curckt->ci_curOpt = ft_curckt->ci_defOpt; } ft_curckt->ci_curTask = ft_curckt->ci_defTask; INPpas1((GENERIC *) ckt, (card *) deck->li_next,(INPtables *)*tab); INPpas2((GENERIC *) ckt, (card *) deck->li_next, (INPtables *) *tab,ft_curckt->ci_defTask); INPkillMods();/* gtri - begin - wbk - 6/6/91 - Finish initialization of event driven structures */ err = EVTinit((void *) ckt); if(err) { ft_sperror(err,"EVTinit"); return(NULL); }/* gtri - end - wbk - 6/6/91 - Finish initialization of event driven structures */ return (ckt);}/* Do a run of the circuit, of the given type. Type "resume" is special -- * it means to resume whatever simulation that was in progress. The * return value of this routine is 0 if the exit was ok, and 1 if there was * a reason to interrupt the circuit (interrupt typed at the keyboard, * error in the simulation, etc). args should be the entire command line, * e.g. "tran 1 10 20 uic" */intif_run(t, what, args, tab) char *t; char *what; wordlist *args; char *tab;{ GENERIC *ckt = (GENERIC *) t; int err; struct line deck; char buf[BSIZE]; int j; int which = -1; IFuid specUid,optUid; /* First parse the line... */ if (eq(what, "tran") || eq(what, "ac") || eq(what, "dc") || eq(what, "op") || eq(what, "pz")) { (void) sprintf(buf, ".%s", wl_flatten(args)); deck.li_next = deck.li_actual = NULL; deck.li_error = NULL; deck.li_linenum = 0; deck.li_line = buf; if(ft_curckt->ci_specTask) { err=(*(ft_sim->deleteTask))(ft_curckt->ci_ckt, ft_curckt->ci_specTask); if(err) { ft_sperror(err,"deleteTask"); return(1); } } err = IFnewUid(ft_curckt->ci_ckt,&specUid,(IFuid)NULL,"special", UID_TASK,(GENERIC**)NULL); if(err) { ft_sperror(err,"newUid"); return(1); } err = (*(ft_sim->newTask))(ft_curckt->ci_ckt, (GENERIC**)&(ft_curckt->ci_specTask),specUid); if(err) { ft_sperror(err,"newTask"); return(1); } for(j=0;j<ft_sim->numAnalyses;j++) { if(strcmp(ft_sim->analyses[j]->name,"options")==0) { which = j; break; } } if(which != -1) { err = IFnewUid(ft_curckt->ci_ckt,&optUid,(IFuid)NULL,"options", UID_ANALYSIS,(GENERIC**)NULL); if(err) { ft_sperror(err,"newUid"); return(1); } err = (*(ft_sim->newAnalysis))(ft_curckt->ci_ckt,which,optUid, (GENERIC**)&(ft_curckt->ci_specOpt), (GENERIC*)ft_curckt->ci_specTask); if(err) { ft_sperror(err,"createOptions"); return(0); } ft_curckt->ci_curOpt = ft_curckt->ci_specOpt; } ft_curckt->ci_curTask = ft_curckt->ci_specTask; INPpas2(ckt, (card *) &deck, (INPtables *)tab, ft_curckt->ci_specTask); if (deck.li_error) { /* INP produdes an E_EXISTS error here... Don't * make this fatal... */ fprintf(cp_err, "Warning: %s\n", deck.li_error); } } if( eq(what,"run") ) { ft_curckt->ci_curTask = ft_curckt->ci_defTask; ft_curckt->ci_curOpt = ft_curckt->ci_defOpt; } /* Then do the stuff. */ if ( (eq(what, "tran")) || (eq(what, "ac")) || (eq(what, "dc")) || (eq(what, "op")) || (eq(what, "pz")) || (eq(what, "run")) ) { if ((err = (*(ft_sim->doAnalyses))(ckt, 1, ft_curckt->ci_curTask))!=OK){ ft_sperror(err, "doAnalyses"); /* wrd_end(); */ return (1); } } else if (eq(what, "resume")) { if ((err = (*(ft_sim->doAnalyses))(ckt, 0, ft_curckt->ci_curTask))!=OK){ ft_sperror(err, "doAnalyses"); /* wrd_end(); */ return (1); } } else { fprintf(cp_err, "if_run: Internal Error: bad run type %s\n", what); } return (0);}/* Set an option in the circuit. Arguments are option name, type, and * value (the last a char *), suitable for casting to whatever needed... */static char *unsupported[] = { "itl3", "itl5", "lvltim", "maxord", "method", NULL} ;static char *obsolete[] = { "limpts", "limtim", "lvlcod", "nomod", NULL} ;voidif_option(ckt, name, type, value) char *ckt; char *name; int type; char *value;{ IFvalue pval; int err, i; GENERIC *cc = (GENERIC *) ckt; char **vv; int which = -1; if (eq(name, "acct")) { ft_acctprint = true; return; } else if (eq(name, "list")) { ft_listprint = true; return; } else if (eq(name, "node")) { ft_nodesprint = true; return; } else if (eq(name, "opts")) { ft_optsprint = true; return; } else if (eq(name, "nopage")) { ft_nopage = true; return; } for(i=0;i<ft_sim->numAnalyses;i++) { if(strcmp(ft_sim->analyses[i]->name,"options")==0) { which = i; break; } } if(which==-1) { fprintf(cp_err,"Warning: .options card unsupported\n"); return; } for (i = 0; i < ft_sim->analyses[which]->numParms; i++) if (eq(ft_sim->analyses[which]->analysisParms[i].keyword, name) && (ft_sim->analyses[which]->analysisParms[i].dataType & IF_SET)) break; if (i == ft_sim->analyses[which]->numParms) { /* See if this is unsupported or obsolete. */ for (vv = unsupported; *vv; vv++) if (eq(name, *vv)) { fprintf(cp_err, "Warning: option %s is currently unsupported.\n", name); return; } for (vv = obsolete; *vv; vv++) if (eq(name, *vv)) { fprintf(cp_err, "Warning: option %s is obsolete.\n", name); return; } return; }#ifndef LINT switch (ft_sim->analyses[which]->analysisParms[i].dataType & IF_VARTYPES) {#else switch (i) {#endif case IF_REAL: if (type == VT_REAL) pval.rValue = *((double *) value); else if (type == VT_NUM) pval.rValue = *((int *) value); else goto badtype; break; case IF_INTEGER: if (type == VT_NUM) pval.iValue = *((int *) value); else if (type == VT_REAL) pval.iValue = *((double *) value); else goto badtype; break; case IF_STRING: if (type == VT_STRING) pval.sValue = copy(value); else goto badtype; break; case IF_FLAG: /* Do nothing. */ pval.iValue = 1; break; default: fprintf(cp_err, "if_option: Internal Error: bad option type %d.\n", ft_sim->analyses[which]->analysisParms[i].dataType); } if ((err = (*(ft_sim->setAnalysisParm))(cc, (GENERIC *)ft_curckt->ci_curOpt, ft_sim->analyses[which]->analysisParms[i].id, &pval, (IFvalue *)NULL)) != OK) ft_sperror(err, "setAnalysisParm(options)"); return;badtype: fprintf(cp_err, "Error: bad type given for option %s --\n", name); fprintf(cp_err, "\ttype given was "); switch (type) { case VT_BOOL: fputs("boolean", cp_err); break; case VT_NUM: fputs("integer", cp_err); break; case VT_REAL: fputs("real", cp_err); break; case VT_STRING: fputs("string", cp_err); break; case VT_LIST: fputs("list", cp_err); break; default: fputs("something strange", cp_err); break; } fprintf(cp_err, ", type expected was ");#ifndef LINT switch(ft_sim->analyses[which]->analysisParms[i].dataType & IF_VARTYPES) {#else switch (i) {#endif case IF_REAL: fputs("real.\n", cp_err); break; case IF_INTEGER:fputs("integer.\n", cp_err); break; case IF_STRING: fputs("string.\n", cp_err); break; case IF_FLAG: fputs("flag.\n", cp_err); break; default: fputs("something strange.\n", cp_err); break; } if (type == VT_BOOL)fputs("\t(Note that you must use an = to separate option name and value.)\n", cp_err); return;}/* ARGSUSED */voidif_dump(ckt, file) char *ckt; FILE *file;{ /*GENERIC *cc = (GENERIC *) ckt;*/ fprintf(file,"diagnostic output dump unavailable."); return;}voidif_cktfree(ckt, tab) char *ckt; char *tab;{ GENERIC *cc = (GENERIC *) ckt; (*(ft_sim->deleteCircuit))(cc); INPtabEnd((INPtables *) tab); return;}/* Return a string describing an error code. *//* BLOW THIS AWAY.... */char *if_errstring(code) int code;{ return (INPerror(code));}/* Get a parameter value from the circuit. If name is left unspecified, * we want a circuit parameter. */struct variable *if_getparam(ckt, name, param, ind) char *ckt; char **name; char *param; int ind;{ struct variable *vv = NULL, *tv; IFvalue *pv; IFparm *opt; int typecode, i; GENinstance *dev=(GENinstance *)NULL; GENmodel *mod=(GENmodel *)NULL; IFdevice *device; /* fprintf(cp_err, "Calling if_getparam(%s, %s)\n", *name, param); */ if (param && eq(param, "all")) { INPinsert(name,(INPtables *)ft_curckt->ci_symtab); typecode = finddev(ckt, *name,(GENERIC**) &dev,(GENERIC**) &mod); if (typecode == -1) { fprintf(cp_err, "Error: no such device or model name %s\n", *name); return (NULL); } device = ft_sim->devices[typecode]; for (i = 0; i < device->numInstanceParms; i++) { opt = &device->instanceParms[i]; if(!(opt->dataType & IF_ASK)) continue; pv = doask(ckt, typecode, dev, mod, opt, ind); if (pv) { tv = parmtovar(pv, opt); if (vv) tv->va_next = vv; vv = tv; } else fprintf(cp_err, "Internal Error: no parameter '%s' on device '%s'\n", device->instanceParms[i].keyword, device->name); } return (vv); } else if (param) { INPinsert(name,(INPtables *)ft_curckt->ci_symtab); typecode = finddev(ckt, *name, (GENERIC**)&dev, (GENERIC**)&mod); if (typecode == -1) { fprintf(cp_err, "Error: no such device or model name %s\n", *name); return (NULL); } device = ft_sim->devices[typecode]; opt = parmlookup(device, &dev, param); if (!opt) { fprintf(cp_err, "Error: no such parameter %s.\n", param); return (NULL); } pv = doask(ckt, typecode, dev, mod, opt, ind); if (pv) vv = parmtovar(pv, opt); return (vv); } else return (if_getstat(ckt, *name)); /* The way I used to do this was to make @foo refer to all the * parameters of the device foo... */#ifdef notdef } else if (dev) { /* He wants a list of them all. */ for (i = 0; i < device->DEVquestCount; i++) { opt = &device->DEVquests[i]; pv = doask(ckt, typecode, dev, mod, opt, ind); tv = parmtovar(pv, opt); if (vv) tv->va_next = vv; vv = tv; } return (vv); } else { for (i = 0; i < device->DEVmodQuestCount; i++) { opt = &device->DEVmodQuests[i]; pv = doask(ckt, typecode, dev, mod, opt, ind); tv = parmtovar(pv, opt); if (vv) tv->va_next = vv; vv = tv; } return (vv); }#endif}/* ARGSUSED */voidif_setparam(ckt, name, param, val) char *ckt; char *name; char *param; struct variable *val;{}static struct variable *parmtovar(pv, opt) IFvalue *pv; IFparm *opt;{ struct variable *vv = alloc(variable);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -