1 /***************************************************************************
2 JSPICE3 adaptation of Spice3e2 - Copyright (c) Stephen R. Whiteley 1992
3 Copyright 1990 Regents of the University of California. All rights reserved.
4 Authors: 1988 Wayne A. Christopher
5 1992 Stephen R. Whiteley
6 ****************************************************************************/
7
8 /*
9 * This module replaces the old "writedata" routines in nutmeg.
10 * Unlike the writedata routines, the OUT routines are only called by
11 * the simulator routines, and only call routines in nutmeg. The rest
12 * of nutmeg doesn't deal with OUT at all.
13 */
14
15 #include "spice.h"
16 #include "ftedefs.h"
17 #include "inpdefs.h"
18 #include "ftegraph.h"
19 #include "spfteext.h"
20 #include "plotext.h"
21 #include "iferrmsg.h"
22 #include "outdata.h"
23
24 #define DOUBLE_PRECISION 15
25
26 typedef struct dataDesc {
27 char *name; /* The name of the vector. */
28 int type; /* The type. */
29 bool regular; /* Is this given to us? */
30 int outIndex; /* If regular then the index. */
31 char *specName; /* The device name if special. */
32 char *specParamName;/* The parameter name if special. */
33 int specIndex; /* For sensitivity, if special. */
34 int specType;
35 GENERIC *specFast;
36 int refIndex; /* The index of our ref vector. */
37 struct dvec *vec;
38 } dataDesc;
39
40 typedef struct runDesc {
41 GENERIC *analysis;
42 GENERIC *circuit;
43 char *name;
44 char *type;
45 int numData;
46 int refIndex;
47 dataDesc *data;
48 bool writeOut;
49 bool binary;
50 struct plot *runPlot;
51 FILE *fp;
52 long pointPos; /* where to write pointCount */
53 int pointCount; /* running count of output points */
54 int numPoints; /* num points expected, -1 if not known */
55 int isComplex;
56 int windowCount;
57 } runDesc;
58
59 /* signal the simulator to end analysis as if finished */
60 bool OUTendit;
61
62 static struct sOUTcontrol OUTcntrl;
63
64 #ifdef __STDC__
65 static void out_destroy(void);
66 static int addDataDesc(runDesc*,char*,int,int);
67 static int addSpecialDesc(runDesc*,char*,char*,char*,int);
68 static void addPointToFile(runDesc*,IFvalue*,IFvalue*);
69 static void addPointToPlot(runDesc*,IFvalue*,IFvalue*,bool);
70 static void fileInit(runDesc*);
71 static void fileStartPoint(FILE*,bool,int);
72 static void fileAddRealValue(FILE*,bool,double);
73 static void fileAddComplexValue(FILE*,bool,IFcomplex);
74 static void fileEndPoint(FILE*,bool);
75 static void fileEnd(runDesc*);
76 static void plotInit(runDesc*,double,double,double,struct plot*);
77 static void plotAddRealValue(dataDesc*,double,bool);
78 static void plotAddComplexValue(dataDesc*,IFcomplex,bool);
79 static void plotEnd(runDesc*);
80 static bool parseSpecial(char*,char*,char*,char*);
81 static bool name_eq(char*,char*);
82 static bool getSpecial(dataDesc*,runDesc*,IFvalue*);
83 static void freeRun(runDesc*);
84 #else
85 static void out_destroy();
86 static int addDataDesc();
87 static int addSpecialDesc();
88 static void addPointToFile();
89 static void addPointToPlot();
90 static void fileInit();
91 static void fileStartPoint();
92 static void fileAddRealValue();
93 static void fileAddComplexValue();
94 static void fileEndPoint();
95 static void fileEnd();
96 static void plotInit();
97 static void plotAddRealValue();
98 static void plotAddComplexValue();
99 static void plotEnd();
100 static bool parseSpecial();
101 static bool name_eq();
102 static bool getSpecial();
103 static void freeRun();
104 #endif
105
106 static bool shouldstop = false; /* Tell simulator to stop next time it asks. */
107 static bool printinfo = false; /* Print informational "error messages". */
108
109
110 char *
OUTcntrlInit()111 OUTcntrlInit()
112 {
113 /* return the OUTcntrl structure */
114 OUTcntrl.out_destroy = out_destroy;
115 OUTcntrl.out_rundesc = NULL;
116 OUTcntrl.out_check = false;
117 OUTcntrl.out_usecurplot = false;
118 OUTcntrl.out_keepplot = false;
119 OUTcntrl.out_points = NULL;
120 OUTcntrl.out_index = 0;
121 OUTcntrl.out_max = 0;
122 OUTcntrl.out_fail = 0;
123 OUTcntrl.out_evaluate = NULL;
124 OUTcntrl.out_end = NULL;
125 return (char *)&OUTcntrl;
126 }
127
128
129 static void
out_destroy()130 out_destroy()
131 {
132 if (OUTcntrl.out_rundesc) {
133 freeRun((runDesc*)OUTcntrl.out_rundesc);
134 OUTcntrl.out_rundesc = NULL;
135 }
136 OUTcntrl.out_check = false;
137 OUTcntrl.out_usecurplot = false;
138 OUTcntrl.out_keepplot = false;
139 OUTcntrl.out_points = NULL;
140 OUTcntrl.out_index = 0;
141 OUTcntrl.out_max = 0;
142 OUTcntrl.out_fail = 0;
143 OUTcntrl.out_evaluate = NULL;
144 OUTcntrl.out_end = NULL;
145 }
146
147
148 int
OUTbeginPlot(outdp)149 OUTbeginPlot(outdp)
150
151 GENERIC *outdp;
152 {
153 struct sOUTdata *outd = (struct sOUTdata*)outdp;
154 struct plot *plot = NULL;
155 runDesc *run;
156 char **saves;
157 char *cktName;
158 bool *savesused;
159 int numsaves;
160 int i, j, depind;
161 char namebuf[BSIZE_SP], parambuf[BSIZE_SP], depbuf[BSIZE_SP];
162 bool saveall = true;
163 extern char *kw_printinfo;
164
165 shouldstop = false;
166
167 if (OUTcntrl.out_check) {
168 OUTcntrl.out_index = 0;
169 }
170 if (OUTcntrl.out_usecurplot) {
171 plot = plot_cur;
172 }
173 if (OUTcntrl.out_keepplot && OUTcntrl.out_rundesc) {
174 *outd->plotPtr = (GENERIC*)OUTcntrl.out_rundesc;
175 return (OK);
176 }
177
178 if (ft_curckt && ft_curckt->ci_ckt == outd->circuitPtr)
179 cktName = ft_curckt->ci_name;
180 else {
181 /* hack for test system interface */
182 if (outd->circuitPtr == NULL)
183 cktName = (char*)outd->refName + (strlen(outd->refName) + 1);
184 else
185 cktName = "circuit name";
186 }
187
188 /* Check to see if we want to print informational data. */
189 if (cp_getvar(kw_printinfo, VT_BOOL, (char *) &printinfo))
190 fprintf(cp_err, "(debug printing enabled)\n");
191
192 run = alloc(struct runDesc);
193 *outd->plotPtr = (GENERIC*)run;
194
195 /* First fill in some general stuff. */
196 run->analysis = outd->analysisPtr;
197 run->circuit = outd->circuitPtr;
198 run->name = copy(cktName);
199 run->type = copy(outd->analName);
200 if (outd->numPts <= 0)
201 run->numPoints = 1;
202 else
203 run->numPoints = outd->numPts;
204
205 if (OUTcntrl.out_check) {
206 run->numPoints = 1;
207 }
208 if (OUTcntrl.out_keepplot) {
209 OUTcntrl.out_rundesc = (char*)run;
210 }
211
212 /* Now let's see which of these things we need. First toss in the
213 * reference vector. Then toss in anything that getSaves() tells
214 * us to save that we can find in the name list. Finally unpack
215 * the remaining saves into parameters.
216 */
217 numsaves = ft_getSaves(&saves);
218 if (numsaves) {
219 savesused = (bool *) tmalloc(sizeof (bool) * numsaves);
220 saveall = false;
221 for (i = 0; i < numsaves; i++)
222 if (cieq(saves[i], "all")) {
223 saveall = true;
224 savesused[i] = true;
225 break;
226 }
227 }
228
229 /* Pass 0. */
230 if (outd->refName) {
231 addDataDesc(run, outd->refName, outd->refType, -1);
232 for (i = 0; i < numsaves; i++)
233 if (name_eq(saves[i], outd->refName)) {
234 savesused[i] = true;
235 }
236 }
237 else {
238 run->refIndex = -1;
239 }
240
241 /* Pass 1. */
242 if (numsaves && !saveall) {
243 for (i = 0; i < numsaves; i++) {
244 for (j = 0; j < outd->numNames; j++)
245 if (name_eq(saves[i], outd->dataNames[j])) {
246 addDataDesc(run, outd->dataNames[j],
247 outd->dataType, j);
248 savesused[i] = true;
249 break;
250 }
251 }
252 }
253 else {
254 for (i = 0; i < outd->numNames; i++)
255 if (!outd->refName ||
256 !name_eq(outd->dataNames[i], outd->refName)) {
257 addDataDesc(run, outd->dataNames[i], outd->dataType, i);
258 }
259 }
260
261 /* Pass 2. */
262 for (i = 0; i < numsaves; i++) {
263 if (savesused[i])
264 continue;
265 if (!parseSpecial(saves[i], namebuf, parambuf, depbuf)) {
266 if (numsaves == 1 && !saves[0])
267 fprintf(cp_err, "Warning: no variables saved\n");
268 else
269 fprintf(cp_err, "Warning: can't parse '%s': ignored\n",
270 saves[i]);
271 continue;
272 }
273 /* Now, if there's a dep variable, do we already have it? */
274 if (*depbuf) {
275 for (j = 0; j < run->numData; j++)
276 if (name_eq(depbuf, run->data[j].name))
277 break;
278 if (j == run->numData) {
279 /* Better add it. */
280 for (j = 0; j < outd->numNames; j++)
281 if (name_eq(depbuf, outd->dataNames[j]))
282 break;
283 if (j == outd->numNames) {
284 fprintf(cp_err,
285 "Warning: can't find '%s': value '%s' ignored\n",
286 depbuf, saves[i]);
287 continue;
288 }
289 addDataDesc(run, outd->dataNames[j], outd->dataType, j);
290 savesused[i] = true;
291 depind = j;
292 }
293 else
294 depind = run->data[j].outIndex;
295 }
296 addSpecialDesc(run, saves[i], namebuf, parambuf, depind);
297 }
298
299 if (numsaves)
300 txfree((char*)savesused);
301
302 /* Now that we have our own data structures built up, let's see what
303 * nutmeg wants us to do.
304 */
305 run->writeOut = ft_getOutReq(&run->fp, &run->runPlot, &run->binary,
306 run->type, run->name);
307
308 if (run->writeOut)
309 fileInit(run);
310 else
311 plotInit(run,outd->initValue,outd->finalValue,outd->step,plot);
312
313 if (outd->refName && run->runPlot)
314 run->runPlot->pl_ndims = 1;
315
316 return (OK);
317 }
318
319
320 static int
addDataDesc(run,name,type,ind)321 addDataDesc(run, name, type, ind)
322
323 runDesc *run;
324 char *name;
325 int type;
326 int ind;
327 {
328 dataDesc *data;
329
330 if (!run->numData)
331 run->data = (dataDesc *) tmalloc(sizeof (dataDesc));
332 else
333 run->data = (dataDesc *) trealloc((char *) run->data,
334 sizeof (dataDesc) * (run->numData + 1));
335 data = &run->data[run->numData];
336 /* so freeRun will get nice NULL pointers for the fields we don't set */
337 bzero(data, sizeof(dataDesc));
338
339 data->name = copy(name);
340 data->type = type;
341 data->regular = true;
342 data->outIndex = ind;
343
344 if (ind == -1) {
345 /* It's the reference vector. */
346 run->refIndex = run->numData;
347 }
348
349 run->numData++;
350
351 return (OK);
352 }
353
354
355 static int
addSpecialDesc(run,name,devname,param,depind)356 addSpecialDesc(run, name, devname, param, depind)
357
358 runDesc *run;
359 char *name;
360 char *devname;
361 char *param;
362 int depind;
363 {
364 dataDesc *data;
365 char *unique; /* unique char * from back-end */
366
367 if (!run->numData)
368 run->data = (dataDesc *) tmalloc(sizeof (dataDesc));
369 else
370 run->data = (dataDesc *) trealloc((char *) run->data,
371 sizeof (dataDesc) * (run->numData + 1));
372 data = &run->data[run->numData];
373 /* so freeRun will get nice NULL pointers for the fields we don't set */
374 bzero(data, sizeof(dataDesc));
375
376 data->name = copy(name);
377
378 unique = devname;
379 INPinsert(&unique, (INPtables *) ft_curckt->ci_symtab);
380 data->specName = unique;
381
382 data->specParamName = copy(param);
383
384 data->specIndex = depind;
385 data->specType = -1;
386 data->specFast = NULL;
387 data->regular = false;
388
389 run->numData++;
390
391 return (OK);
392 }
393
394
395 int
OUTdata(plotPtr,refValue,valuePtr)396 OUTdata(plotPtr, refValue, valuePtr)
397
398 GENERIC *plotPtr;
399 IFvalue *refValue;
400 IFvalue *valuePtr;
401 {
402 runDesc *run = (runDesc *) plotPtr;
403
404 if (OUTcntrl.out_check) {
405
406 if (refValue->rValue < OUTcntrl.out_points[OUTcntrl.out_index])
407 return (OK);
408
409 addPointToPlot(run,refValue,valuePtr,false);
410 if (OUTcntrl.out_evaluate)
411 OUTcntrl.out_fail = (*OUTcntrl.out_evaluate)();
412 else
413 OUTcntrl.out_fail = false;
414
415 OUTcntrl.out_index++;
416 if (OUTcntrl.out_fail || OUTcntrl.out_index == OUTcntrl.out_max) {
417 OUTendit = true;
418 }
419 return (OK);
420 }
421
422 run->pointCount++;
423
424 if (run->writeOut) {
425 addPointToFile(run,refValue,valuePtr);
426 }
427 else {
428 addPointToPlot(run,refValue,valuePtr,true);
429 gr_iplot(run->runPlot);
430 }
431
432 if (ft_bpcheck(run->runPlot, run->pointCount) == false)
433 shouldstop = true;
434
435 vec_gc();
436 return (OK);
437 }
438
439
440 int
OUTsetDims(plotPtr,dims,numDims)441 OUTsetDims(plotPtr,dims,numDims)
442
443 GENERIC *plotPtr;
444 int *dims, numDims;
445 {
446 runDesc *run = (runDesc *) plotPtr;
447 struct dvec *v;
448 int i, j;
449
450 if (OUTcntrl.out_check) {
451 OUTcntrl.out_index = 0;
452 if (OUTcntrl.out_fail)
453 OUTendit = true;
454 return (OK);
455 }
456
457 if (run->writeOut)
458 return (OK);
459
460 for (i = 0; i < run->numData; i++) {
461 v = run->data[i].vec;
462 for (j = 0; j < numDims; j++)
463 v->v_dims[j] = dims[j];
464 v->v_numdims = numDims;
465 }
466 return (OK);
467 }
468
469
470 static void
addPointToFile(run,refValue,valuePtr)471 addPointToFile(run,refValue,valuePtr)
472
473 runDesc *run;
474 IFvalue *refValue;
475 IFvalue *valuePtr;
476 {
477 int i;
478 IFvalue val;
479
480 fileStartPoint(run->fp, run->binary, run->pointCount);
481
482 if (run->refIndex != -1) {
483 if (run->isComplex)
484 fileAddComplexValue(run->fp, run->binary, refValue->cValue);
485 else
486 fileAddRealValue(run->fp, run->binary, refValue->rValue);
487 }
488
489 for (i = 0; i < run->numData; i++) {
490 /* we've already printed reference vec first */
491 if (run->data[i].outIndex == -1) continue;
492
493 if (run->data[i].regular) {
494 if(run->data[i].type == IF_REAL)
495 fileAddRealValue(run->fp, run->binary,
496 valuePtr->v.vec.rVec
497 [run->data[i].outIndex]);
498 else if (run->data[i].type == IF_COMPLEX)
499 fileAddComplexValue(run->fp, run->binary,
500 valuePtr->v.vec.cVec
501 [run->data[i].outIndex]);
502 else
503 fprintf(stderr, "OUTdata: unsupported data type\n");
504 }
505 else {
506 /* should pre-check instance */
507 if (!getSpecial(&run->data[i], run, &val))
508 continue;
509 if (run->data[i].type == IF_REAL)
510 fileAddRealValue(run->fp, run->binary,
511 val.rValue);
512 else if (run->data[i].type == IF_COMPLEX)
513 fileAddComplexValue(run->fp, run->binary,
514 val.cValue);
515 else
516 fprintf(stderr, "OUTdata: unsupported data type\n");
517 }
518 }
519 fileEndPoint(run->fp, run->binary);
520 }
521
522
523 static void
addPointToPlot(run,refValue,valuePtr,inc)524 addPointToPlot(run,refValue,valuePtr,inc)
525
526 runDesc *run;
527 IFvalue *refValue;
528 IFvalue *valuePtr;
529 bool inc; /* increment dvec length if true */
530 {
531 int i;
532 IFvalue val;
533
534 for (i = 0; i < run->numData; i++) {
535 if (run->data[i].outIndex == -1) {
536 if (run->data[i].type == IF_REAL)
537 plotAddRealValue(&run->data[i],
538 refValue->rValue,inc);
539 else if (run->data[i].type == IF_COMPLEX)
540 plotAddComplexValue(&run->data[i],
541 refValue->cValue,inc);
542 }
543 else if (run->data[i].regular) {
544 if (run->data[i].type == IF_REAL)
545 plotAddRealValue(&run->data[i],
546 valuePtr->v.vec.rVec
547 [run->data[i].outIndex],inc);
548 else if (run->data[i].type == IF_COMPLEX)
549 plotAddComplexValue(&run->data[i],
550 valuePtr->v.vec.cVec
551 [run->data[i].outIndex],inc);
552 }
553 else {
554 /* should pre-check instance */
555 if (!getSpecial(&run->data[i], run, &val))
556 continue;
557 if (run->data[i].type == IF_REAL)
558 plotAddRealValue(&run->data[i],
559 val.rValue,inc);
560 else if (run->data[i].type == IF_COMPLEX)
561 plotAddComplexValue(&run->data[i],
562 val.cValue,inc);
563 else
564 fprintf(stderr, "OUTdata: unsupported data type\n");
565 }
566 }
567 }
568
569
570 int
OUTendPlot(plotPtr)571 OUTendPlot(plotPtr)
572
573 GENERIC *plotPtr;
574 {
575 runDesc *run = (runDesc *) plotPtr;
576
577 if (OUTcntrl.out_check) {
578 if (OUTcntrl.out_end)
579 (*OUTcntrl.out_end)();
580 OUTendit = false;
581 return (OK);
582 }
583 else if (OUTcntrl.out_keepplot) {
584 return (OK);
585 }
586
587 if (run->writeOut)
588 fileEnd(run);
589 else {
590 gr_end_iplot();
591 plotEnd(run);
592 }
593
594 freeRun(run);
595
596 return (OK);
597 }
598
599
600 /* The file writing routines. */
601
602 static void
fileInit(run)603 fileInit(run)
604
605 runDesc *run;
606 {
607 int i;
608 char *name, buf[BSIZE_SP];
609 int type;
610
611 /* This is a hack. */
612 run->isComplex = false;
613 for (i = 0; i < run->numData; i++)
614 if (run->data[i].type == IF_COMPLEX)
615 run->isComplex = true;
616
617 fprintf(run->fp, "Title: %s\n", run->name);
618 fprintf(run->fp, "Date: %s\n", datestring());
619 fprintf(run->fp, "Plotname: %s\n", run->type);
620 fprintf(run->fp, "Flags: %s\n", run->isComplex ? "complex" : "real");
621 fprintf(run->fp, "No. Variables: %d\n", run->numData);
622 fprintf(run->fp, "No. Points: ");
623
624 fflush(run->fp); /* Gotta do this for LATTICE. */
625 run->pointPos = ftell(run->fp);
626 fprintf(run->fp, "0 \n"); /* Save 8 spaces here. */
627
628 fprintf(run->fp, "Command: version %s\n", ft_sim->version);
629 fprintf(run->fp, "Variables:\n");
630
631 for (i = 0; i < run->numData; i++) {
632 if (isdigit(*run->data[i].name)) {
633 (void) sprintf(buf, "v(%s)", run->data[i].name);
634 name = buf;
635 }
636 else {
637 name = run->data[i].name;
638 }
639 if (substring("#branch", name))
640 type = SV_CURRENT;
641 else if (cieq(name, "time"))
642 type = SV_TIME;
643 else if (cieq(name, "frequency"))
644 type = SV_FREQUENCY;
645 else
646 type = SV_VOLTAGE;
647 fprintf(run->fp, "\t%d\t%s\t%s\n", i, name,
648 ft_typenames(type));
649 }
650
651 fprintf(run->fp, "%s:\n", run->binary ? "Binary" : "Values");
652
653 return;
654 }
655
656
657 static void
fileStartPoint(fp,bin,num)658 fileStartPoint(fp, bin, num)
659
660 FILE *fp;
661 bool bin;
662 int num;
663 {
664 if (!bin)
665 fprintf(fp, "%d", num - 1);
666
667 return;
668 }
669
670
671 static void
fileAddRealValue(fp,bin,value)672 fileAddRealValue(fp, bin, value)
673
674 FILE *fp;
675 bool bin;
676 double value;
677 {
678 if (bin)
679 fwrite((char *) &value, sizeof (double), 1, fp);
680 else
681 fprintf(fp, "\t%.*e\n", DOUBLE_PRECISION, value);
682
683 return;
684 }
685
686
687 static void
fileAddComplexValue(fp,bin,value)688 fileAddComplexValue(fp, bin, value)
689
690 FILE *fp;
691 bool bin;
692 IFcomplex value;
693 {
694
695 if (bin) {
696 fwrite((char *) &value.real, sizeof (double), 1, fp);
697 fwrite((char *) &value.imag, sizeof (double), 1, fp);
698 }
699 else {
700 fprintf(fp, "\t%.*e,%.*e\n", DOUBLE_PRECISION, value.real,
701 DOUBLE_PRECISION, value.imag);
702 }
703
704 }
705
706
707 /* ARGSUSED */ /* until some code gets written */
708 static void
fileEndPoint(fp,bin)709 fileEndPoint(fp, bin)
710
711 FILE *fp;
712 bool bin;
713 {
714 return;
715 }
716
717
718 /* Here's the hack... Run back and fill in the number of points. */
719
720 static void
fileEnd(run)721 fileEnd(run)
722
723 runDesc *run;
724 {
725 long place;
726
727 if (run->fp == stdout)
728 return;
729 fflush(run->fp); /* For LATTICE... */
730 place = ftell(run->fp);
731 fseek(run->fp, run->pointPos, 0);
732 fprintf(run->fp, "%d", run->pointCount);
733 fseek(run->fp, place, 0);
734 fflush(run->fp);
735
736 return;
737 }
738
739
740 /* The plot maintenance routines. */
741
742 static void
plotInit(run,tstart,tstop,tstep,plot)743 plotInit(run,tstart,tstop,tstep,plot)
744
745 runDesc *run;
746 double tstart, tstop, tstep;
747 struct plot *plot;
748 {
749 struct plot *pl;
750 char buf[100];
751 struct dvec *v;
752 dataDesc *dd;
753 int i;
754
755 if (plot == NULL) {
756 pl = plot_alloc(run->type);
757 plot_new(pl);
758 plot_setcur(pl->pl_typename);
759 }
760 else
761 pl = plot;
762 pl->pl_title = copy(run->name);
763 pl->pl_name = copy(run->type);
764 pl->pl_date = copy(datestring( ));
765 pl->pl_ndims = 0;
766 pl->pl_start = tstart;
767 pl->pl_stop = tstop;
768 pl->pl_step = tstep;
769 run->runPlot = pl;
770
771 /* This is a hack. */
772 /* if any of them are complex, make them all complex */
773 run->isComplex = false;
774 for (i = 0; i < run->numData; i++) {
775 if (run->data[i].type == IF_COMPLEX) run->isComplex = true;
776 }
777
778 for (i = 0; i < run->numData; i++) {
779 dd = &run->data[i];
780 v = alloc(struct dvec);
781 if (isdigit(*dd->name)) {
782 (void) sprintf(buf, "v(%s)", dd->name);
783 v->v_name = copy(buf);
784 }
785 else
786 v->v_name = copy(dd->name);
787 if (substring("#branch", v->v_name) || eq(v->v_name,"isweep"))
788 v->v_type = SV_CURRENT;
789 else if (cieq(v->v_name, "time"))
790 v->v_type = SV_TIME;
791 else if (cieq(v->v_name, "frequency"))
792 v->v_type = SV_FREQUENCY;
793 else
794 v->v_type = SV_VOLTAGE;
795 v->v_length = 0;
796 v->v_rlength = run->numPoints;
797 v->v_scale = NULL;
798
799 if (!run->isComplex) {
800 v->v_flags = VF_REAL;
801 v->v_realdata = (double *)
802 tmalloc(v->v_rlength * sizeof(double));
803 }
804 else {
805 v->v_flags = VF_COMPLEX;
806 v->v_compdata = (complex *)
807 tmalloc(v->v_rlength * sizeof(complex));
808 }
809 vec_newperm(v);
810 dd->vec = v;
811 }
812 }
813
814
815 static void
plotAddRealValue(desc,value,inc)816 plotAddRealValue(desc, value, inc)
817
818 dataDesc *desc;
819 double value;
820 bool inc;
821 {
822 struct dvec *v = desc->vec;
823
824 if (isreal(v)) {
825 if (!inc) {
826 v->v_realdata[0] = value;
827 v->v_length = 1;
828 return;
829 }
830 if (v->v_length >= v->v_rlength) {
831 v->v_realdata = (double *) trealloc((char *) v->v_realdata,
832 sizeof (double) * (v->v_length + 1));
833 v->v_rlength = v->v_length + 1;
834 }
835 v->v_realdata[v->v_length] = value;
836 }
837 else {
838 /* a real parading as a VF_COMPLEX */
839 if (!inc) {
840 v->v_compdata[0].cx_real = value;
841 v->v_compdata[0].cx_imag = (double) 0;
842 v->v_length = 1;
843 return;
844 }
845 if (v->v_length >= v->v_rlength) {
846 v->v_compdata = (complex *) trealloc((char *) v->v_compdata,
847 sizeof (complex) * (v->v_length + 1));
848 v->v_rlength = v->v_length + 1;
849 }
850 v->v_compdata[v->v_length].cx_real = value;
851 v->v_compdata[v->v_length].cx_imag = (double) 0;
852 }
853 v->v_length++;
854
855 return;
856 }
857
858
859 static void
plotAddComplexValue(desc,value,inc)860 plotAddComplexValue(desc, value, inc)
861
862 dataDesc *desc;
863 IFcomplex value;
864 bool inc;
865 {
866 struct dvec *v = desc->vec;
867
868 if (!inc) {
869 v->v_compdata[0].cx_real = value.real;
870 v->v_compdata[0].cx_imag = value.imag;
871 v->v_length = 1;
872 return;
873 }
874 if (v->v_length >= v->v_rlength) {
875 v->v_compdata = (complex *) trealloc((char *) v->v_compdata,
876 sizeof (complex) * (v->v_length + 1));
877 v->v_rlength = v->v_length + 1;
878 }
879 v->v_compdata[v->v_length].cx_real = value.real;
880 v->v_compdata[v->v_length].cx_imag = value.imag;
881 v->v_length++;
882
883 return;
884 }
885
886
887 /* ARGSUSED */ /* until some code gets written */
888 static void
plotEnd(run)889 plotEnd(run)
890
891 runDesc *run;
892 {
893 return;
894 }
895
896
897 /* ParseSpecial takes something of the form "@name[param,index]" and rips
898 * out name, param, and index.
899 */
900
901 static bool
parseSpecial(name,dev,param,ind)902 parseSpecial(name, dev, param, ind)
903
904 char *name;
905 char *dev;
906 char *param;
907 char *ind;
908 {
909 char *s;
910
911 *dev = *param = *ind = '\0';
912
913 if (*name != '@')
914 return (false);
915 name++;
916
917 s = dev;
918 while (*name && (*name != '['))
919 *s++ = *name++;
920 *s = '\0';
921 if (!*name)
922 return (true);
923 name++;
924
925 s = param;
926 while (*name && (*name != ',') && (*name != ']'))
927 *s++ = *name++;
928 *s = '\0';
929 if (*name == ']')
930 return (!name[1] ? true : false);
931 else if (!*name)
932 return (false);
933 name++;
934
935 s = ind;
936 while (*name && (*name != ']'))
937 *s++ = *name++;
938 *s = '\0';
939 if (*name && !name[1])
940 return (true);
941 else
942 return (false);
943 }
944
945
946 /* This routine must match two names with or without a V() around them. */
947
948 static bool
name_eq(n1,n2)949 name_eq(n1, n2)
950
951 char *n1, *n2;
952 {
953 char *s;
954
955 if (!n1 || !n2)
956 return (false);
957 s = strchr(n1,'(');
958 if (s)
959 n1 = s+1;
960 s = strchr(n2,'(');
961 if (s)
962 n2 = s+1;
963
964 for ( ; ; n1++,n2++) {
965 if ((*n1 == 0 || *n1 == ')') && (*n2 == 0 || *n2 == ')'))
966 return (true);
967 if (*n1 != *n2)
968 break;
969 }
970 return (false);
971 }
972
973
974 static bool
getSpecial(desc,run,val)975 getSpecial(desc, run, val)
976
977 dataDesc *desc;
978 runDesc *run;
979 IFvalue *val;
980 {
981 IFvalue selector;
982 struct variable *vv;
983
984 selector.iValue = desc->specIndex;
985 if (INPaName(desc->specParamName, val, run->circuit, &desc->specType,
986 desc->specName, &desc->specFast, ft_sim, &desc->type,
987 &selector) == OK) {
988 desc->type &= (IF_REAL | IF_COMPLEX); /* mask out other bits */
989 return (true);
990 }
991 if (vv = if_getstat(run->circuit, &desc->name[1],
992 (wordlist **)NULL)) {
993 /* skip @ sign */
994 desc->type = IF_REAL;
995 if (vv->va_type == VT_REAL)
996 val->rValue = vv->va_real;
997 else if (vv->va_type == VT_NUM)
998 val->rValue = vv->va_num;
999 else if (vv->va_type == VT_BOOL)
1000 val->rValue = (vv->va_bool ? 1.0 : 0.0);
1001 else {
1002 return (false); /* not a real */
1003 }
1004 tfree(vv);
1005 return (true);
1006 }
1007 return (false);
1008 }
1009
1010
1011 static void
freeRun(run)1012 freeRun(run)
1013
1014 runDesc *run;
1015 {
1016
1017 int i;
1018
1019 for (i = 0; i < run->numData; i++) {
1020 txfree(run->data[i].name);
1021 txfree(run->data[i].specParamName);
1022 }
1023 txfree((char*)run->data);
1024 txfree(run->type);
1025 txfree(run->name);
1026 txfree((char*)run);
1027
1028 }
1029
1030
1031 int
OUTstopnow()1032 OUTstopnow()
1033 {
1034 static REQUEST reqst = { checkup_option, 0 };
1035
1036 if (!ft_batchmode)
1037 DevInput(&reqst, 0);
1038 if (ft_intrpt || shouldstop) {
1039 ft_intrpt = shouldstop = false;
1040 return (1);
1041 }
1042 else
1043 return (0);
1044 }
1045
1046
1047 /* Print out error messages. */
1048
1049 static struct mesg {
1050 char *string;
1051 long flag;
1052 } msgs[] = {
1053 { "Warning", ERR_WARNING } ,
1054 { "Fatal error", ERR_FATAL } ,
1055 { "Panic", ERR_PANIC } ,
1056 { "Note", ERR_INFO } ,
1057 { NULL, 0 }
1058 } ;
1059
1060
1061 int
OUTerror(flags,format,names)1062 OUTerror(flags,format,names)
1063
1064 int flags;
1065 char *format;
1066 IFuid *names;
1067 {
1068
1069 struct mesg *m;
1070 char buf[BSIZE_SP], *s, *bptr;
1071 int nindex = 0;
1072
1073 if ((flags == ERR_INFO) && !printinfo)
1074 return (OK);
1075
1076 for (m = msgs; m->flag; m++)
1077 if (flags & m->flag)
1078 fprintf(cp_err, "%s: ", m->string);
1079
1080 for (s = format, bptr = buf; *s; s++) {
1081 if (*s == '%' && (s == format || *(s-1) != '%') && *(s+1) == 's') {
1082 strcpy(bptr, names[nindex]);
1083 bptr += strlen(names[nindex]);
1084 s++;
1085 nindex++;
1086 }
1087 else {
1088 *bptr++ = *s;
1089 }
1090 }
1091 *bptr = '\0';
1092 fprintf(cp_err, "%s\n", buf);
1093 fflush(cp_err);
1094 return (OK);
1095 }
1096