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