1 /***************************************************************************
2 JSPICE3 adaptation of Spice3f2 - Copyright (c) Stephen R. Whiteley 1992
3 Copyright 1990 Regents of the University of California. All rights reserved.
4 Authors: 1985 Wayne A. Christopher
5 1992 Stephen R. Whiteley
6 ****************************************************************************/
7
8 /*
9 * Interface routines. These are specific to spice. The only changes to FTE
10 * that should be needed to make FTE work with a different simulator is
11 * to rewrite this file. What each routine is expected to do can be
12 * found in the programmer's manual. This file should be the only one
13 * that includes spice header files.
14 */
15
16 #include "spice.h"
17 #include "ftedefs.h"
18 #include "ftedebug.h"
19 #include "spfteext.h"
20 #include "inpdefs.h"
21 #include "fteinp.h"
22 #include "jobdefs.h"
23 #include "iferrmsg.h"
24 #include "util.h"
25
26 #ifdef __STDC__
27 static int get_anal(char*);
28 static void set_options(void);
29 static struct variable *parmtovar(IFvalue*,IFparm*);
30 static IFparm * parmlookup(IFdevice*,GENinstance*,GENmodel*,char*);
31 static IFvalue *doask(char*,int,GENinstance*,GENmodel*,IFparm*,int);
32 static int finddev(char*,char*,GENERIC**,GENERIC**);
33 #else
34 static int get_anal();
35 static void set_options();
36 static struct variable *parmtovar();
37 static IFparm * parmlookup();
38 static IFvalue *doask();
39 static int finddev();
40 #endif
41
42
43 char *
if_inpdeck(deck,tab)44 if_inpdeck(deck, tab)
45
46 /* Input a single deck, and return a pointer to the circuit. */
47 struct line *deck;
48 char **tab;
49 {
50 GENERIC *ckt;
51 int err, i, j;
52 struct line *ll;
53 IFuid taskUid;
54 IFuid optUid;
55 int which;
56
57 for (i = 0, ll = deck; ll; ll = ll->li_next)
58 i++;
59 *tab = (char *)INPtabInit(i);
60 ft_curckt->ci_symtab = *tab;
61 if ((err = (*(ft_sim->newCircuit))(&ckt)) != OK) {
62 ft_sperror(err, "CKTinit");
63 return (NULL);
64 }
65 err =
66 IFnewUid(ckt,&taskUid,(IFuid)NULL,"default",UID_TASK,(GENERIC**)NULL);
67 if (err) {
68 ft_sperror(err,"newUid");
69 return (NULL);
70 }
71 err =
72 (*(ft_sim->newTask))(ckt,(GENERIC**)&(ft_curckt->ci_defTask),taskUid);
73 if (err) {
74 ft_sperror(err,"newTask");
75 return (NULL);
76 }
77 which = get_anal("options");
78 if (which != -1) {
79 err = IFnewUid(ckt,&optUid,(IFuid)NULL,"options",UID_ANALYSIS,
80 (GENERIC**)NULL);
81 if (err) {
82 ft_sperror(err,"newUid");
83 return (NULL);
84 }
85 err = (*(ft_sim->newAnalysis))(ckt,which,optUid,
86 (GENERIC**)&(ft_curckt->ci_defOpt),
87 (GENERIC*)ft_curckt->ci_defTask);
88 if (err) {
89 ft_sperror(err,"createOptions");
90 return (NULL);
91 }
92 ft_curckt->ci_curOpt = ft_curckt->ci_defOpt;
93 }
94 ft_curckt->ci_curTask = ft_curckt->ci_defTask;
95 INPpas1((GENERIC *) ckt, (card *) deck->li_next,(INPtables *)*tab);
96 INPpas2((GENERIC *) ckt, (card *) deck->li_next,
97 (INPtables *) *tab,ft_curckt->ci_defTask);
98 INPkillMods();
99 return (ckt);
100 }
101
102
103 int
if_run(what,args)104 if_run(what, args)
105
106 /* Do a run of the circuit, of the given type. Type "resume" is special --
107 * it means to resume whatever simulation that was in progress. The
108 * return value of this routine is 0 if the exit was ok, and 1 if there was
109 * a reason to interrupt the circuit (interrupt typed at the keyboard,
110 * error in the simulation, etc).
111 * args may be the entire command line,
112 * e.g. "tran 1 10 20 uic",
113 * or only the arguments that follow "what".
114 */
115 char *what;
116 wordlist *args;
117 {
118 GENERIC *ckt = (GENERIC *)ft_curckt->ci_ckt;
119 INPtables *tab = (INPtables *)ft_curckt->ci_symtab;
120 int err;
121 struct line deck;
122 char buf[BSIZE_SP], *tmp;
123 int j;
124 int which;
125 IFuid specUid,optUid;
126
127 /* First parse the line... */
128 if (eq(what,"sens") || eq(what, "tran") || eq(what, "ac") ||
129 eq(what, "dc") || eq(what, "op") || eq(what, "pz") ||
130 eq(what,"disto")|| eq(what,"tf") || eq(what, "noise")) {
131
132 if (args) {
133 tmp = wl_flatten(args);
134 if (ciprefix(what,tmp))
135 (void) sprintf(buf, ".%s", tmp);
136 else
137 (void) sprintf(buf, ".%s %s", what, tmp);
138 txfree(tmp);
139 }
140 else
141 (void) sprintf(buf, ".%s", what);
142
143 deck.li_next = deck.li_actual = NULL;
144 deck.li_error = NULL;
145 deck.li_linenum = 0;
146 deck.li_line = buf;
147
148 if (ft_curckt->ci_specTask) {
149 err = (*(ft_sim->deleteTask))(ckt, ft_curckt->ci_specTask);
150 if (err) {
151 ft_sperror(err,"deleteTask");
152 return (2);
153 }
154 }
155 err = IFnewUid(ckt,&specUid,(IFuid)NULL,"special",
156 UID_TASK,(GENERIC**)NULL);
157 if (err) {
158 ft_sperror(err,"newUid");
159 return (2);
160 }
161 err = (*(ft_sim->newTask))(ckt,
162 (GENERIC**)&(ft_curckt->ci_specTask),specUid);
163 if (err) {
164 ft_sperror(err,"newTask");
165 return (2);
166 }
167 which = get_anal("options");
168 if (which != -1) {
169 err = IFnewUid(ckt,&optUid,(IFuid)NULL,"options",
170 UID_ANALYSIS,(GENERIC**)NULL);
171 if (err) {
172 ft_sperror(err,"newUid");
173 return (2);
174 }
175 err = (*(ft_sim->newAnalysis))(ckt,which,optUid,
176 (GENERIC**)&(ft_curckt->ci_specOpt),
177 (GENERIC*)ft_curckt->ci_specTask);
178 if (err) {
179 ft_sperror(err,"createOptions");
180 return (2);
181 }
182 ft_curckt->ci_curOpt = ft_curckt->ci_specOpt;
183 set_options();
184 }
185 ft_curckt->ci_curTask = ft_curckt->ci_specTask;
186
187 INPpas2(ckt, (card *) &deck, tab, ft_curckt->ci_specTask);
188 if (deck.li_error) {
189 /* INP produdes an E_EXISTS error here... Don't
190 * make this fatal...
191 */
192 fprintf(cp_err, "Warning: %s\n", deck.li_error);
193 }
194 }
195 if ( eq(what,"run") ) {
196 ft_curckt->ci_curTask = ft_curckt->ci_defTask;
197 ft_curckt->ci_curOpt = ft_curckt->ci_defOpt;
198 }
199
200 if ( (eq(what, "tran")) ||
201 (eq(what, "ac")) ||
202 (eq(what, "dc")) ||
203 (eq(what, "op")) ||
204 (eq(what, "pz")) ||
205 (eq(what, "disto")) ||
206 (eq(what, "sens")) ||
207 (eq(what, "noise")) ||
208 (eq(what, "tf")) ||
209 (eq(what, "run")) ) {
210 if ((err =
211 (*(ft_sim->doAnalyses))(ckt, 1, ft_curckt->ci_curTask)) != OK) {
212 if (err == E_PAUSE)
213 return (1);
214 else {
215 ft_sperror(err, "doAnalyses");
216 return (2);
217 }
218 }
219 }
220 else if (eq(what, "resume")) {
221 if ((err =
222 (*(ft_sim->doAnalyses))(ckt, 0, ft_curckt->ci_curTask)) != OK) {
223 if (err == E_PAUSE)
224 return (1);
225 else {
226 ft_sperror(err, "doAnalyses");
227 return (2);
228 }
229 }
230 }
231 else {
232 fprintf(cp_err, "if_run: Internal Error: bad run type %s\n", what);
233 return (2);
234 }
235 return (0);
236 }
237
238
239 static int
get_anal(string)240 get_anal(string)
241 char *string;
242 {
243 int i;
244
245 for (i = 0; i < ft_sim->numAnalyses; i++) {
246 if (strcmp(ft_sim->analyses[i]->name,string) == 0) {
247 return (i);
248 }
249 }
250 return (-1);
251 }
252
253
254 static void
set_options()255 set_options()
256
257 /* Set the options for the "special" task. If analysis is initiated with
258 * the "run" command, we use the options found in the .options line only,
259 * which have already been set (so this routine need not be called).
260 * Otherise if an analysis is given, a new task is created. This routine
261 * is called to first set the options found in the .options line, then
262 * (laboriously) set any options that were entered with the "set" command.
263 * The options set with the "set" command override those set in the
264 * .options line. Note that if "run" is used, the "set" options are
265 * ignored.
266 */
267 {
268 int i, which, type;
269 char *name, *vv;
270 double f;
271 struct variable *var;
272 struct line *opt;
273
274
275 for (opt = ft_curckt->ci_options; opt; opt = opt->li_next) {
276 txfree(opt->li_error);
277 opt->li_error = NULL;
278 INP2dot(ft_curckt->ci_ckt,(INPtables*)ft_curckt->ci_symtab,
279 (card*)opt,NULL,NULL);
280 }
281
282 /* set the "set" variables */
283 which = get_anal("options");
284 if (which == -1) return;
285
286 for (i = 0; i < ft_sim->analyses[which]->numParms; i++) {
287 type = ft_sim->analyses[which]->analysisParms[i].dataType;
288 if (type & IF_SET) {
289
290 name = ft_sim->analyses[which]->analysisParms[i].keyword;
291
292 if (type & IF_FLAG) {
293 if (cp_getvar(name,VT_BOOL,(char*)&f))
294 if_option(ft_curckt->ci_ckt, name, VT_BOOL, (char*)&f);
295 }
296 else if (type & IF_INTEGER) {
297 if (cp_getvar(name,VT_NUM,(char*)&f))
298 if_option(ft_curckt->ci_ckt, name, VT_NUM, (char*)&f);
299 }
300 else if (type & IF_REAL) {
301 if (cp_getvar(name,VT_REAL,(char*)&f))
302 if_option(ft_curckt->ci_ckt, name, VT_REAL, (char*)&f);
303 }
304 else if (type & IF_STRING) {
305 if (cp_getvar(name,VT_STRING,(char*)&f))
306 if_option(ft_curckt->ci_ckt, name, VT_STRING, (char*)&f);
307 }
308 }
309 }
310 }
311
312 static char *unsupported[] = {
313 "itl3",
314 "itl5",
315 "lvltim",
316 "maxord",
317 "method",
318 NULL
319 } ;
320
321 static char *obsolete[] = {
322 "limpts",
323 "limtim",
324 "lvlcod",
325 "nomod",
326 NULL
327 } ;
328
329
330 void
if_option(ckt,name,type,value)331 if_option(ckt, name, type, value)
332
333 /* Set an option in the circuit. Arguments are option name, type, and
334 * value (the last a char *), suitable for casting to whatever needed...
335 */
336 char *ckt;
337 char *name;
338 int type;
339 char *value;
340 {
341 IFvalue pval;
342 int err, i;
343 GENERIC *cc = (GENERIC *) ckt;
344 char **vv;
345 int which;
346
347 if (eq(name, "acct")) {
348 ft_acctprint = true;
349 return;
350 }
351 else if (eq(name, "list")) {
352 ft_listprint = true;
353 return;
354 }
355 else if (eq(name, "node")) {
356 ft_nodesprint = true;
357 return;
358 }
359 else if (eq(name, "opts")) {
360 ft_optsprint = true;
361 return;
362 }
363 else if (eq(name, "nopage")) {
364 ft_nopage = true;
365 return;
366 }
367
368 which = get_anal("options");
369 if (which == -1) {
370 fprintf(cp_err,"Warning: .options card unsupported\n");
371 return;
372 }
373
374 for (i = 0; i < ft_sim->analyses[which]->numParms; i++)
375 if (eq(ft_sim->analyses[which]->analysisParms[i].keyword, name) &&
376 (ft_sim->analyses[which]->analysisParms[i].dataType & IF_SET))
377 break;
378 if (i == ft_sim->analyses[which]->numParms) {
379 /* See if this is unsupported or obsolete. */
380 for (vv = unsupported; *vv; vv++)
381 if (eq(name, *vv)) {
382 fprintf(cp_err,
383 "Warning: option %s is currently unsupported.\n", name);
384 return;
385 }
386 for (vv = obsolete; *vv; vv++)
387 if (eq(name, *vv)) {
388 fprintf(cp_err,
389 "Warning: option %s is obsolete.\n", name);
390 return;
391 }
392 return;
393 }
394
395 switch (ft_sim->analyses[which]->analysisParms[i].dataType & IF_VARTYPES) {
396 case IF_REAL:
397 if (type == VT_REAL)
398 pval.rValue = *((double *) value);
399 else if (type == VT_NUM)
400 pval.rValue = *((int *) value);
401 else
402 goto badtype;
403 break;
404 case IF_INTEGER:
405 if (type == VT_NUM)
406 pval.iValue = *((int *) value);
407 else if (type == VT_REAL)
408 pval.iValue = *((double *) value);
409 else
410 goto badtype;
411 break;
412 case IF_STRING:
413 if (type == VT_STRING)
414 pval.sValue = copy(value);
415 else
416 goto badtype;
417 break;
418 case IF_FLAG:
419 /* Do nothing. */
420 pval.iValue = 1;
421 break;
422 default:
423 fprintf(cp_err,
424 "if_option: Internal Error: bad option type %d.\n",
425 ft_sim->analyses[which]->analysisParms[i].dataType);
426 }
427
428 if ((err = (*(ft_sim->setAnalysisParm))(cc, (GENERIC *)ft_curckt->ci_curOpt,
429 ft_sim->analyses[which]->analysisParms[i].id, &pval,
430 (IFvalue *)NULL)) != OK)
431 ft_sperror(err, "setAnalysisParm(options)");
432
433 return;
434
435 badtype:
436 fprintf(cp_err, "Error: bad type given for option %s --\n", name);
437 fprintf(cp_err, "\ttype given was ");
438 switch (type) {
439 case VT_BOOL: fputs("boolean", cp_err); break;
440 case VT_NUM: fputs("integer", cp_err); break;
441 case VT_REAL: fputs("real", cp_err); break;
442 case VT_STRING: fputs("string", cp_err); break;
443 case VT_LIST: fputs("list", cp_err); break;
444 default: fputs("something strange", cp_err); break;
445 }
446 fprintf(cp_err, ", type expected was ");
447 switch(ft_sim->analyses[which]->analysisParms[i].dataType & IF_VARTYPES) {
448 case IF_REAL: fputs("real.\n", cp_err); break;
449 case IF_INTEGER:fputs("integer.\n", cp_err); break;
450 case IF_STRING: fputs("string.\n", cp_err); break;
451 case IF_FLAG: fputs("flag.\n", cp_err); break;
452 default: fputs("something strange.\n", cp_err); break;
453 }
454 if (type == VT_BOOL)
455 fputs("\t(Note that you must use an = to separate option name and value.)\n",
456 cp_err);
457 return;
458 }
459
460
461 void
if_cktfree(ckt,tab)462 if_cktfree(ckt, tab)
463
464 char *ckt;
465 char *tab;
466 {
467 GENERIC *cc = (GENERIC *) ckt;
468
469 (*(ft_sim->deleteCircuit))(cc);
470 INPtabEnd((INPtables *) tab);
471 return;
472 }
473
474
475 void
if_cktclear()476 if_cktclear()
477
478 /* Delete the current circuit.
479 * This blows away all the peripheral stuff, unlike if_cktfree() which only
480 * frees the ckt structure and input tables.
481 */
482 {
483 struct circ *cc;
484
485 if (!ft_curckt) return;
486 tfree(ft_curckt->ci_name);
487 inp_deckfree(ft_curckt->ci_deck);
488 inp_deckfree(ft_curckt->ci_options);
489 wl_free(ft_curckt->ci_commands);
490
491 (*(ft_sim->deleteTask))(ft_curckt->ci_ckt,ft_curckt->ci_specTask);
492 (*(ft_sim->deleteTask))(ft_curckt->ci_ckt,ft_curckt->ci_defTask);
493 va_free(ft_curckt->ci_vars);
494
495 tfree(ft_curckt->ci_filename);
496
497 if (ft_curckt->ci_contblk) {
498 for (cc = ft_circuits; cc; cc = cc->ci_next) {
499 if (cc == ft_curckt)
500 continue;
501 if (cc->ci_contblk && eq(cc->ci_contblk,ft_curckt->ci_contblk))
502 break;
503 }
504 if (!cc) {
505 if (prefix("#_",ft_curckt->ci_contblk)) {
506 cp_freeblock(ft_curckt->ci_contblk);
507 ft_curckt->ci_contblk[1] = '#';
508 cp_freeblock(ft_curckt->ci_contblk);
509 }
510 }
511 txfree(ft_curckt->ci_contblk);
512 }
513
514 if_cktfree(ft_curckt->ci_ckt, (char*)ft_curckt->ci_symtab);
515 ft_curckt->ci_devices = cp_kwswitch(CT_DEVNAMES,(char *)NULL);
516 ft_curckt->ci_nodes = cp_kwswitch(CT_NODENAMES,(char *)NULL);
517 cp_ccfreetrie(ft_curckt->ci_devices);
518 cp_ccfreetrie(ft_curckt->ci_nodes);
519
520 if (ft_curckt == ft_circuits) {
521 tfree(ft_curckt);
522 ft_circuits = ft_curckt = ft_circuits->ci_next;
523 }
524 else {
525 for (cc = ft_circuits; cc; cc = cc->ci_next)
526 if (cc->ci_next == ft_curckt)
527 break;
528
529 if (!cc) {
530 fprintf(cp_err,"Internal Error: cktfree -- not in list\n");
531 goto xxx;
532 }
533 cc->ci_next = ft_curckt->ci_next;
534 tfree(ft_curckt);
535 ft_curckt = cc;
536 }
537 xxx:
538 if (ft_curckt) {
539 (void) cp_kwswitch(CT_DEVNAMES, ft_curckt->ci_devices);
540 (void) cp_kwswitch(CT_NODENAMES, ft_curckt->ci_nodes);
541 }
542 }
543
544 /* Return a string describing an error code. */
545
546
547 /* BLOW THIS AWAY.... */
548
549 char *
if_errstring(code)550 if_errstring(code)
551
552 int code;
553 {
554 return (INPerror(code));
555 }
556
557
558 struct variable *
spif_getparam(ckt,name,param,ind,keyword)559 spif_getparam(ckt, name, param, ind, keyword)
560
561 /* Get a parameter value from the circuit. If name is left unspecified,
562 * we want a circuit parameter. If keywords is not null, a list of
563 * matching keywords is built.
564 */
565 char *ckt;
566 char **name;
567 char *param;
568 int ind;
569 wordlist **keyword;
570 {
571 struct variable *vv, *tv;
572 IFvalue *pv;
573 IFparm *opt;
574 int typecode, i, num;
575 GENinstance *dev = (GENinstance *)NULL;
576 GENmodel *mod = (GENmodel *)NULL;
577 IFdevice *device;
578 wordlist *ww;
579
580 if (param && eq(param, "all")) {
581 INPinsert(name,(INPtables *)ft_curckt->ci_symtab);
582 typecode = finddev(ckt, *name,(GENERIC**) &dev,(GENERIC**) &mod);
583 if (typecode == -1) {
584 fprintf(cp_err,
585 "Error: no such device or model name %s\n", *name);
586 return (NULL);
587 }
588 device = ft_sim->devices[typecode];
589 vv = tv = (struct variable*)NULL;
590 if (dev) {
591 num = *(device->numInstanceParms);
592 opt = device->instanceParms;
593 }
594 else {
595 num = *(device->numModelParms);
596 opt = device->modelParms;
597 }
598 if (opt) {
599 for (i = 0; i < num; i++, opt++) {
600 if (!(opt->dataType & IF_ASK)) continue;
601 pv = doask(ckt, typecode, dev, mod, opt, ind);
602 if (pv) {
603 if (tv) {
604 if (keyword) {
605 ww->wl_next = alloc(struct wordlist);
606 ww = ww->wl_next;
607 ww->wl_word = copy(opt->keyword);
608 }
609 tv->va_next = parmtovar(pv,opt);
610 tv = tv->va_next;
611 }
612 else {
613 if (keyword) {
614 *keyword = ww = alloc(struct wordlist);
615 ww->wl_word = copy(opt->keyword);
616 }
617 vv = tv = parmtovar(pv,opt);
618 }
619 }
620 else
621 fprintf(cp_err,
622 "Internal Error: no parameter '%s' on device '%s'\n",
623 device->instanceParms[i].keyword,
624 device->name);
625 }
626 return (vv);
627 }
628 else
629 return (NULL);
630 }
631 else if (param) {
632 INPinsert(name,(INPtables *)ft_curckt->ci_symtab);
633 typecode = finddev(ckt, *name, (GENERIC**)&dev, (GENERIC**)&mod);
634 if (typecode == -1) {
635 fprintf(cp_err,
636 "Error: no such device or model name %s\n", *name);
637 return (NULL);
638 }
639 device = ft_sim->devices[typecode];
640 opt = parmlookup(device, dev, mod, param);
641 if (!opt) {
642 fprintf(cp_err, "Error: no such parameter %s.\n", param);
643 return (NULL);
644 }
645 pv = doask(ckt, typecode, dev, mod, opt, ind);
646 if (pv) {
647 if (keyword) {
648 *keyword = alloc(struct wordlist);
649 (*keyword)->wl_word = copy(opt->keyword);
650 }
651 vv = parmtovar(pv, opt);
652 }
653 return (vv);
654 }
655 else
656 return (if_getstat(ckt, *name, keyword));
657 }
658
659
660 /* ARGSUSED */
661 void
if_setparam(ckt,name,param,val)662 if_setparam(ckt, name, param, val)
663
664 char *ckt;
665 char *name;
666 char *param;
667 struct variable *val;
668 {
669 }
670
671
672 static struct variable *
parmtovar(pv,opt)673 parmtovar(pv, opt)
674
675 IFvalue *pv;
676 IFparm *opt;
677 {
678 struct variable *tv, *vv = alloc(struct variable);
679 int i = 0;
680
681 switch (opt->dataType & IF_VARTYPES) {
682 case IF_INTEGER:
683 vv->va_type = VT_NUM;
684 vv->va_num = pv->iValue;
685 break;
686 case IF_REAL:
687 case IF_COMPLEX:
688 vv->va_type = VT_REAL;
689 vv->va_real = pv->rValue;
690 break;
691 case IF_STRING:
692 vv->va_type = VT_STRING;
693 vv->va_string = copy(pv->sValue);
694 break;
695 case IF_INSTANCE:
696 vv->va_type = VT_STRING;
697 vv->va_string = copy((char*)pv->uValue);
698 break;
699 case IF_FLAG:
700 vv->va_type = VT_BOOL;
701 vv->va_bool = pv->iValue ? true : false;
702 break;
703 case IF_REALVEC:
704 vv->va_type = VT_LIST;
705 tv = NULL;
706 for (i = 0; i < pv->v.numValue; i++) {
707 if (!tv)
708 tv = vv->va_vlist = alloc(struct variable);
709 else {
710 tv->va_next = alloc(struct variable);
711 tv = tv->va_next;
712 }
713 tv->va_type = VT_REAL;
714 tv->va_real = (pv->v.vec.rVec)[i];
715 }
716 break;
717 case IF_PARSETREE:
718 vv->va_type = VT_STRING;
719 vv->va_string = NULL;
720 if (pv->tValue)
721 vv->va_string = copy(pv->tValue->line);
722 break;
723 default:
724 fprintf(cp_err,
725 "parmtovar: Internal Error: bad PARM type %d.\n",
726 opt->dataType);
727 tfree(vv);
728 return (NULL);
729 }
730
731 /* It's not clear whether we want the keyword or the desc here... */
732 vv->va_name = copy(opt->description);
733 return (vv);
734 }
735
736
737 static IFparm *
parmlookup(device,dev,mod,param)738 parmlookup(device, dev, mod, param)
739
740 /* Extract the IFparm structure from the device. A match is assumed if
741 * param is a case insensitive match of the IFdevice keyword. If inptr
742 * is not NULL, the devices are checked first. *inptr is NULLed if
743 * no matching device is found, and a model is returned if there is a
744 * match.
745 */
746 IFdevice *device;
747 GENinstance *dev;
748 GENmodel *mod;
749 char *param;
750 {
751 int i;
752
753 if (dev) {
754 for (i = 0; i < *(device->numInstanceParms); i++) {
755 if ((device->instanceParms[i].dataType & IF_ASK) &&
756 cieq(param,device->instanceParms[i].keyword))
757 return (&device->instanceParms[i]);
758 }
759 }
760 else if (mod) {
761 if (device->modelParms == NULL)
762 return (NULL);
763 for (i = 0; i < *(device->numModelParms); i++)
764 if ((device->modelParms[i].dataType & IF_ASK) &&
765 cieq(param,device->modelParms[i].keyword))
766 return (&device->modelParms[i]);
767 }
768 return (NULL);
769 }
770
771
772 /* ARGSUSED */
773 static IFvalue *
doask(ckt,typecode,dev,mod,opt,ind)774 doask(ckt, typecode, dev, mod, opt, ind)
775
776 /* Perform the CKTask call. We have both 'fast' and 'modfast', so the other
777 * parameters aren't necessary.
778 */
779 char *ckt;
780 GENinstance *dev;
781 GENmodel *mod;
782 IFparm *opt;
783 int ind;
784 {
785 static IFvalue pv;
786 int err;
787
788 pv.rValue = 0.0;
789 pv.iValue = ind; /* Sometimes this will be junk and ignored... */
790
791 if (dev)
792 err = (*(ft_sim->askInstanceQuest))((GENERIC *)ckt, (GENERIC *)dev,
793 opt->id, &pv, (IFvalue *)NULL);
794 else
795 err = (*(ft_sim->askModelQuest))((GENERIC*)ckt, (GENERIC*) mod,
796 opt->id, &pv, (IFvalue *)NULL);
797 if (err != OK) {
798 ft_sperror(err, "doask");
799 return (NULL);
800 }
801
802 return (&pv);
803 }
804
805
806 static int
finddev(ck,name,devptr,modptr)807 finddev(ck, name, devptr, modptr)
808
809 /* Get pointers to a device, its model, and its type number given the name.
810 * If there is no such device, try to find a model with that name.
811 */
812 char *ck;
813 char *name;
814 GENERIC **devptr;
815 GENERIC **modptr;
816 {
817 int err;
818 int type = -1;
819
820 err =
821 (*(ft_sim->findInstance))((GENERIC *)ck,&type,devptr,name,NULL,NULL);
822 if (err == OK)
823 return (type);
824
825 type = -1;
826 *devptr = (GENERIC *)NULL;
827
828 err = (*(ft_sim->findModel))((GENERIC *)ck,&type,modptr,name);
829 if (err == OK)
830 return(type);
831
832 *modptr = (GENERIC *)NULL;
833 return (-1);
834 }
835
836
837 /* Extract the node and device names from the line and add them to the command
838 * completion structure. This is probably not a good thing to do if it
839 * takes too much time.
840 */
841
842 void
if_setndnames(line)843 if_setndnames(line)
844
845 char *line;
846 {
847 int i;
848 char buf[BSIZE_SP];
849
850 while (isspace(*line))
851 line++;
852
853 if (!*line || (*line == '*'))
854 return;
855 if (*line == '.') {
856 line++;
857 if (prefix("model",line)) {
858 copytok(buf,&line);
859 copytok(buf,&line);
860 cp_addkword(CT_DEVNAMES, buf);
861 }
862 return;
863 }
864 copytok(buf,&line);
865 cp_addkword(CT_DEVNAMES, buf);
866
867 /* inefficient and not very useful */
868 /*
869 if (!(i = inp_numnodes(*buf)))
870 return;
871 if ((*buf == 'q') || (*buf == 'Q'))
872 i = 3;
873
874 while (i-- > 0) {
875 if (copytok(buf,&line))
876 cp_addkword(CT_NODENAMES, buf);
877 }
878 return;
879 */
880 }
881
882
883 struct variable *
if_getstat(ckt,name,keyword)884 if_getstat(ckt, name, keyword)
885
886 /* Get the statistic called 'name'. If this is NULL get all statistics
887 * available. If keyword is not null, it returns a wordlist of actual
888 * keyword matches. A match is assumed if name is a case insensitive
889 * prefix of the keyword.
890 */
891 char *ckt;
892 char *name;
893 wordlist **keyword;
894 {
895 int i;
896 struct variable *v, *vars;
897 IFvalue parm;
898 int which;
899 wordlist *ww;
900
901 which = get_anal("options");
902 if (which == -1) {
903 fprintf(cp_err,"Warning: statistics unsupported\n");
904 return(NULL);
905 }
906
907 if (name) {
908 for (i = 0; i < ft_sim->analyses[which]->numParms; i++)
909 if (ciprefix(name,
910 ft_sim->analyses[which]->analysisParms[i].keyword))
911 break;
912 if (i == ft_sim->analyses[which]->numParms)
913 return (NULL);
914 if ((*(ft_sim->askAnalysisQuest))(ckt, ft_curckt->ci_curTask,
915 ft_sim->analyses[which]->analysisParms[i].id, &parm,
916 (IFvalue *)NULL) == -1) {
917 goto error;
918 }
919 if (keyword) {
920 *keyword = alloc(struct wordlist);
921 (*keyword)->wl_word = copy(
922 ft_sim->analyses[which]->analysisParms[i].keyword);
923 }
924 return (parmtovar(&parm,
925 &(ft_sim->analyses[which]->analysisParms[i])));
926 }
927 else {
928 for (i = 0, vars = v = NULL;
929 i < ft_sim->analyses[which]->numParms; i++) {
930 if (!(ft_sim->analyses[which]->analysisParms[i].dataType&IF_ASK)) {
931 continue;
932 }
933 if ((*(ft_sim->askAnalysisQuest))(ckt, ft_curckt->ci_curTask,
934 ft_sim->analyses[which]->analysisParms[i].id,
935 &parm, (IFvalue *)NULL) == -1) {
936 goto error;
937 }
938 if (v) {
939 if (keyword) {
940 ww->wl_next = alloc(struct wordlist);
941 ww = ww->wl_next;
942 ww->wl_word = copy(
943 ft_sim->analyses[which]->analysisParms[i].keyword);
944 }
945 v->va_next = parmtovar(&parm,
946 &(ft_sim->analyses[which]->analysisParms[i]));
947 v = v->va_next;
948 }
949 else {
950 if (keyword) {
951 *keyword = ww = alloc(struct wordlist);
952 ww->wl_word = copy(
953 ft_sim->analyses[which]->analysisParms[i].keyword);
954 }
955 vars = v = parmtovar(&parm,
956 &(ft_sim->analyses[which]->analysisParms[i]));
957 }
958 }
959 return (vars);
960 }
961 error:
962 fprintf(cp_err,"if_getstat: Internal Error: can't get %s.\n",name);
963 return NULL;
964 }
965
966
967 wordlist *
GetAnalysisFromDeck()968 GetAnalysisFromDeck()
969 {
970 wordlist *tl1 = NULL;
971 int numjobs;
972
973 if (!(*ft_sim->findAnalysis)(ft_curckt->ci_ckt,&numjobs,
974 (GENERIC**)NULL,(IFuid)NULL,ft_curckt->ci_defTask,(IFuid)NULL)) {
975
976 if (numjobs != 1)
977 return (NULL);
978
979 /* one analysis specified in file */
980 ft_curckt->ci_curTask = ft_curckt->ci_defTask;
981 ft_curckt->ci_curOpt = ft_curckt->ci_defOpt;
982 tl1 = alloc(wordlist);
983 tl1->wl_word = copy("run");
984 }
985 return (tl1);
986 }
987
988
989 int
InProgress()990 InProgress()
991 {
992 return (ft_curckt && ft_curckt->ci_inprogress);
993 }
994
995
996 int
IsIplot()997 IsIplot()
998 {
999 struct dbcomm *d;
1000 extern struct dbcomm *dbiplot;
1001
1002 for (d = dbiplot; d; d = d->db_next) {
1003 if (d->db_type == DB_IPLOT) return (true);
1004 if (d->db_type == DB_IPLOTALL) return (true);
1005 }
1006 return (false);
1007 }
1008