1 /**********
2 Copyright 1990 Regents of the University of California.  All rights reserved.
3 Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
4 Modified: 2000 AlansFixes
5 **********/
6 
7 /*
8  * Interface routines. These are specific to spice. The only changes to FTE
9  * that should be needed to make FTE work with a different simulator is
10  * to rewrite this file. What each routine is expected to do can be
11  * found in the programmer's manual. This file should be the only one
12  * that includes ngspice.header files.
13  */
14 
15 /*CDHW Notes:
16 
17 I have never really understood the way Berkeley intended the six pointers
18 to default values (ci_defOpt/Task  ci_specOpt/Task ci_curOpt/Task) to work,
19 as there only see to be two data blocks to point at, or I've missed something
20 clever elsewhere.
21 
22 Anyway, in the original 3f4 the interactive command 'set temp = 10'
23 set temp for its current task and clobbered the default values as a side
24 effect. When an interactive is run it created specTask using the spice
25 application default values, not the circuit defaults affected
26 by 'set temp = 10'.
27 
28 The fix involves two changes
29 
30   1. Make 'set temp = 10' change the values in the 'default' block, not whatever
31      the 'current' pointer happens to be pointing at (which is usually the
32      default block except when one interactive is run immediately
33 after another).
34 
35   2. Hack CKTnewTask() so that it looks to see whether it is creating
36 a 'special'
37      task, in which case it copies the values from
38 ft_curckt->ci_defTask providing
39      everything looks sane, otherwise it uses the hard-coded
40 'application defaults'.
41 
42 These are fairly minor changes, and as they don't change the data structures
43 they should be fairly 'safe'. However, ...
44 
45 
46 CDHW*/
47 
48 #include "ngspice/ngspice.h"
49 #include "ngspice/cktdefs.h"
50 #include "ngspice/cpdefs.h"
51 #include "ngspice/tskdefs.h" /* Is really needed ? */
52 #include "ngspice/ftedefs.h"
53 #include "ngspice/fteinp.h"
54 #include "ngspice/inpdefs.h"
55 #include "ngspice/iferrmsg.h"
56 #include "ngspice/ifsim.h"
57 
58 #include "circuits.h"
59 #include "spiceif.h"
60 #include "variable.h"
61 
62 
63 #ifdef XSPICE
64 #include "ngspice/evt.h"
65 #include "ngspice/enh.h"
66 /* gtri - add - wbk - 11/9/90 - include MIF function prototypes */
67 #include "ngspice/mifproto.h"
68 /* gtri - end - wbk - 11/9/90 */
69 
70 /* gtri - evt - wbk - 5/20/91 - Add stuff for user-defined nodes */
71 #include "ngspice/evtproto.h"
72 #include "ngspice/evtudn.h"
73 /* gtri - end - wbk - 5/20/91 - Add stuff for user-defined nodes */
74 #include "ngspice/mif.h"
75 #endif
76 
77 extern INPmodel *modtab;
78 
79 static struct variable *parmtovar(IFvalue *pv, IFparm *opt);
80 static IFparm *parmlookup(IFdevice *dev, GENinstance **inptr, char *param,
81                            int do_model, int inout);
82 static IFvalue *doask(CKTcircuit *ckt, int typecode, GENinstance *dev, GENmodel *mod,
83                        IFparm *opt, int ind);
84 static int doset(CKTcircuit *ckt, int typecode, GENinstance *dev, GENmodel *mod,
85                  IFparm *opt, struct dvec *val);
86 static int finddev(CKTcircuit *ckt, char *name, GENinstance **devptr, GENmodel **modptr);
87 
88 /* espice fix integration */
89 static int finddev_special(CKTcircuit *ckt, char *name, GENinstance **devptr, GENmodel **modptr, int *device_or_model);
90 
91 
92 /* Input a single deck, and return a pointer to the circuit. */
93 
94 CKTcircuit *
if_inpdeck(struct card * deck,INPtables ** tab)95 if_inpdeck(struct card *deck, INPtables **tab)
96 {
97     CKTcircuit *ckt;
98     int err, i;
99     struct card *ll;
100     IFuid taskUid;
101     IFuid optUid;
102     int which = -1;
103 
104     for (i = 0, ll = deck; ll; ll = ll->nextcard)
105         i++;
106     *tab = INPtabInit(i);
107     ft_curckt->ci_symtab = *tab;
108 
109     err = ft_sim->newCircuit (&ckt);
110     if (err != OK) {
111         ft_sperror(err, "CKTinit");
112         return (NULL);
113     }
114 
115     /*CDHW Create a task DDD with a new UID. ci_defTask will point to it CDHW*/
116 
117     err = IFnewUid(ckt, &taskUid, NULL, "default", UID_TASK, NULL);
118     if (err) {
119         ft_sperror(err, "newUid");
120         return (NULL);
121     }
122 
123 #if (0)
124     err = ft_sim->newTask (ckt, &(ft_curckt->ci_defTask), taskUid);
125 #else /*CDHW*/
126     err = ft_sim->newTask (ckt, &(ft_curckt->ci_defTask), taskUid, NULL);
127 #endif
128     if (err) {
129         ft_sperror(err, "newTask");
130         return (NULL);
131     }
132 
133     /*CDHW which options available for this simulator? CDHW*/
134 
135     which = ft_find_analysis("options");
136 
137     if (which != -1) {
138         err = IFnewUid(ckt, &optUid, NULL, "options", UID_ANALYSIS, NULL);
139         if (err) {
140             ft_sperror(err, "newUid");
141             return (NULL);
142         }
143 
144         err = ft_sim->newAnalysis (ft_curckt->ci_ckt, which, optUid,
145                                    &(ft_curckt->ci_defOpt),
146                                    ft_curckt->ci_defTask);
147 
148         /*CDHW ci_defTask and ci_defOpt point to parameters DDD CDHW*/
149 
150         if (err) {
151             ft_sperror(err, "createOptions");
152             return (NULL);
153         }
154 
155         ft_curckt->ci_curOpt  = ft_curckt->ci_defOpt;
156         /*CDHW ci_curOpt and ci_defOpt point to DDD CDHW*/
157     }
158 
159     ft_curckt->ci_curTask = ft_curckt->ci_defTask;
160 
161     /* Parse the .model lines. Enter the model into the global model table modtab. */
162     modtab = NULL;
163     INPpas1(ckt, deck->nextcard, *tab);
164     /* store the new model table in the current circuit */
165     ft_curckt->ci_modtab = modtab;
166 
167     /* Scan through the instance lines and parse the circuit. */
168     INPpas2(ckt, deck->nextcard, *tab, ft_curckt->ci_defTask);
169 
170     /* If option cshunt is given, add capacitors to each voltage node */
171     INPpas4(ckt, *tab);
172 
173     /* Fill in .NODESET and .IC data.
174      * nodeset/ic of non-existent nodes is rejected.  */
175     INPpas3(ckt, deck->nextcard,
176             *tab, ft_curckt->ci_defTask, ft_sim->nodeParms,
177             ft_sim->numNodeParms);
178 
179 #ifdef XSPICE
180     /* gtri - begin - wbk - 6/6/91 - Finish initialization of event driven structures */
181     err = EVTinit(ckt);
182     if (err) {
183         ft_sperror(err, "EVTinit");
184         return (NULL);
185     }
186     /* gtri - end - wbk - 6/6/91 - Finish initialization of event driven structures */
187 #endif
188 
189     return (ckt);
190 }
191 
192 
193 /* Do a run of the circuit, of the given type. Type "resume" is
194  * special -- it means to resume whatever simulation that was in
195  * progress. The return value of this routine is 0 if the exit was ok,
196  * and 1 if there was a reason to interrupt the circuit (interrupt
197  * typed at the keyboard, error in the simulation, etc). args should
198  * be the entire command line, e.g. "tran 1 10 20 uic" */
199 int
if_run(CKTcircuit * ckt,char * what,wordlist * args,INPtables * tab)200 if_run(CKTcircuit *ckt, char *what, wordlist *args, INPtables *tab)
201 {
202     int err;
203     struct card deck;
204     char buf[BSIZE_SP];
205     int which = -1;
206     IFuid specUid, optUid;
207     char *s;
208 
209 
210     /* First parse the line... */
211     /*CDHW Look for an interactive task CDHW*/
212     if (eq(what, "tran") ||
213         eq(what, "ac") ||
214         eq(what, "dc") ||
215         eq(what, "op") ||
216         eq(what, "pz") ||
217         eq(what, "disto") ||
218         eq(what, "adjsen") ||
219         eq(what, "sens") ||
220         eq(what, "tf") ||
221         eq(what, "noise")
222 #ifdef WITH_PSS
223         /* SP: Steady State Analysis */
224         || eq(what, "pss")
225         /* SP */
226 #endif
227         )
228     {
229         s = wl_flatten(args); /* va: tfree char's tmalloc'ed in wl_flatten */
230         (void) sprintf(buf, ".%s", s);
231         tfree(s);
232         deck.nextcard = deck.actualLine = NULL;
233         deck.error = NULL;
234         deck.linenum = 0;
235         deck.line = buf;
236 
237         /*CDHW Delete any previous special task CDHW*/
238 
239         if (ft_curckt->ci_specTask) {
240             if (ft_curckt->ci_specTask == ft_curckt->ci_defTask)   /*CDHW*/
241                 printf("Oh dear...something bad has happened to the options.\n");
242 
243             err = ft_sim->deleteTask (ft_curckt->ci_ckt, ft_curckt->ci_specTask);
244             if (err) {
245                 ft_sperror(err, "deleteTask");
246                 return (2);
247             }
248 
249             ft_curckt->ci_specTask = NULL;
250             ft_curckt->ci_specOpt  = NULL; /*CDHW*/
251         }
252         /*CDHW Create an interactive task AAA with a new UID.
253           ci_specTask will point to it CDHW*/
254 
255         err = IFnewUid(ft_curckt->ci_ckt, &specUid, NULL, "special", UID_TASK, NULL);
256         if (err) {
257             ft_sperror(err, "newUid");
258             return (2);
259         }
260 #if (0)
261         err = ft_sim->newTask (ft_curckt->ci_ckt,
262                                &(ft_curckt->ci_specTask), specUid);
263 #else /*CDHW*/
264 
265         err = ft_sim->newTask (ft_curckt->ci_ckt,
266                                &(ft_curckt->ci_specTask),
267                                specUid, &(ft_curckt->ci_defTask));
268 #endif
269         if (err) {
270             ft_sperror(err, "newTask");
271             return (2);
272         }
273 
274         /*CDHW which options available for this simulator? CDHW*/
275 
276         which = ft_find_analysis("options");
277 
278         if (which != -1) { /*CDHW options are available CDHW*/
279             err = IFnewUid(ft_curckt->ci_ckt, &optUid, NULL, "options", UID_ANALYSIS, NULL);
280             if (err) {
281                 ft_sperror(err, "newUid");
282                 return (2);
283             }
284 
285             err = ft_sim->newAnalysis (ft_curckt->ci_ckt, which, optUid,
286                                        &(ft_curckt->ci_specOpt),
287                                        ft_curckt->ci_specTask);
288 
289             /*CDHW 'options' ci_specOpt points to AAA in this case CDHW*/
290 
291             if (err) {
292                 ft_sperror(err, "createOptions");
293                 return (2);
294             }
295 
296             ft_curckt->ci_curOpt  = ft_curckt->ci_specOpt;
297 
298             /*CDHW ci_specTask ci_specOpt and ci_curOpt all point to AAA CDHW*/
299 
300         }
301 
302         ft_curckt->ci_curTask = ft_curckt->ci_specTask;
303 
304         /*CDHW ci_curTask and ci_specTask point to the interactive task AAA CDHW*/
305 
306         INPpas2(ckt, &deck, tab, ft_curckt->ci_specTask);
307 
308         if (deck.error) {
309             fprintf(cp_err, "Warning: %s\n", deck.error);
310             return 2;
311         }
312     }
313 
314     /*CDHW
315     ** if the task is to 'run' the deck, change ci_curTask and
316     ** ci_curOpt to point to DDD
317     ** created by if_inpdeck(), otherwise they point to AAA.
318     CDHW*/
319 
320     if (eq(what, "run")) {
321         ft_curckt->ci_curTask = ft_curckt->ci_defTask;
322         ft_curckt->ci_curOpt = ft_curckt->ci_defOpt;
323     }
324 
325     /* -- Find out what we are supposed to do.              */
326 
327     if ((eq(what, "tran")) ||
328         (eq(what, "ac")) ||
329         (eq(what, "dc")) ||
330         (eq(what, "op")) ||
331         (eq(what, "pz")) ||
332         (eq(what, "disto")) ||
333         (eq(what, "noise")) ||
334         (eq(what, "adjsen")) ||
335         (eq(what, "sens")) ||
336         (eq(what, "tf")) ||
337 #ifdef WITH_PSS
338         /* SP: Steady State Analysis */
339         (eq(what, "pss")) ||
340         /* SP */
341 #endif
342         (eq(what, "run")))
343     {
344         /*CDHW Run the analysis pointed to by ci_curTask CDHW*/
345 
346         ft_curckt->ci_curOpt = ft_curckt->ci_defOpt;
347         if ((err = ft_sim->doAnalyses (ckt, 1, ft_curckt->ci_curTask)) != OK) {
348             ft_sperror(err, "doAnalyses");
349             /* wrd_end(); */
350             if (err == E_PAUSE)
351                 return (1);
352             else
353                 return (2);
354         }
355     } else if (eq(what, "resume")) {
356         if ((err = ft_sim->doAnalyses (ckt, 0, ft_curckt->ci_curTask)) != OK) {
357             ft_sperror(err, "doAnalyses");
358             /* wrd_end(); */
359             if (err == E_PAUSE)
360                 return (1);
361             else
362                 return (2);
363         }
364     } else {
365         fprintf(cp_err, "if_run: Internal Error: bad run type %s\n", what);
366         return (2);
367     }
368 
369     return (0);
370 }
371 
372 
373 /* Set an option in the circuit. Arguments are option name, type, and
374  * value (the last a char *), suitable for casting to whatever needed...
375  */
376 
377 static char *unsupported[] = {
378     "itl3",
379     "itl5",
380     "lvltim",
381     "maxord",
382     "method",
383     NULL
384 };
385 
386 static char *obsolete[] = {
387     "limpts",
388     "limtim",
389     "lvlcod",
390     NULL
391 };
392 
393 
394 int
if_option(CKTcircuit * ckt,char * name,enum cp_types type,void * value)395 if_option(CKTcircuit *ckt, char *name, enum cp_types type, void *value)
396 {
397     IFvalue pval;
398     int err;
399     char **vv, *sfree = NULL;
400     int which = -1;
401     IFparm *if_parm;
402 
403     if (eq(name, "acct")) {
404         ft_acctprint = TRUE;
405         return 0;
406     } else if (eq(name, "noacct")) {
407         ft_noacctprint = TRUE;
408         return 0;
409     } else if (eq(name, "noinit")) {
410         ft_noinitprint = TRUE;
411         return 0;
412     } else if (eq(name, "norefvalue")) {
413         ft_norefprint = TRUE;
414         return 0;
415     } else if (eq(name, "list")) {
416         ft_listprint = TRUE;
417         return 0;
418     } else if (eq(name, "node")) {
419         ft_nodesprint = TRUE;
420         return 0;
421     } else if (eq(name, "opts")) {
422         ft_optsprint = TRUE;
423         return 0;
424     } else if (eq(name, "nopage")) {
425         ft_nopage = TRUE;
426         return 0;
427     } else if (eq(name, "nomod")) {
428         ft_nomod = TRUE;
429         return 0;
430     }
431 
432     which = ft_find_analysis("options");
433 
434     if (which == -1) {
435         fprintf(cp_err, "Warning:  .options line unsupported\n");
436         return 0;
437     }
438 
439     if_parm = ft_find_analysis_parm(which, name);
440 
441     if (!if_parm || !(if_parm->dataType & IF_SET)) {
442         /* See if this is unsupported or obsolete. */
443         for (vv = unsupported; *vv; vv++)
444             if (eq(name, *vv)) {
445                 fprintf(cp_err, "Warning: option %s is currently unsupported.\n", name);
446                 return 1;
447             }
448         for (vv = obsolete; *vv; vv++)
449             if (eq(name, *vv)) {
450                 fprintf(cp_err, "Warning: option %s is obsolete.\n", name);
451                 return 1;
452             }
453         return 0;
454     }
455 
456     switch (if_parm->dataType & IF_VARTYPES) {
457     case IF_REAL:
458         if (type == CP_REAL)
459             pval.rValue = *((double *) value);
460         else if (type == CP_NUM)
461             pval.rValue = *((int *) value);
462         else
463             goto badtype;
464         break;
465     case IF_INTEGER:
466         if (type == CP_NUM)
467             pval.iValue = *((int *) value);
468         else if (type == CP_REAL)
469             pval.iValue = (int)floor((*(double *)value) + 0.5);
470         else
471             goto badtype;
472         break;
473     case IF_STRING:
474         if (type == CP_STRING)
475             sfree = pval.sValue = copy((char*) value);
476         else
477             goto badtype;
478         break;
479     case IF_FLAG:
480         if (type == CP_BOOL)
481             pval.iValue = *((bool *) value) ? 1 : 0;
482         else if (type == CP_NUM) /* FIXME, shall we allow this ? */
483             pval.iValue = *((int *) value);
484         else
485             goto badtype;
486         break;
487     default:
488         fprintf(cp_err,
489                 "if_option: Internal Error: bad option type %d.\n",
490                 if_parm->dataType);
491     }
492 
493     if (!ckt) {
494         /* XXX No circuit loaded */
495         fprintf(cp_err, "Simulation parameter \"%s\" can't be set until\n",
496                 name);
497         fprintf(cp_err, "a circuit has been loaded.\n");
498         return 1;
499     }
500 
501 #if (0)
502     if ((err = ft_sim->setAnalysisParm (ckt, ft_curckt->ci_curOpt,
503                                         if_parm->id, &pval,
504                                         NULL)) != OK)
505         ft_sperror(err, "setAnalysisParm(options) ci_curOpt");
506 #else /*CDHW*/
507     if ((err = ft_sim->setAnalysisParm (ckt, ft_curckt->ci_defOpt,
508                                         if_parm->id, &pval,
509                                         NULL)) != OK)
510         ft_sperror(err, "setAnalysisParm(options) ci_curOpt");
511     tfree(sfree);
512     return 1;
513 #endif
514 
515 badtype:
516     fprintf(cp_err, "Error: bad type given for option %s --\n", name);
517     fprintf(cp_err, "\ttype given was ");
518     switch (type) {
519     case CP_BOOL:
520         fputs("boolean", cp_err);
521         break;
522     case CP_NUM:
523         fputs("integer", cp_err);
524         break;
525     case CP_REAL:
526         fputs("real", cp_err);
527         break;
528     case CP_STRING:
529         fputs("string", cp_err);
530         break;
531     case CP_LIST:
532         fputs("list", cp_err);
533         break;
534     default:
535         fputs("something strange", cp_err);
536         break;
537     }
538     fprintf(cp_err, ", type expected was ");
539     switch (if_parm->dataType & IF_VARTYPES) {
540     case IF_REAL:
541         fputs("real.\n", cp_err);
542         break;
543     case IF_INTEGER:
544         fputs("integer.\n", cp_err);
545         break;
546     case IF_STRING:
547         fputs("string.\n", cp_err);
548         break;
549     case IF_FLAG:
550         fputs("flag.\n", cp_err);
551         break;
552     default:
553         fputs("something strange.\n", cp_err);
554         break;
555     }
556 
557     if (type == CP_BOOL)
558         fputs("\t(Note that you must use an = to separate option name and value.)\n",
559               cp_err);
560     return 0;
561 }
562 
563 
564 void
if_dump(CKTcircuit * ckt,FILE * file)565 if_dump(CKTcircuit *ckt, FILE *file)
566 {
567     NG_IGNORE(ckt);
568 
569     fprintf(file, "diagnostic output dump unavailable.");
570 }
571 
572 
573 void
if_cktfree(CKTcircuit * ckt,INPtables * tab)574 if_cktfree(CKTcircuit *ckt, INPtables *tab)
575 {
576     ft_sim->deleteCircuit (ckt);
577     INPtabEnd(tab);
578 }
579 
580 
581 /* Return a string describing an error code. */
582 
583 /* BLOW THIS AWAY.... */
584 
585 char *
if_errstring(int code)586 if_errstring(int code)
587 {
588     return (INPerror(code));
589 }
590 
591 
592 /* Get pointers to a device, its model, and its type number given the name. If
593  * there is no such device, try to find a model with that name
594  * device_or_model says if we are referencing a device or a model.
595  *  finddev_special(ck, name, devptr, modptr, device_or_model):
596  *  Introduced to look for correct reference in expression like  print @BC107 [is]
597  * and find out  whether a model or a device parameter is referenced and properly
598  * call the spif_getparam_special (ckt, name, param, ind, do_model) function in
599  * vector.c - A. Roldan (espice).
600  */
601 static int
finddev_special(CKTcircuit * ckt,char * name,GENinstance ** devptr,GENmodel ** modptr,int * device_or_model)602 finddev_special(
603     CKTcircuit *ckt,
604     char *name,
605     GENinstance **devptr,
606     GENmodel **modptr,
607     int *device_or_model)
608 {
609     *devptr = ft_sim->findInstance (ckt, name);
610     if (*devptr) {
611         *device_or_model = 0;
612         return (*devptr)->GENmodPtr->GENmodType;
613     }
614 
615     *modptr = ft_sim->findModel (ckt, name);
616     if (*modptr) {
617         *device_or_model = 1;
618         return (*modptr)->GENmodType;
619     }
620 
621     *device_or_model = 2;
622     return (-1);
623 }
624 
625 
626 /* Get a parameter value from the circuit. If name is left unspecified,
627  * we want a circuit parameter. Now works both for devices and models.
628  * A.Roldan (espice)
629  */
630 struct variable *
spif_getparam_special(CKTcircuit * ckt,char ** name,char * param,int ind,int do_model)631 spif_getparam_special(CKTcircuit *ckt, char **name, char *param, int ind, int do_model)
632 {
633     struct variable *vv = NULL, *tv;
634     IFvalue *pv;
635     IFparm *opt;
636     int typecode, i, modelo_dispositivo;
637     GENinstance *dev = NULL;
638     GENmodel *mod = NULL;
639     IFdevice *device;
640 
641     NG_IGNORE(do_model);
642 
643     /* fprintf(cp_err, "Calling if_getparam(%s, %s)\n", *name, param); */
644 
645     if (!param || (param && eq(param, "all"))) {
646         INPretrieve(name, ft_curckt->ci_symtab);
647         typecode = finddev_special(ckt, *name, &dev, &mod, &modelo_dispositivo);
648         if (typecode == -1) {
649             fprintf(cp_err, "Error: no such device or model name %s\n", *name);
650             return (NULL);
651         }
652         device = ft_sim->devices[typecode];
653         if (!modelo_dispositivo) {
654             /* It is a device */
655             for (i = 0; i < *(device->numInstanceParms); i++) {
656                 opt = &device->instanceParms[i];
657                 if (opt->dataType & IF_REDUNDANT || !opt->description)
658                     continue;
659                 if (!(opt->dataType & IF_ASK))
660                     continue;
661                 pv = doask(ckt, typecode, dev, mod, opt, ind);
662                 if (pv) {
663                     tv = parmtovar(pv, opt);
664 
665                     /* With the following we pack the name and the acronym of the parameter */
666                     {
667                         char *x = tv->va_name;
668                         tv->va_name = tprintf("%s [%s]", tv->va_name, device->instanceParms[i].keyword);
669                         tfree(x);
670                     }
671                     if (vv)
672                         tv->va_next = vv;
673                     vv = tv;
674                 } else {
675                     fprintf(cp_err,
676                             "Internal Error: no parameter '%s' on device '%s'\n",
677                             device->instanceParms[i].keyword, device->name);
678                 }
679             }
680             return (vv);
681         } else { /* Is it a model or a device ? */
682             /* It is a model */
683             for (i = 0; i < *(device->numModelParms); i++) {
684                 opt = &device->modelParms[i];
685                 if (opt->dataType & IF_REDUNDANT || !opt->description)
686                     continue;
687 
688                 /* We check that the parameter is interesting and therefore is
689                  * implemented in the corresponding function ModelAsk. Originally
690                  * the argument of "if" was: || (opt->dataType & IF_STRING)) continue;
691                  * so, a model parameter defined like  OP("type",   MOS_SGT_MOD_TYPE,
692                  * IF_STRING, N-channel or P-channel MOS") would not be printed.
693                  */
694 
695                 /* if (!(opt->dataType & IF_ASK) || (opt->dataType & IF_UNINTERESTING) || (opt->dataType & IF_STRING)) continue; */
696                 if (!(opt->dataType & IF_ASK) || (opt->dataType & IF_UNINTERESTING))
697                     continue;
698                 pv = doask(ckt, typecode, dev, mod, opt, ind);
699                 if (pv) {
700                     tv = parmtovar(pv, opt);
701                     /* Inside parmtovar:
702                      * 1. tv->va_name = copy(opt->description);
703                      * 2. Copy the type of variable of IFparm into a variable (thus parm-to-var)
704                      * vv->va_type = opt->dataType
705                      * The long description of the parameter:
706                      * IFparm MOS_SGTmPTable[] = { // model parameters //
707                      * OP("type",   MOS_SGT_MOD_TYPE,  IF_STRING, "N-channel or P-channel MOS")
708                      * goes into tv->va_name to put braces around the parameter of the model
709                      * tv->va_name += device->modelParms[i].keyword;
710                      */
711                     {
712                         char *x = tv->va_name;
713                         tv->va_name = tprintf("%s [%s]", tv->va_name, device->modelParms[i].keyword);
714                         tfree(x);
715                     }
716                     /* tv->va_string = device->modelParms[i].keyword;   Put the name of the variable */
717                     if (vv)
718                         tv->va_next = vv;
719                     vv = tv;
720                 } else {
721                     fprintf(cp_err,
722                             "Internal Error: no parameter '%s' on device '%s'\n",
723                             device->modelParms[i].keyword, device->name);
724                 }
725             }
726             return (vv);
727         }
728     } else if (param) {
729         INPretrieve(name, ft_curckt->ci_symtab);
730         typecode = finddev_special(ckt, *name, &dev, &mod, &modelo_dispositivo);
731         if (typecode == -1) {
732             fprintf(cp_err, "Error: no such device or model name %s\n", *name);
733             return (NULL);
734         }
735         device = ft_sim->devices[typecode];
736         opt = parmlookup(device, &dev, param, modelo_dispositivo, 0);
737         if (!opt) {
738             fprintf(cp_err, "Error: no such parameter %s.\n", param);
739             return (NULL);
740         }
741         pv = doask(ckt, typecode, dev, mod, opt, ind);
742         if (pv)
743             vv = parmtovar(pv, opt);
744         return (vv);
745     } else {
746         return (if_getstat(ckt, *name));
747     }
748 }
749 
750 
751 /* Get a parameter value from the circuit. If name is left unspecified,
752  * we want a circuit parameter.
753  */
754 
755 struct variable *
spif_getparam(CKTcircuit * ckt,char ** name,char * param,int ind,int do_model)756 spif_getparam(CKTcircuit *ckt, char **name, char *param, int ind, int do_model)
757 {
758     struct variable *vv = NULL, *tv;
759     IFvalue *pv;
760     IFparm *opt;
761     int typecode, i;
762     GENinstance *dev = NULL;
763     GENmodel *mod = NULL;
764     IFdevice *device;
765 
766     /* fprintf(cp_err, "Calling if_getparam(%s, %s)\n", *name, param); */
767 
768     if (param && eq(param, "all")) {
769 
770         /* MW. My "special routine here" */
771         INPretrieve(name, ft_curckt->ci_symtab);
772 
773         typecode = finddev(ckt, *name, &dev, &mod);
774         if (typecode == -1) {
775             fprintf(cp_err,
776                     "Error: no such device or model name %s\n",
777                     *name);
778             return (NULL);
779         }
780         device = ft_sim->devices[typecode];
781         for (i = 0; i < *(device->numInstanceParms); i++) {
782             opt = &device->instanceParms[i];
783             if (opt->dataType & IF_REDUNDANT || !opt->description)
784                 continue;
785             if (!(opt->dataType & IF_ASK))
786                 continue;
787             pv = doask(ckt, typecode, dev, mod, opt, ind);
788             if (pv) {
789                 tv = parmtovar(pv, opt);
790                 if (vv)
791                     tv->va_next = vv;
792                 vv = tv;
793             } else {
794                 fprintf(cp_err,
795                         "Internal Error: no parameter '%s' on device '%s'\n",
796                         device->instanceParms[i].keyword,
797                         device->name);
798             }
799         }
800         return (vv);
801     } else if (param) {
802 
803         /* MW.  */
804         INPretrieve(name, ft_curckt->ci_symtab);
805         typecode = finddev(ckt, *name, &dev, &mod);
806         if (typecode == -1) {
807             fprintf(cp_err, "Error: no such device or model name %s\n", *name);
808             return (NULL);
809         }
810         device = ft_sim->devices[typecode];
811         opt = parmlookup(device, &dev, param, do_model, 0);
812         if (!opt) {
813             fprintf(cp_err, "Error: no such parameter %s.\n", param);
814             return (NULL);
815         }
816         pv = doask(ckt, typecode, dev, mod, opt, ind);
817         if (pv)
818             vv = parmtovar(pv, opt);
819         return (vv);
820     } else {
821         return (if_getstat(ckt, *name));
822     }
823 }
824 
825 
826 /* 9/26/03 PJB : function to allow setting model of device */
827 void
if_setparam_model(CKTcircuit * ckt,char ** name,char * val)828 if_setparam_model(CKTcircuit *ckt, char **name, char *val)
829 {
830     GENinstance *dev     = NULL;
831     GENinstance *prevDev = NULL;
832     GENmodel    *curMod  = NULL;
833     GENmodel    *newMod  = NULL;
834     INPmodel    *inpmod  = NULL;
835     GENinstance *iter;
836     GENmodel    *mods, *prevMod;
837     int         typecode;
838     char        *modname;
839 
840     /* retrieve device name from symbol table */
841     INPretrieve(name, ft_curckt->ci_symtab);
842     /* find the specified device */
843     typecode = finddev(ckt, *name, &dev, &curMod);
844     if (typecode == -1) {
845         fprintf(cp_err, "Error: no such device name %s\n", *name);
846         return;
847     }
848     curMod = dev->GENmodPtr;
849     modname = copy(dev->GENmodPtr->GENmodName);
850     modname = strtok(modname, "."); /* want only have the parent model name */
851     /*
852       retrieve the model from the global model table; also add the model to 'ckt'
853       and indicate model is being used
854     */
855     INPgetMod(ckt, modname, &inpmod, ft_curckt->ci_symtab);
856     /* check if using model binning -- pass in line since need 'l' and 'w' */
857     if (inpmod == NULL)
858         INPgetModBin(ckt, modname, &inpmod, ft_curckt->ci_symtab, val);
859     tfree(modname);
860     if (inpmod == NULL) {
861         fprintf(cp_err, "Error: no model available for %s.\n", val);
862         return;
863     }
864     newMod = inpmod->INPmodfast;
865 
866     /* see if new model name same as current model name */
867     if (newMod->GENmodName != curMod->GENmodName)
868         printf("Notice: model has changed from %s to %s.\n", curMod->GENmodName, newMod->GENmodName);
869     if (newMod->GENmodType != curMod->GENmodType) {
870         fprintf(cp_err, "Error: new model %s must be same type as current model.\n", val);
871         return;
872     }
873 
874     /* fix current model linked list */
875     prevDev = NULL;
876     for (iter = curMod->GENinstances; iter; iter = iter->GENnextInstance) {
877         if (iter->GENname == dev->GENname) {
878 
879             /* see if at beginning of linked list */
880             if (prevDev == NULL)
881                 curMod->GENinstances     = iter->GENnextInstance;
882             else
883                 prevDev->GENnextInstance = iter->GENnextInstance;
884 
885             /* update model for device */
886             dev->GENmodPtr       = newMod;
887             dev->GENnextInstance = newMod->GENinstances;
888             newMod->GENinstances = dev;
889             break;
890         }
891         prevDev = iter;
892     }
893     /* see if any devices remaining that reference current model */
894     if (curMod->GENinstances == NULL) {
895         prevMod = NULL;
896         for (mods = ckt->CKThead[typecode]; mods; mods = mods->GENnextModel) {
897             if (mods->GENmodName == curMod->GENmodName) {
898 
899                 /* see if at beginning of linked list */
900                 if (prevMod == NULL)
901                     ckt->CKThead[typecode] = mods->GENnextModel;
902                 else
903                     prevMod->GENnextModel  = mods->GENnextModel;
904 
905                 INPgetMod(ckt, mods->GENmodName, &inpmod, ft_curckt->ci_symtab);
906                 if (curMod != nghash_delete(ckt->MODnameHash, curMod->GENmodName))
907                     fprintf(stderr, "ERROR, ouch nasal daemons ...\n");
908                 GENmodelFree(mods);
909 
910                 inpmod->INPmodfast = NULL;
911                 break;
912             }
913             prevMod = mods;
914         }
915     }
916 }
917 
918 
919 void
if_setparam(CKTcircuit * ckt,char ** name,char * param,struct dvec * val,int do_model)920 if_setparam(CKTcircuit *ckt, char **name, char *param, struct dvec *val, int do_model)
921 {
922     IFparm *opt;
923     IFdevice *device;
924     GENmodel *mod = NULL;
925     GENinstance *dev = NULL;
926     int typecode;
927 
928     /* PN  */
929     INPretrieve(name, ft_curckt->ci_symtab);
930     typecode = finddev(ckt, *name, &dev, &mod);
931     if (typecode == -1) {
932         fprintf(cp_err, "Error: no such device or model name %s\n", *name);
933         return;
934     }
935     device = ft_sim->devices[typecode];
936     opt = parmlookup(device, &dev, param, do_model, 1);
937     if (!opt) {
938         if (param)
939             fprintf(cp_err, "Error: no such parameter %s.\n", param);
940         else
941             fprintf(cp_err, "Error: no default parameter.\n");
942         return;
943     }
944     if (do_model && !mod) {
945         mod = dev->GENmodPtr;
946         dev = NULL;
947     }
948     doset(ckt, typecode, dev, mod, opt, val);
949 
950     /* Call to CKTtemp(ckt) will be invoked here only by 'altermod' commands,
951        to set internal model parameters pParam of each instance for immediate use,
952        otherwise e.g. model->BSIM3vth0 will be set, but not pParam of any BSIM3 instance.
953        Call only if CKTtime > 0 to avoid conflict with previous 'reset' command.
954        May contain side effects because called from many places.  h_vogt 110101
955     */
956     if (do_model && (ckt->CKTtime > 0)) {
957         int error = 0;
958         error = CKTtemp(ckt);
959         if (error)
960             fprintf(stderr, "Error during changing a device model parameter!\n");
961         if (error)
962             controlled_exit(1);
963     }
964 }
965 
966 
967 static struct variable *
parmtovar(IFvalue * pv,IFparm * opt)968 parmtovar(IFvalue *pv, IFparm *opt)
969 {
970     /* It is not clear whether we want to name the variable
971      *   by `keyword' or by `description' */
972 
973     switch (opt->dataType & IF_VARTYPES) {
974     case IF_INTEGER:
975         return var_alloc_num(copy(opt->description), pv->iValue, NULL);
976     case IF_REAL:
977     case IF_COMPLEX:
978         return var_alloc_real(copy(opt->description), pv->rValue, NULL);
979     case IF_STRING:
980         return var_alloc_string(copy(opt->description), pv->sValue, NULL);
981     case IF_FLAG:
982         return var_alloc_bool(copy(opt->description), pv->iValue ? TRUE : FALSE, NULL);
983     case IF_REALVEC: {
984         struct variable *list = NULL;
985         int i;
986         for (i = pv->v.numValue; --i >= 0;)
987             list = var_alloc_real(NULL, pv->v.vec.rVec[i], list);
988         return var_alloc_vlist(copy(opt->description), list, NULL);
989         /* It is a linked list where the first node is a variable
990          * pointing to the different values of the variables.
991          *
992          * To access the values of the real variable vector must be
993          * vv->va_V.vV_real = valor node ppal that is of no use.
994          *
995          * In the case of Vin_sin 1 0 sin (0 2 2000)
996          * and of print @vin_sin[sin]
997          *
998          * vv->va_V.vV_list->va_V.vV_real = 2000
999          * vv->va_V.vV_list->va_next->va_V.vV_real = 2
1000          * vv->va_V.vV_list->va_next->va_next->va_V.vV_real = 0
1001          * So the list is starting from behind, but no problem
1002          * This works fine
1003          */
1004     }
1005     default:
1006         fprintf(cp_err,
1007                 "parmtovar: Internal Error: bad PARM type %d.\n",
1008                 opt->dataType);
1009         return (NULL);
1010     }
1011 }
1012 
1013 
1014 /* Extract the parameter (IFparm structure) from the device or device's model.
1015  * If do_mode is TRUE then look in the device's parameters
1016  * If do_mode is FALSE then look in the device model's parameters
1017  * If inout equals 1 then look only for parameters with the IF_SET type flag
1018  * if inout equals 0 then look only for parameters with the IF_ASK type flag
1019  */
1020 
1021 static IFparm *
parmlookup(IFdevice * dev,GENinstance ** inptr,char * param,int do_model,int inout)1022 parmlookup(IFdevice *dev, GENinstance **inptr, char *param, int do_model, int inout)
1023 {
1024     int i;
1025 
1026     NG_IGNORE(inptr);
1027 
1028     /* First try the device questions... */
1029     if (!do_model && dev->numInstanceParms) {
1030         for (i = 0; i < *(dev->numInstanceParms); i++) {
1031             if (!param && (dev->instanceParms[i].dataType & IF_PRINCIPAL))
1032                 return (&dev->instanceParms[i]);
1033             else if (!param)
1034                 continue;
1035             else if ((((dev->instanceParms[i].dataType & IF_SET) && inout == 1) ||
1036                       ((dev->instanceParms[i].dataType & IF_ASK) && inout == 0)) &&
1037                      cieq(dev->instanceParms[i].keyword, param))
1038             {
1039                 while ((dev->instanceParms[i].dataType & IF_REDUNDANT) && (i > 0))
1040                     i--;
1041                 return (&dev->instanceParms[i]);
1042             }
1043         }
1044         return NULL;
1045     }
1046 
1047     if (dev->numModelParms)
1048         for (i = 0; i < *(dev->numModelParms); i++)
1049             if ((((dev->modelParms[i].dataType & IF_SET) && inout == 1) ||
1050                  ((dev->modelParms[i].dataType & IF_ASK) && inout == 0)) &&
1051                 eq(dev->modelParms[i].keyword, param))
1052             {
1053                 while ((dev->modelParms[i].dataType & IF_REDUNDANT) && (i > 0))
1054                     i--;
1055                 return (&dev->modelParms[i]);
1056             }
1057 
1058     return (NULL);
1059 }
1060 
1061 
1062 /* Perform the CKTask call. We have both 'fast' and 'modfast', so the other
1063  * parameters aren't necessary.
1064  */
1065 
1066 static IFvalue *
doask(CKTcircuit * ckt,int typecode,GENinstance * dev,GENmodel * mod,IFparm * opt,int ind)1067 doask(CKTcircuit *ckt, int typecode, GENinstance *dev, GENmodel *mod, IFparm *opt, int ind)
1068 {
1069     static IFvalue pv;
1070     int err;
1071 
1072     NG_IGNORE(typecode);
1073 
1074     pv.iValue = ind;    /* Sometimes this will be junk and ignored... */
1075 
1076     /* fprintf(cp_err, "Calling doask(%d, %x, %x, %x)\n",
1077        typecode, dev, mod, opt); */
1078     if (dev)
1079         err = ft_sim->askInstanceQuest (ckt, dev, opt->id, &pv, NULL);
1080     else
1081         err = ft_sim->askModelQuest (ckt, mod, opt->id, &pv, NULL);
1082 
1083     if (err != OK) {
1084         ft_sperror(err, "if_getparam");
1085         return (NULL);
1086     }
1087 
1088     return (&pv);
1089 }
1090 
1091 
1092 /* Perform the CKTset call. We have both 'fast' and 'modfast', so the other
1093  * parameters aren't necessary.
1094  */
1095 
1096 static int
doset(CKTcircuit * ckt,int typecode,GENinstance * dev,GENmodel * mod,IFparm * opt,struct dvec * val)1097 doset(CKTcircuit *ckt, int typecode, GENinstance *dev, GENmodel *mod, IFparm *opt, struct dvec *val)
1098 {
1099     IFvalue nval;
1100     int err;
1101     int n;
1102     int *iptr;
1103     double *dptr;
1104     int i;
1105 
1106     NG_IGNORE(typecode);
1107 
1108     /* Count items */
1109     if (opt->dataType & IF_VECTOR) {
1110         n = nval.v.numValue = val->v_length;
1111 
1112         dptr = val->v_realdata;
1113         /* XXXX compdata!!! */
1114 
1115         switch (opt->dataType & (IF_VARTYPES & ~IF_VECTOR)) {
1116         case IF_FLAG:
1117         case IF_INTEGER:
1118             iptr = nval.v.vec.iVec = TMALLOC(int, n);
1119 
1120             for (i = 0; i < n; i++)
1121                 *iptr++ = (int)floor(*dptr++ + 0.5);
1122             break;
1123 
1124         case IF_REAL:
1125             nval.v.vec.rVec = val->v_realdata;
1126             break;
1127 
1128         default:
1129             fprintf(cp_err,
1130                     "Can't assign value to \"%s\" (unsupported vector type)\n",
1131                     opt->keyword);
1132             return E_UNSUPP;
1133         }
1134     } else {
1135         switch (opt->dataType & IF_VARTYPES) {
1136         case IF_FLAG:
1137         case IF_INTEGER:
1138             nval.iValue = (int)floor(*val->v_realdata + 0.5);
1139             break;
1140 
1141         case IF_REAL:
1142             /*kensmith don't blow up with NULL dereference*/
1143             if (!val->v_realdata) {
1144                 fprintf(cp_err, "Unable to determine the value\n");
1145                 return E_UNSUPP;
1146             }
1147 
1148             nval.rValue = *val->v_realdata;
1149             break;
1150 
1151         default:
1152             fprintf(cp_err,
1153                     "Can't assign value to \"%s\" (unsupported type)\n",
1154                     opt->keyword);
1155             return E_UNSUPP;
1156         }
1157     }
1158 
1159     /* fprintf(cp_err, "Calling doask(%d, %x, %x, %x)\n",
1160        typecode, dev, mod, opt); */
1161 
1162     if (dev)
1163         err = ft_sim->setInstanceParm (ckt, dev, opt->id, &nval, NULL);
1164     else
1165         err = ft_sim->setModelParm (ckt, mod, opt->id, &nval, NULL);
1166 
1167     return err;
1168 }
1169 
1170 
1171 /* Get pointers to a device, its model, and its type number given the name. If
1172  * there is no such device, try to find a model with that name.
1173  */
1174 
1175 static int
finddev(CKTcircuit * ckt,char * name,GENinstance ** devptr,GENmodel ** modptr)1176 finddev(CKTcircuit *ckt, char *name, GENinstance **devptr, GENmodel **modptr)
1177 {
1178     *devptr = ft_sim->findInstance (ckt, name);
1179     if (*devptr)
1180         return (*devptr)->GENmodPtr->GENmodType;
1181 
1182     *modptr = ft_sim->findModel (ckt, name);
1183     if (*modptr)
1184         return (*modptr)->GENmodType;
1185 
1186     return (-1);
1187 }
1188 
1189 
1190 /* get an analysis parameter by name instead of id */
1191 
1192 int
if_analQbyName(CKTcircuit * ckt,int which,JOB * anal,char * name,IFvalue * parm)1193 if_analQbyName(CKTcircuit *ckt, int which, JOB *anal, char *name, IFvalue *parm)
1194 {
1195     IFparm *if_parm = ft_find_analysis_parm(which, name);
1196 
1197     if (!if_parm)
1198         return (E_BADPARM);
1199 
1200     return (ft_sim->askAnalysisQuest (ckt, anal, if_parm->id, parm, NULL));
1201 }
1202 
1203 
1204 /* Get the parameters tstart, tstop, and tstep from the CKT struct. */
1205 
1206 /* BLOW THIS AWAY TOO */
1207 
1208 bool
if_tranparams(struct circ * ci,double * start,double * stop,double * step)1209 if_tranparams(struct circ *ci, double *start, double *stop, double *step)
1210 {
1211     IFvalue tmp;
1212     int err;
1213     int which = -1;
1214     JOB *anal;
1215     IFuid tranUid;
1216 
1217     if (!ci->ci_curTask)
1218         return (FALSE);
1219 
1220     which = ft_find_analysis("TRAN");
1221 
1222     if (which == -1)
1223         return (FALSE);
1224 
1225     err = IFnewUid(ci->ci_ckt, &tranUid, NULL, "Transient Analysis", UID_ANALYSIS, NULL);
1226     if (err != OK)
1227         return (FALSE);
1228 
1229     err = ft_sim->findAnalysis (ci->ci_ckt, &which, &anal, tranUid,
1230                                 ci->ci_curTask, NULL);
1231     if (err != OK)
1232         return (FALSE);
1233 
1234     err = if_analQbyName(ci->ci_ckt, which, anal, "tstart", &tmp);
1235     if (err != OK)
1236         return (FALSE);
1237 
1238     *start = tmp.rValue;
1239 
1240     err = if_analQbyName(ci->ci_ckt, which, anal, "tstop", &tmp);
1241     if (err != OK)
1242         return (FALSE);
1243 
1244     *stop = tmp.rValue;
1245 
1246     err = if_analQbyName(ci->ci_ckt, which, anal, "tstep", &tmp);
1247     if (err != OK)
1248         return (FALSE);
1249 
1250     *step = tmp.rValue;
1251     return (TRUE);
1252 }
1253 
1254 
1255 /* Get the statistic called 'name'.  If this is NULL get all statistics
1256  * available.
1257  */
1258 
1259 struct variable *
if_getstat(CKTcircuit * ckt,char * name)1260 if_getstat(CKTcircuit *ckt, char *name)
1261 {
1262     int         options_idx, i;
1263     IFanalysis *options;
1264     IFvalue     parm;
1265     IFparm     *if_parm;
1266 
1267     options_idx = ft_find_analysis("options");
1268 
1269     if (options_idx == -1) {
1270         fprintf(cp_err, "Warning:  statistics unsupported\n");
1271         return (NULL);
1272     }
1273 
1274     options = ft_sim->analyses[options_idx];
1275 
1276     if (name) {
1277 
1278         if_parm = ft_find_analysis_parm(options_idx, name);
1279 
1280         if (!if_parm)
1281             return (NULL);
1282 
1283         if (ft_sim->askAnalysisQuest (ckt,
1284                                       &(ft_curckt->ci_curTask->taskOptions),
1285                                       if_parm->id, &parm,
1286                                       NULL) == -1)
1287         {
1288             fprintf(cp_err, "if_getstat: Internal Error: can't get %s\n", name);
1289             return (NULL);
1290         }
1291 
1292         return (parmtovar(&parm, if_parm));
1293 
1294     } else {
1295 
1296         struct variable *vars = NULL, **v = &vars;
1297 
1298         for (i = 0; i < options->numParms; i++) {
1299 
1300             if_parm = &(options->analysisParms[i]);
1301 
1302             if (!(if_parm->dataType & IF_ASK))
1303                 continue;
1304 
1305             if (ft_sim->askAnalysisQuest (ckt,
1306                                           &(ft_curckt->ci_curTask->taskOptions),
1307                                           if_parm->id, &parm,
1308                                           NULL) == -1)
1309             {
1310                 fprintf(cp_err, "if_getstat: Internal Error: can't get a name\n");
1311                 return (NULL);
1312             }
1313 
1314             *v = parmtovar(&parm, if_parm);
1315             v = &((*v)->va_next);
1316         }
1317 
1318         return (vars);
1319     }
1320 }
1321 
1322 
1323 /* Some small updates to make it work, h_vogt, Feb. 2012
1324    Still very experimental !
1325    It is now possible to save a state during transient simulation,
1326    reload it later into a new ngspice run and resume simulation.
1327    XSPICE code models probably will not do.
1328    LTRA transmission line will not do.
1329    Many others are not tested.
1330 */
1331 
1332 #include "ngspice/cktdefs.h"
1333 #include "ngspice/trandefs.h"
1334 
1335 /* arg0: circuit file, arg1: data file */
com_snload(wordlist * wl)1336 void com_snload(wordlist *wl)
1337 {
1338     int error = 0;
1339     FILE *file;
1340     int tmpI, i, size;
1341     CKTcircuit *my_ckt, *ckt;
1342 
1343     /*
1344       Pseudo code:
1345 
1346       source(file_name);
1347       This should setup all the device structs, voltage nodes, etc.
1348 
1349       call cktsetup;
1350       This is needed to setup vector mamory allocation for vectors and branch nodes
1351 
1352       load_binary_data(info);
1353       Overwrite the allocated numbers, rhs etc, with saved data
1354     */
1355 
1356 
1357     if (ft_curckt && !strstr(ft_curckt->ci_name, "script")) {
1358         /* Circuit, not a script */
1359         fprintf(cp_err, "Error: there is already a circuit loaded.\n");
1360         return;
1361     }
1362 
1363     /* source the circuit */
1364     inp_source(wl->wl_word);
1365     if (!ft_curckt)
1366         return;
1367 
1368     /* allocate all the vectors, with luck!  */
1369     if (!error)
1370         error = CKTsetup(ft_curckt->ci_ckt);
1371     if (!error)
1372         error = CKTtemp(ft_curckt->ci_ckt);
1373 
1374     if (error) {
1375         fprintf(cp_err, "Some error in the CKT setup fncts!\n");
1376         return;
1377     }
1378 
1379     /* so it resumes ... */
1380     ft_curckt->ci_inprogress = TRUE;
1381 
1382     /* now load the binary file */
1383     ckt = ft_curckt->ci_ckt;
1384 
1385     file = fopen(wl->wl_next->wl_word, "rb");
1386 
1387     if (!file) {
1388         fprintf(cp_err, "Error: Couldn't open \"%s\" for reading\n", wl->wl_next->wl_word);
1389         return;
1390     }
1391 
1392     if (fread(&tmpI, sizeof(int), 1, file) != 1) {
1393         (void) fprintf(cp_err, "Unable to read spice version from snapshot.\n");
1394         fclose(file);
1395         return;
1396     }
1397     if (tmpI != sizeof(CKTcircuit)) {
1398         fprintf(cp_err, "loaded num: %d, expected num: %ld\n", tmpI, (long)sizeof(CKTcircuit));
1399         fprintf(cp_err, "Error: snapshot saved with different version of spice\n");
1400         fclose(file);
1401         return;
1402     }
1403 
1404     my_ckt = TMALLOC(CKTcircuit, 1);
1405 
1406     if (fread(my_ckt, sizeof(CKTcircuit), 1, file) != 1) {
1407         (void) fprintf(cp_err, "Unable to read spice circuit from snapshot.\n");
1408         fclose(file);
1409         return;
1410     }
1411 
1412 #define _t(name) ckt->name = my_ckt->name
1413 #define _ta(name, size)                                                 \
1414     do { int __i; for (__i = 0; __i < size; __i++) _t(name[__i]); } while(0)
1415 
1416     _t(CKTtime);
1417     _t(CKTdelta);
1418     _ta(CKTdeltaOld, 7);
1419     _t(CKTtemp);
1420     _t(CKTnomTemp);
1421     _t(CKTvt);
1422     _ta(CKTag, 7);
1423 
1424     _t(CKTorder);
1425     _t(CKTmaxOrder);
1426     _t(CKTintegrateMethod);
1427     _t(CKTxmu);
1428     _t(CKTindverbosity);
1429     _t(CKTepsmin);
1430 
1431     _t(CKTniState);
1432 
1433     _t(CKTmaxEqNum);
1434     _t(CKTcurrentAnalysis);
1435 
1436     _t(CKTnumStates);
1437     _t(CKTmode);
1438 
1439     _t(CKTbypass);
1440     _t(CKTdcMaxIter);
1441     _t(CKTdcTrcvMaxIter);
1442     _t(CKTtranMaxIter);
1443     _t(CKTbreakSize);
1444     _t(CKTbreak);
1445     _t(CKTsaveDelta);
1446     _t(CKTminBreak);
1447     _t(CKTabstol);
1448     _t(CKTpivotAbsTol);
1449     _t(CKTpivotRelTol);
1450     _t(CKTreltol);
1451     _t(CKTchgtol);
1452     _t(CKTvoltTol);
1453 
1454     _t(CKTgmin);
1455     _t(CKTgshunt);
1456     _t(CKTcshunt);
1457     _t(CKTdelmin);
1458     _t(CKTtrtol);
1459     _t(CKTfinalTime);
1460     _t(CKTstep);
1461     _t(CKTmaxStep);
1462     _t(CKTinitTime);
1463     _t(CKTomega);
1464     _t(CKTsrcFact);
1465     _t(CKTdiagGmin);
1466     _t(CKTnumSrcSteps);
1467     _t(CKTnumGminSteps);
1468     _t(CKTgminFactor);
1469     _t(CKTnoncon);
1470     _t(CKTdefaultMosM);
1471     _t(CKTdefaultMosL);
1472     _t(CKTdefaultMosW);
1473     _t(CKTdefaultMosAD);
1474     _t(CKTdefaultMosAS);
1475     _t(CKThadNodeset);
1476     _t(CKTfixLimit);
1477     _t(CKTnoOpIter);
1478     _t(CKTisSetup);
1479 #ifdef XSPICE
1480     _t(CKTadevFlag);
1481 #endif
1482     _t(CKTtimeListSize);
1483     _t(CKTtimeIndex);
1484     _t(CKTsizeIncr);
1485 
1486     _t(CKTtryToCompact);
1487     _t(CKTbadMos3);
1488     _t(CKTkeepOpInfo);
1489     _t(CKTcopyNodesets);
1490     _t(CKTnodeDamping);
1491     _t(CKTabsDv);
1492     _t(CKTrelDv);
1493     _t(CKTtroubleNode);
1494 
1495 #undef _foo
1496 #define _foo(name, type, _size)                                         \
1497     do {                                                                \
1498         int __i;                                                        \
1499         if (fread(&__i, sizeof(int), 1, file) == 1 && __i > 0) {        \
1500             if (name) {                                                 \
1501                 txfree(name);                                           \
1502             }                                                           \
1503             name = (type *) tmalloc((size_t) __i);                      \
1504             if (fread(name, 1, (size_t) __i, file) != (size_t) __i) {   \
1505                 (void) fprintf(cp_err,                                  \
1506                         "Unable to read vector " #name "\n");           \
1507                 break;                                                  \
1508             }                                                           \
1509         }                                                               \
1510         else {                                                          \
1511             fprintf(cp_err, "size for vector " #name " is 0\n");        \
1512         }                                                               \
1513         if ((_size) != -1 && __i !=                                     \
1514                 (int) (_size) * (int) sizeof(type)) {                   \
1515             fprintf(cp_err, "expected %ld, but got %d for "#name"\n",   \
1516                     (_size)*(long)sizeof(type), __i);                   \
1517         }                                                               \
1518     } while(0)
1519 
1520 
1521     for (i = 0; i <= ckt->CKTmaxOrder+1; i++)
1522         _foo(ckt->CKTstates[i], double, ckt->CKTnumStates);
1523 
1524     size = SMPmatSize(ckt->CKTmatrix) + 1;
1525     _foo(ckt->CKTrhs, double, size);
1526     _foo(ckt->CKTrhsOld, double, size);
1527     _foo(ckt->CKTrhsSpare, double, size);
1528     _foo(ckt->CKTirhs, double, size);
1529     _foo(ckt->CKTirhsOld, double, size);
1530     _foo(ckt->CKTirhsSpare, double, size);
1531 //    _foo(ckt->CKTrhsOp, double, size);
1532 //    _foo(ckt->CKTsenRhs, double, size);
1533 //    _foo(ckt->CKTseniRhs, double, size);
1534 
1535 //    _foo(ckt->CKTtimePoints, double, -1);
1536 //    _foo(ckt->CKTdeltaList, double, -1);
1537 
1538     _foo(ckt->CKTbreaks, double, ckt->CKTbreakSize);
1539 
1540     {   /* avoid invalid lvalue assignment errors in the macro _foo() */
1541         TSKtask *lname = NULL;
1542         _foo(lname, TSKtask, 1);
1543         ft_curckt->ci_curTask = lname;
1544     }
1545 
1546     /* To stop the Free */
1547     ft_curckt->ci_curTask->TSKname = NULL;
1548     ft_curckt->ci_curTask->jobs = NULL;
1549 
1550     _foo(ft_curckt->ci_curTask->TSKname, char, -1);
1551 
1552     {
1553         TRANan *lname = NULL;
1554         _foo(lname, TRANan, -1);
1555         ft_curckt->ci_curTask->jobs = (JOB *)lname;
1556     }
1557     ft_curckt->ci_curTask->jobs->JOBname = NULL;
1558     _foo(ft_curckt->ci_curTask->jobs->JOBname, char, -1);
1559     ft_curckt->ci_curTask->jobs->JOBnextJob = NULL;
1560     ckt->CKTcurJob = ft_curckt->ci_curTask->jobs;
1561     ((TRANan *)ft_curckt->ci_curTask->jobs)->TRANplot = NULL;
1562 
1563     _foo(ckt->CKTstat, STATistics, 1);
1564     ckt->CKTstat->STATdevNum = NULL;
1565     _foo(ckt->CKTstat->STATdevNum, STATdevList, -1);
1566 
1567 #ifdef XSPICE
1568     _foo(ckt->evt, Evt_Ckt_Data_t, 1);
1569     _foo(ckt->enh, Enh_Ckt_Data_t, 1);
1570     g_mif_info.breakpoint.current = ckt->enh->breakpoint.current;
1571     g_mif_info.breakpoint.last = ckt->enh->breakpoint.last;
1572 #endif
1573 
1574     tfree(my_ckt);
1575     fclose(file);
1576 
1577     /* Finally to resume the plot in some fashion */
1578 
1579     /* a worked out version of this should be enough */
1580     {
1581         IFuid *nameList;
1582         int numNames;
1583         IFuid timeUid;
1584 
1585         error = CKTnames(ckt, &numNames, &nameList);
1586         if (error) {
1587             fprintf(cp_err, "error in CKTnames\n");
1588             return;
1589         }
1590         SPfrontEnd->IFnewUid (ckt, &timeUid, NULL, "time", UID_OTHER, NULL);
1591         error = SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob,
1592                                            ckt->CKTcurJob->JOBname,
1593                                            timeUid, IF_REAL,
1594                                            numNames, nameList, IF_REAL,
1595                                            &(((TRANan*)ckt->CKTcurJob)->TRANplot));
1596         if (error) {
1597             fprintf(cp_err, "error in CKTnames\n");
1598             return;
1599         }
1600     }
1601 }
1602 
1603 
com_snsave(wordlist * wl)1604 void com_snsave(wordlist *wl)
1605 {
1606     FILE *file;
1607     int i, size;
1608     CKTcircuit *ckt;
1609     TSKtask *task;
1610 
1611     if (!ft_curckt) {
1612         fprintf(cp_err, "Error: there is no circuit loaded.\n");
1613         return;
1614     } else if (!ft_curckt->ci_ckt) { /* Set noparse? */
1615         fprintf(cp_err, "Error: circuit not parsed.\n");
1616         return;
1617     }
1618 
1619     /* save the data */
1620 
1621     ckt = ft_curckt->ci_ckt;
1622 
1623 #ifdef XSPICE
1624     if (ckt->CKTadevFlag == 1) {
1625         fprintf(cp_err, "Warning: snsave not implemented for XSPICE A devices.\n");
1626         fprintf(cp_err, "    Command 'snsave' will be ingnored!\n");
1627         return;
1628     }
1629 #endif
1630 
1631     task = ft_curckt->ci_curTask;
1632 
1633     if (task->jobs->JOBtype != 4) {
1634         fprintf(cp_err, "Only saving of tran analysis is implemented\n");
1635         return;
1636     }
1637 
1638     file = fopen(wl->wl_word, "wb");
1639 
1640     if (!file) {
1641         fprintf(cp_err,
1642                 "Error: Couldn't open \"%s\" for writing\n", wl->wl_word);
1643         return;
1644     }
1645 
1646 #undef _foo
1647 #define _foo(name, type, num)                                           \
1648     do {                                                                \
1649         int __i;                                                        \
1650         if (name) {                                                     \
1651             __i = (num) * (int)sizeof(type); fwrite(&__i, sizeof(int), 1, file); \
1652             if ((num))                                                  \
1653                 fwrite(name, sizeof(type), (size_t)(num), file);        \
1654         } else {                                                        \
1655             __i = 0;                                                    \
1656             fprintf(cp_err, #name " is NULL, zero written\n");          \
1657             fwrite(&__i, sizeof(int), 1, file);                         \
1658         }                                                               \
1659     } while(0)
1660 
1661 
1662     _foo(ckt, CKTcircuit, 1);
1663 
1664     /* To save list
1665 
1666        double *(CKTstates[8]);
1667        double *CKTrhs;
1668        double *CKTrhsOld;
1669        double *CKTrhsSpare;
1670        double *CKTirhs;
1671        double *CKTirhsOld;
1672        double *CKTirhsSpare;
1673        double *CKTrhsOp;
1674        double *CKTsenRhs;
1675        double *CKTseniRhs;
1676        double *CKTtimePoints;       list of all accepted timepoints in
1677        the current transient simulation
1678        double *CKTdeltaList;        list of all timesteps in the
1679        current transient simulation
1680 
1681     */
1682 
1683 
1684     for (i = 0; i <= ckt->CKTmaxOrder+1; i++)
1685         _foo(ckt->CKTstates[i], double, ckt->CKTnumStates);
1686 
1687 
1688     size = SMPmatSize(ckt->CKTmatrix) + 1;
1689 
1690     _foo(ckt->CKTrhs, double, size);
1691     _foo(ckt->CKTrhsOld, double, size);
1692     _foo(ckt->CKTrhsSpare, double, size);
1693     _foo(ckt->CKTirhs, double, size);
1694     _foo(ckt->CKTirhsOld, double, size);
1695     _foo(ckt->CKTirhsSpare, double, size);
1696 //    _foo(ckt->CKTrhsOp, double, size);
1697 //    _foo(ckt->CKTsenRhs, double, size);
1698 //    _foo(ckt->CKTseniRhs, double, size);
1699 
1700 //    _foo(ckt->CKTtimePoints, double, ckt->CKTtimeListSize);
1701 //    _foo(ckt->CKTdeltaList, double, ckt->CKTtimeListSize);
1702 
1703     /* need to save the breakpoints, or something */
1704     _foo(ckt->CKTbreaks, double, ckt->CKTbreakSize);
1705 
1706     /* now save the TSK struct, ft_curckt->ci_curTask*/
1707     _foo(task, TSKtask, 1);
1708     _foo(task->TSKname, char, ((int)strlen(task->TSKname)+1));
1709 
1710     /* now save the JOB struct task->jobs */
1711     /* lol, only allow one job, tough! */
1712     /* Note that JOB is a base class, need to save actual type!! */
1713     _foo(task->jobs, TRANan, 1);
1714     _foo(task->jobs->JOBname, char, ((int)strlen(task->jobs->JOBname)+1));
1715 
1716     /* Finally the stats */
1717     _foo(ckt->CKTstat, STATistics, 1);
1718     _foo(ckt->CKTstat->STATdevNum, STATdevList, 1);
1719 
1720 #ifdef XSPICE
1721     /* FIXME struct ckt->evt->data and others are not stored
1722        thus snsave, snload not compatible with XSPICE code models*/
1723     _foo(ckt->evt, Evt_Ckt_Data_t, 1);
1724     _foo(ckt->enh, Enh_Ckt_Data_t, 1);
1725 #endif
1726 
1727     fclose(file);
1728     fprintf(stdout, "Snapshot saved to %s.\n", wl->wl_word);
1729 }
1730 
1731 
1732 int
ft_find_analysis(char * name)1733 ft_find_analysis(char *name)
1734 {
1735     int j;
1736     for (j = 0; j < ft_sim->numAnalyses; j++)
1737         if (strcmp(ft_sim->analyses[j]->name, name) == 0)
1738             return j;
1739     return -1;
1740 }
1741 
1742 
1743 IFparm *
ft_find_analysis_parm(int which,char * name)1744 ft_find_analysis_parm(int which, char *name)
1745 {
1746     int i;
1747     for (i = 0; i < ft_sim->analyses[which]->numParms; i++)
1748         if (!strcmp(ft_sim->analyses[which]->analysisParms[i].keyword, name))
1749             return &(ft_sim->analyses[which]->analysisParms[i]);
1750     return NULL;
1751 }
1752