1 /**********
2 Copyright 1990 Regents of the University of California.  All rights reserved.
3 Author: 1988 Wayne A. Christopher, U. C. Berkeley CAD Group
4 Modified: 2000 AlansFixes, 2013/2015 patch by Krzysztof Blaszkowski
5 **********/
6 
7 /*
8  * This module replaces the old "writedata" routines in nutmeg.
9  * Unlike the writedata routines, the OUT routines are only called by
10  * the simulator routines, and only call routines in nutmeg.  The rest
11  * of nutmeg doesn't deal with OUT at all.
12  */
13 
14 #include "ngspice/ngspice.h"
15 #include "ngspice/cpdefs.h"
16 #include "ngspice/ftedefs.h"
17 #include "ngspice/dvec.h"
18 #include "ngspice/plot.h"
19 #include "ngspice/sim.h"
20 #include "ngspice/inpdefs.h"        /* for INPtables */
21 #include "ngspice/ifsim.h"
22 #include "ngspice/jobdefs.h"
23 #include "ngspice/iferrmsg.h"
24 #include "circuits.h"
25 #include "outitf.h"
26 #include "variable.h"
27 #include <fcntl.h>
28 #include "ngspice/cktdefs.h"
29 #include "ngspice/inpdefs.h"
30 #include "breakp2.h"
31 #include "runcoms.h"
32 #include "plotting/graf.h"
33 #include "../misc/misc_time.h"
34 
35 extern char *spice_analysis_get_name(int index);
36 extern char *spice_analysis_get_description(int index);
37 extern int EVTsetup_plot(CKTcircuit* ckt, char* plotname);
38 
39 
40 static int beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analName,
41                      char *refName, int refType, int numNames, char **dataNames, int dataType,
42                      bool windowed, runDesc **runp);
43 static int addDataDesc(runDesc *run, char *name, int type, int ind, int meminit);
44 static int addSpecialDesc(runDesc *run, char *name, char *devname, char *param, int depind, int meminit);
45 static void fileInit(runDesc *run);
46 static void fileInit_pass2(runDesc *run);
47 static void fileStartPoint(FILE *fp, bool bin, int num);
48 static void fileAddRealValue(FILE *fp, bool bin, double value);
49 static void fileAddComplexValue(FILE *fp, bool bin, IFcomplex value);
50 static void fileEndPoint(FILE *fp, bool bin);
51 static void fileEnd(runDesc *run);
52 static void plotInit(runDesc *run);
53 static void plotAddRealValue(dataDesc *desc, double value);
54 static void plotAddComplexValue(dataDesc *desc, IFcomplex value);
55 static void plotEnd(runDesc *run);
56 static bool parseSpecial(char *name, char *dev, char *param, char *ind);
57 static bool name_eq(char *n1, char *n2);
58 static bool getSpecial(dataDesc *desc, runDesc *run, IFvalue *val);
59 static void freeRun(runDesc *run);
60 static int InterpFileAdd(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr);
61 static int InterpPlotAdd(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr);
62 
63 /*Output data to spice module*/
64 #ifdef TCL_MODULE
65 #include "ngspice/tclspice.h"
66 #elif defined SHARED_MODULE
67 extern int sh_ExecutePerLoop(void);
68 extern int sh_vecinit(runDesc *run);
69 #endif
70 
71 /*Suppressing progress info in -o option */
72 #ifndef HAS_WINGUI
73 extern bool orflag;
74 #endif
75 
76 // fixme
77 //   ugly hack to work around missing api to specify the "type" of signals
78 int fixme_onoise_type = SV_NOTYPE;
79 int fixme_inoise_type = SV_NOTYPE;
80 
81 
82 #define DOUBLE_PRECISION    15
83 
84 
85 static clock_t lastclock, currclock, startclock;
86 static double *rowbuf;
87 static size_t column, rowbuflen;
88 
89 static bool shouldstop = FALSE; /* Tell simulator to stop next time it asks. */
90 
91 static bool interpolated = FALSE;
92 static double *valueold, *valuenew;
93 
94 #ifdef SHARED_MODULE
95 static bool savenone = FALSE;
96 #endif
97 
98 /* The two "begin plot" routines share all their internals... */
99 
100 int
OUTpBeginPlot(CKTcircuit * circuitPtr,JOB * analysisPtr,IFuid analName,IFuid refName,int refType,int numNames,IFuid * dataNames,int dataType,runDesc ** plotPtr)101 OUTpBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr,
102               IFuid analName,
103               IFuid refName, int refType,
104               int numNames, IFuid *dataNames, int dataType, runDesc **plotPtr)
105 {
106     char *name;
107 
108     if (ft_curckt->ci_ckt == circuitPtr)
109         name = ft_curckt->ci_name;
110     else
111         name = "circuit name";
112 
113     return (beginPlot(analysisPtr, circuitPtr, name,
114                       analName, refName, refType, numNames,
115                       dataNames, dataType, FALSE,
116                       plotPtr));
117 }
118 
119 
120 int
OUTwBeginPlot(CKTcircuit * circuitPtr,JOB * analysisPtr,IFuid analName,IFuid refName,int refType,int numNames,IFuid * dataNames,int dataType,runDesc ** plotPtr)121 OUTwBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr,
122               IFuid analName,
123               IFuid refName, int refType,
124               int numNames, IFuid *dataNames, int dataType, runDesc **plotPtr)
125 {
126 
127     return (beginPlot(analysisPtr, circuitPtr, "circuit name",
128                       analName, refName, refType, numNames,
129                       dataNames, dataType, TRUE,
130                       plotPtr));
131 }
132 
133 
134 static int
beginPlot(JOB * analysisPtr,CKTcircuit * circuitPtr,char * cktName,char * analName,char * refName,int refType,int numNames,char ** dataNames,int dataType,bool windowed,runDesc ** runp)135 beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analName, char *refName, int refType, int numNames, char **dataNames, int dataType, bool windowed, runDesc **runp)
136 {
137     runDesc *run;
138     struct save_info *saves;
139     bool *savesused = NULL;
140     int numsaves;
141     int i, j, depind = 0;
142     char namebuf[BSIZE_SP], parambuf[BSIZE_SP], depbuf[BSIZE_SP];
143     char *ch, tmpname[BSIZE_SP];
144     bool saveall  = TRUE;
145     bool savealli = FALSE;
146     char *an_name;
147     int initmem;
148     /*to resume a run saj
149      *All it does is reassign the file pointer and return (requires *runp to be NULL if this is not needed)
150      */
151 
152     if (dataType == 666 && numNames == 666) {
153         run = *runp;
154         run->writeOut = ft_getOutReq(&run->fp, &run->runPlot, &run->binary,
155                                      run->type, run->name);
156 
157     } else {
158         /*end saj*/
159 
160         /* Check to see if we want to print informational data. */
161         if (cp_getvar("printinfo", CP_BOOL, NULL, 0))
162             fprintf(cp_err, "(debug printing enabled)\n");
163 
164         /* Check to see if we want to save only interpolated data. */
165         if (cp_getvar("interp", CP_BOOL, NULL, 0)) {
166             interpolated = TRUE;
167             fprintf(cp_out, "Warning: Interpolated raw file data!\n\n");
168         }
169 
170         *runp = run = TMALLOC(struct runDesc, 1);
171 
172         /* First fill in some general information. */
173         run->analysis = analysisPtr;
174         run->circuit = circuitPtr;
175         run->name = copy(cktName);
176         run->type = copy(analName);
177         run->windowed = windowed;
178         run->numData = 0;
179 
180         an_name = spice_analysis_get_name(analysisPtr->JOBtype);
181         ft_curckt->ci_last_an = an_name;
182 
183         /* Now let's see which of these things we need.  First toss in the
184          * reference vector.  Then toss in anything that getSaves() tells
185          * us to save that we can find in the name list.  Finally unpack
186          * the remaining saves into parameters.
187          */
188         numsaves = ft_getSaves(&saves);
189         if (numsaves) {
190             savesused = TMALLOC(bool, numsaves);
191             saveall = FALSE;
192             for (i = 0; i < numsaves; i++) {
193                 if (saves[i].analysis && !cieq(saves[i].analysis, an_name)) {
194                     /* ignore this one this time around */
195                     savesused[i] = TRUE;
196                     continue;
197                 }
198 
199                 /*  Check for ".save all" and new synonym ".save allv"  */
200 
201                 if (cieq(saves[i].name, "all") || cieq(saves[i].name, "allv")) {
202                     saveall = TRUE;
203                     savesused[i] = TRUE;
204                     saves[i].used = 1;
205                     continue;
206                 }
207 
208                 /*  And now for the new ".save alli" option  */
209 
210                 if (cieq(saves[i].name, "alli")) {
211                     savealli = TRUE;
212                     savesused[i] = TRUE;
213                     saves[i].used = 1;
214                     continue;
215                 }
216 #ifdef SHARED_MODULE
217                 /* this may happen if shared ngspice*/
218                 if (cieq(saves[i].name, "none")) {
219                     savenone = TRUE;
220                     saveall = TRUE;
221                     savesused[i] = TRUE;
222                     saves[i].used = 1;
223                     continue;
224                 }
225 #endif
226             }
227         }
228 
229         if (numsaves && !saveall)
230             initmem = numsaves;
231         else
232             initmem = numNames;
233 
234         /* Pass 0. */
235         if (refName) {
236             addDataDesc(run, refName, refType, -1, initmem);
237             for (i = 0; i < numsaves; i++)
238                 if (!savesused[i] && name_eq(saves[i].name, refName)) {
239                     savesused[i] = TRUE;
240                     saves[i].used = 1;
241                 }
242         } else {
243             run->refIndex = -1;
244         }
245 
246 
247         /* Pass 1. */
248         if (numsaves && !saveall) {
249             for (i = 0; i < numsaves; i++) {
250                 if (!savesused[i]) {
251                     for (j = 0; j < numNames; j++) {
252                         if (name_eq(saves[i].name, dataNames[j])) {
253                             addDataDesc(run, dataNames[j], dataType, j, initmem);
254                             savesused[i] = TRUE;
255                             saves[i].used = 1;
256                             break;
257                         }
258                         /* generate a vector of real time information */
259                         else if (ft_ngdebug && refName && eq(refName, "time") && eq(saves[i].name, "speedcheck")) {
260                             addDataDesc(run, "speedcheck", IF_REAL, j, initmem);
261                             savesused[i] = TRUE;
262                             saves[i].used = 1;
263                             break;
264                         }
265                     }
266                 }
267             }
268         } else {
269             for (i = 0; i < numNames; i++)
270                 if (!refName || !name_eq(dataNames[i], refName))
271                     /*  Save the node as long as it's an internal device node  */
272                     if (!strstr(dataNames[i], "#internal") &&
273                         !strstr(dataNames[i], "#source") &&
274                         !strstr(dataNames[i], "#drain") &&
275                         !strstr(dataNames[i], "#collector") &&
276                         !strstr(dataNames[i], "#emitter") &&
277                         !strstr(dataNames[i], "#base"))
278                     {
279                         addDataDesc(run, dataNames[i], dataType, i, initmem);
280                     }
281             /* generate a vector of real time information */
282             if (ft_ngdebug && refName && eq(refName, "time")) {
283                  addDataDesc(run, "speedcheck", IF_REAL, numNames, initmem);
284             }
285         }
286 
287         /* Pass 1 and a bit.
288            This is a new pass which searches for all the internal device
289            nodes, and saves the terminal currents instead  */
290 
291         if (savealli) {
292             depind = 0;
293             for (i = 0; i < numNames; i++) {
294                 if (strstr(dataNames[i], "#internal") ||
295                     strstr(dataNames[i], "#source") ||
296                     strstr(dataNames[i], "#drain") ||
297                     strstr(dataNames[i], "#collector") ||
298                     strstr(dataNames[i], "#emitter") ||
299                     strstr(dataNames[i], "#base"))
300                 {
301                     tmpname[0] = '@';
302                     tmpname[1] = '\0';
303                     strncat(tmpname, dataNames[i], BSIZE_SP-1);
304                     ch = strchr(tmpname, '#');
305 
306                     if (strstr(ch, "#collector")) {
307                         strcpy(ch, "[ic]");
308                     } else if (strstr(ch, "#base")) {
309                         strcpy(ch, "[ib]");
310                     } else if (strstr(ch, "#emitter")) {
311                         strcpy(ch, "[ie]");
312                         if (parseSpecial(tmpname, namebuf, parambuf, depbuf))
313                             addSpecialDesc(run, tmpname, namebuf, parambuf, depind, initmem);
314                         strcpy(ch, "[is]");
315                     } else if (strstr(ch, "#drain")) {
316                         strcpy(ch, "[id]");
317                         if (parseSpecial(tmpname, namebuf, parambuf, depbuf))
318                             addSpecialDesc(run, tmpname, namebuf, parambuf, depind, initmem);
319                         strcpy(ch, "[ig]");
320                     } else if (strstr(ch, "#source")) {
321                         strcpy(ch, "[is]");
322                         if (parseSpecial(tmpname, namebuf, parambuf, depbuf))
323                             addSpecialDesc(run, tmpname, namebuf, parambuf, depind, initmem);
324                         strcpy(ch, "[ib]");
325                     } else if (strstr(ch, "#internal") && (tmpname[1] == 'd')) {
326                         strcpy(ch, "[id]");
327                     } else {
328                         fprintf(cp_err,
329                                 "Debug: could output current for %s\n", tmpname);
330                         continue;
331                     }
332                     if (parseSpecial(tmpname, namebuf, parambuf, depbuf)) {
333                         if (*depbuf) {
334                             fprintf(stderr,
335                                     "Warning : unexpected dependent variable on %s\n", tmpname);
336                         } else {
337                             addSpecialDesc(run, tmpname, namebuf, parambuf, depind, initmem);
338                         }
339                     }
340                 }
341             }
342         }
343 
344 
345         /* Pass 2. */
346         for (i = 0; i < numsaves; i++) {
347 
348             if (savesused[i])
349                 continue;
350 
351             if (!parseSpecial(saves[i].name, namebuf, parambuf, depbuf)) {
352                 if (saves[i].analysis)
353                     fprintf(cp_err, "Warning: can't parse '%s': ignored\n",
354                             saves[i].name);
355                 continue;
356             }
357 
358             /* Now, if there's a dep variable, do we already have it? */
359             if (*depbuf) {
360                 for (j = 0; j < run->numData; j++)
361                     if (name_eq(depbuf, run->data[j].name))
362                         break;
363                 if (j == run->numData) {
364                     /* Better add it. */
365                     for (j = 0; j < numNames; j++)
366                         if (name_eq(depbuf, dataNames[j]))
367                             break;
368                     if (j == numNames) {
369                         fprintf(cp_err,
370                                 "Warning: can't find '%s': value '%s' ignored\n",
371                                 depbuf, saves[i].name);
372                         continue;
373                     }
374                     addDataDesc(run, dataNames[j], dataType, j, initmem);
375                     savesused[i] = TRUE;
376                     saves[i].used = 1;
377                     depind = j;
378                 } else {
379                     depind = run->data[j].outIndex;
380                 }
381             }
382 
383             addSpecialDesc(run, saves[i].name, namebuf, parambuf, depind, initmem);
384         }
385 
386         if (numsaves) {
387             for (i = 0; i < numsaves; i++) {
388                 tfree(saves[i].analysis);
389                 tfree(saves[i].name);
390             }
391             tfree(saves);
392             tfree(savesused);
393         }
394 
395         if (numNames &&
396             ((run->numData == 1 && run->refIndex != -1) ||
397              (run->numData == 0 && run->refIndex == -1)))
398         {
399             fprintf(cp_err, "Error: no data saved for %s; analysis not run\n",
400                     spice_analysis_get_description(analysisPtr->JOBtype));
401             return E_NOTFOUND;
402         }
403 
404         /* Now that we have our own data structures built up, let's see what
405          * nutmeg wants us to do.
406          */
407         run->writeOut = ft_getOutReq(&run->fp, &run->runPlot, &run->binary,
408                                      run->type, run->name);
409 
410         if (run->writeOut) {
411             fileInit(run);
412         } else {
413             plotInit(run);
414             if (refName)
415                 run->runPlot->pl_ndims = 1;
416 #ifdef XSPICE
417             /* set the current plot name into the event job */
418             if (run->runPlot->pl_typename)
419                 EVTsetup_plot(run->circuit, run->runPlot->pl_typename);
420 #endif
421         }
422     }
423 
424     /* define storage for old and new data, to allow interpolation */
425     if (interpolated && run->circuit->CKTcurJob->JOBtype == 4) {
426         valueold = TMALLOC(double, run->numData);
427         for (i = 0; i < run->numData; i++)
428             valueold[i] = 0.0;
429         valuenew = TMALLOC(double, run->numData);
430     }
431 
432     /*Start BLT, initilises the blt vectors saj*/
433 #ifdef TCL_MODULE
434     blt_init(run);
435 #elif defined SHARED_MODULE
436     sh_vecinit(run);
437 #endif
438 
439     startclock = clock();
440     return (OK);
441 }
442 
443 /* Initialze memory for the list of all vectors in the current plot.
444    Add a standard vector to this plot */
445 static int
addDataDesc(runDesc * run,char * name,int type,int ind,int meminit)446 addDataDesc(runDesc *run, char *name, int type, int ind, int meminit)
447 {
448     dataDesc *data;
449 
450     /* initialize memory (for all vectors or given by 'save') */
451     if (!run->numData) {
452         /* even if input 0, do a malloc */
453         run->data = TMALLOC(dataDesc, ++meminit);
454         run->maxData = meminit;
455     }
456     /* If there is need for more memory */
457     else if (run->numData == run->maxData) {
458         run->maxData = (int)(run->maxData * 1.1) + 1;
459         run->data = TREALLOC(dataDesc, run->data, run->maxData);
460     }
461 
462     data = &run->data[run->numData];
463     /* so freeRun will get nice NULL pointers for the fields we don't set */
464     memset(data, 0, sizeof(dataDesc));
465 
466     data->name = copy(name);
467     data->type = type;
468     data->gtype = GRID_LIN;
469     data->regular = TRUE;
470     data->outIndex = ind;
471 
472     /* It's the reference vector. */
473     if (ind == -1)
474         run->refIndex = run->numData;
475 
476     run->numData++;
477 
478     return (OK);
479 }
480 
481 /* Initialze memory for the list of all vectors in the current plot.
482    Add a special vector (e.g. @q1[ib]) to this plot */
483 static int
addSpecialDesc(runDesc * run,char * name,char * devname,char * param,int depind,int meminit)484 addSpecialDesc(runDesc *run, char *name, char *devname, char *param, int depind, int meminit)
485 {
486     dataDesc *data;
487     char *unique, *freeunique;       /* unique char * from back-end */
488     int ret;
489 
490     if (!run->numData) {
491         /* even if input 0, do a malloc */
492         run->data = TMALLOC(dataDesc, ++meminit);
493         run->maxData = meminit;
494     }
495     else if (run->numData == run->maxData) {
496         run->maxData = (int)(run->maxData * 1.1) + 1;
497         run->data = TREALLOC(dataDesc, run->data, run->maxData);
498     }
499 
500     data = &run->data[run->numData];
501     /* so freeRun will get nice NULL pointers for the fields we don't set */
502     memset(data, 0, sizeof(dataDesc));
503 
504     data->name = copy(name);
505 
506     freeunique = unique = copy(devname);
507 
508     /* unique will be overridden, if it already exists */
509     ret = INPinsertNofree(&unique, ft_curckt->ci_symtab);
510     data->specName = unique;
511 
512     if (ret == E_EXISTS)
513         tfree(freeunique);
514 
515     data->specParamName = copy(param);
516 
517     data->specIndex = depind;
518     data->specType = -1;
519     data->specFast = NULL;
520     data->regular = FALSE;
521 
522     run->numData++;
523 
524     return (OK);
525 }
526 
527 
528 static void
OUTpD_memory(runDesc * run,IFvalue * refValue,IFvalue * valuePtr)529 OUTpD_memory(runDesc *run, IFvalue *refValue, IFvalue *valuePtr)
530 {
531     int i, n = run->numData;
532 
533     for (i = 0; i < n; i++) {
534 
535         dataDesc *d;
536 
537 #ifdef TCL_MODULE
538         /*Locks the blt vector to stop access*/
539         blt_lockvec(i);
540 #endif
541 
542         d = &run->data[i];
543 
544         if (d->outIndex == -1) {
545             if (d->type == IF_REAL)
546                 plotAddRealValue(d, refValue->rValue);
547             else if (d->type == IF_COMPLEX)
548                 plotAddComplexValue(d, refValue->cValue);
549         } else if (d->regular) {
550             if (ft_ngdebug && d->type == IF_REAL && eq(d->name, "speedcheck")) {
551                 /* current time */
552                 clock_t cl = clock();
553                 double tt = ((double)cl - (double)startclock) / CLOCKS_PER_SEC;
554                 plotAddRealValue(d, tt);
555             }
556             else if (d->type == IF_REAL)
557                 plotAddRealValue(d, valuePtr->v.vec.rVec[d->outIndex]);
558             else if (d->type == IF_COMPLEX)
559                 plotAddComplexValue(d, valuePtr->v.vec.cVec[d->outIndex]);
560         } else {
561             IFvalue val;
562 
563             /* should pre-check instance */
564             if (!getSpecial(d, run, &val))
565                 continue;
566 
567             if (d->type == IF_REAL)
568                 plotAddRealValue(d, val.rValue);
569             else if (d->type == IF_COMPLEX)
570                 plotAddComplexValue(d, val.cValue);
571             else
572                 fprintf(stderr, "OUTpData: unsupported data type\n");
573         }
574 
575 #ifdef TCL_MODULE
576         /*relinks and unlocks vector*/
577         blt_relink(i, d->vec);
578 #endif
579 
580     }
581 }
582 
583 
584 int
OUTpData(runDesc * plotPtr,IFvalue * refValue,IFvalue * valuePtr)585 OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr)
586 {
587     runDesc *run = plotPtr;  // FIXME
588     int i;
589 
590     run->pointCount++;
591 
592 #ifdef TCL_MODULE
593     steps_completed = run->pointCount;
594 #endif
595     /* interpolated batch mode output to file/plot in transient analysis */
596     if (interpolated && run->circuit->CKTcurJob->JOBtype == 4) {
597         if (run->writeOut) { /* To file */
598             InterpFileAdd(run, refValue, valuePtr);
599         }
600         else { /* To plot */
601             InterpPlotAdd(run, refValue, valuePtr);
602         }
603         return OK;
604     }
605 
606     /* standard batch mode output to file */
607     else if (run->writeOut) {
608         if (run->pointCount == 1) {
609             fileInit_pass2(run);
610         }
611 
612         fileStartPoint(run->fp, run->binary, run->pointCount);
613 
614         if (run->refIndex != -1) {
615             if (run->isComplex) {
616                 fileAddComplexValue(run->fp, run->binary, refValue->cValue);
617 
618                 /*  While we're looking at the reference value, print it to the screen
619                     every quarter of a second, to give some feedback without using
620                     too much CPU time  */
621 #ifndef HAS_WINGUI
622                 if (!orflag && !ft_norefprint) {
623                     currclock = clock();
624                     if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) {
625                         fprintf(stderr, " Reference value : % 12.5e\r",
626                                 refValue->cValue.real);
627                         lastclock = currclock;
628                     }
629                 }
630 #endif
631             }
632             else { /* And the same for a non-complex (real) value  */
633                 fileAddRealValue(run->fp, run->binary, refValue->rValue);
634 #ifndef HAS_WINGUI
635                 if (!orflag && !ft_norefprint) {
636                     currclock = clock();
637                     if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) {
638                         fprintf(stderr, " Reference value : % 12.5e\r",
639                                 refValue->rValue);
640                         lastclock = currclock;
641                     }
642                 }
643 #endif
644             }
645         }
646 
647         for (i = 0; i < run->numData; i++) {
648             /* we've already printed reference vec first */
649             if (run->data[i].outIndex == -1) {
650                 continue;
651             }
652 
653 #ifdef TCL_MODULE
654             blt_add(i, refValue ? refValue->rValue : NAN);
655 #endif
656 
657             if (run->data[i].regular) {
658                 if (run->data[i].type == IF_REAL)
659                     fileAddRealValue(run->fp, run->binary,
660                             valuePtr->v.vec.rVec [run->data[i].outIndex]);
661                 else if (run->data[i].type == IF_COMPLEX)
662                     fileAddComplexValue(run->fp, run->binary,
663                             valuePtr->v.vec.cVec [run->data[i].outIndex]);
664                 else
665                     fprintf(stderr, "OUTpData: unsupported data type\n");
666             }
667             else {
668                 IFvalue val;
669                 /* should pre-check instance */
670                 if (!getSpecial(&run->data[i], run, &val)) {
671 
672                     /*  If this is the first data point, print a warning for any unrecognized
673                         variables, since this has not already been checked  */
674 
675                     if (run->pointCount == 1)
676                         fprintf(stderr, "Warning: unrecognized variable - %s\n",
677                                 run->data[i].name);
678 
679                     if (run->isComplex) {
680                         val.cValue.real = 0;
681                         val.cValue.imag = 0;
682                         fileAddComplexValue(run->fp, run->binary, val.cValue);
683                     }
684                     else {
685                         val.rValue = 0;
686                         fileAddRealValue(run->fp, run->binary, val.rValue);
687                     }
688 
689                     continue;
690                 }
691 
692                 if (run->data[i].type == IF_REAL)
693                     fileAddRealValue(run->fp, run->binary, val.rValue);
694                 else if (run->data[i].type == IF_COMPLEX)
695                     fileAddComplexValue(run->fp, run->binary, val.cValue);
696                 else
697                     fprintf(stderr, "OUTpData: unsupported data type\n");
698             }
699 
700 #ifdef TCL_MODULE
701             blt_add(i, valuePtr->v.vec.rVec [run->data[i].outIndex]);
702 #endif
703 
704         }
705 
706         fileEndPoint(run->fp, run->binary);
707 
708         /*  Check that the write to disk completed successfully, otherwise abort  */
709 
710         if (ferror(run->fp)) {
711             fprintf(stderr, "Warning: rawfile write error !!\n");
712             shouldstop = TRUE;
713         }
714 
715     }
716     else {
717         OUTpD_memory(run, refValue, valuePtr);
718 
719         /*  This is interactive mode. Update the screen with the reference
720             variable just the same  */
721 
722 #ifndef HAS_WINGUI
723         if (!orflag && !ft_norefprint) {
724             currclock = clock();
725             if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) {
726                 if (run->isComplex) {
727                     fprintf(stderr, " Reference value : % 12.5e\r",
728                             refValue ? refValue->cValue.real : NAN);
729                 } else {
730                     fprintf(stderr, " Reference value : % 12.5e\r",
731                             refValue ? refValue->rValue : NAN);
732                 }
733                 lastclock = currclock;
734             }
735         }
736 #endif
737 
738         gr_iplot(run->runPlot);
739     }
740 
741     if (ft_bpcheck(run->runPlot, run->pointCount) == FALSE)
742         shouldstop = TRUE;
743 
744 #ifdef TCL_MODULE
745     Tcl_ExecutePerLoop();
746 #elif defined SHARED_MODULE
747     sh_ExecutePerLoop();
748 #endif
749 
750     return OK;
751 } /* end of function OUTpData */
752 
753 
754 
OUTwReference(runDesc * plotPtr,IFvalue * valuePtr,void ** refPtr)755 int OUTwReference(runDesc*plotPtr, IFvalue *valuePtr, void **refPtr)
756 {
757     NG_IGNORE(refPtr);
758     NG_IGNORE(valuePtr);
759     NG_IGNORE(plotPtr);
760 
761     return OK;
762 }
763 
764 
765 int
OUTwData(runDesc * plotPtr,int dataIndex,IFvalue * valuePtr,void * refPtr)766 OUTwData(runDesc *plotPtr, int dataIndex, IFvalue *valuePtr, void *refPtr)
767 {
768     NG_IGNORE(refPtr);
769     NG_IGNORE(valuePtr);
770     NG_IGNORE(dataIndex);
771     NG_IGNORE(plotPtr);
772 
773     return OK;
774 }
775 
776 
777 int
OUTwEnd(runDesc * plotPtr)778 OUTwEnd(runDesc *plotPtr)
779 {
780     NG_IGNORE(plotPtr);
781 
782     return OK;
783 }
784 
785 
786 int
OUTendPlot(runDesc * plotPtr)787 OUTendPlot(runDesc *plotPtr)
788 {
789     if (plotPtr->writeOut) {
790         fileEnd(plotPtr);
791     } else {
792         gr_end_iplot();
793         plotEnd(plotPtr);
794     }
795 
796     tfree(valueold);
797     tfree(valuenew);
798 
799     freeRun(plotPtr);
800 
801     return (OK);
802 }
803 
804 
805 int
OUTbeginDomain(runDesc * plotPtr,IFuid refName,int refType,IFvalue * outerRefValue)806 OUTbeginDomain(runDesc *plotPtr, IFuid refName, int refType, IFvalue *outerRefValue)
807 {
808     NG_IGNORE(outerRefValue);
809     NG_IGNORE(refType);
810     NG_IGNORE(refName);
811     NG_IGNORE(plotPtr);
812 
813     return (OK);
814 }
815 
816 
817 int
OUTendDomain(runDesc * plotPtr)818 OUTendDomain(runDesc *plotPtr)
819 {
820     NG_IGNORE(plotPtr);
821 
822     return (OK);
823 }
824 
825 
826 int
OUTattributes(runDesc * plotPtr,IFuid varName,int param,IFvalue * value)827 OUTattributes(runDesc *plotPtr, IFuid varName, int param, IFvalue *value)
828 {
829     runDesc *run = plotPtr;  // FIXME
830     GRIDTYPE type;
831 
832     struct dvec *d;
833 
834     NG_IGNORE(value);
835 
836     if (param == OUT_SCALE_LIN)
837         type = GRID_LIN;
838     else if (param == OUT_SCALE_LOG)
839         type = GRID_XLOG;
840     else
841         return E_UNSUPP;
842 
843     if (run->writeOut) {
844         if (varName) {
845             int i;
846             for (i = 0; i < run->numData; i++)
847                 if (!strcmp(varName, run->data[i].name))
848                     run->data[i].gtype = type;
849         } else {
850             run->data[run->refIndex].gtype = type;
851         }
852     } else {
853         if (varName) {
854             for (d = run->runPlot->pl_dvecs; d; d = d->v_next)
855                 if (!strcmp(varName, d->v_name))
856                     d->v_gridtype = type;
857         } else if (param == PLOT_COMB) {
858             for (d = run->runPlot->pl_dvecs; d; d = d->v_next)
859                 d->v_plottype = PLOT_COMB;
860         } else {
861             run->runPlot->pl_scale->v_gridtype = type;
862         }
863     }
864 
865     return (OK);
866 }
867 
868 
869 /* The file writing routines.
870    Write a raw file in batch mode (-b and -r flags).
871    Writing a raw file in interactive or control  mode is handled
872    by raw_write() in rawfile.c */
873 static void
fileInit(runDesc * run)874 fileInit(runDesc *run)
875 {
876     char buf[513];
877     int i;
878     size_t n;
879 
880     lastclock = clock();
881 
882     /* This is a hack. */
883     run->isComplex = FALSE;
884     for (i = 0; i < run->numData; i++)
885         if (run->data[i].type == IF_COMPLEX)
886             run->isComplex = TRUE;
887 
888     n = 0;
889     sprintf(buf, "Title: %s\n", run->name);
890     n += strlen(buf);
891     fputs(buf, run->fp);
892     sprintf(buf, "Date: %s\n", datestring());
893     n += strlen(buf);
894     fputs(buf, run->fp);
895     sprintf(buf, "Plotname: %s\n", run->type);
896     n += strlen(buf);
897     fputs(buf, run->fp);
898     sprintf(buf, "Flags: %s\n", run->isComplex ? "complex" : "real");
899     n += strlen(buf);
900     fputs(buf, run->fp);
901     sprintf(buf, "No. Variables: %d\n", run->numData);
902     n += strlen(buf);
903     fputs(buf, run->fp);
904     sprintf(buf, "No. Points: ");
905     n += strlen(buf);
906     fputs(buf, run->fp);
907 
908     fflush(run->fp);        /* Gotta do this for LATTICE. */
909     if (run->fp == stdout || (run->pointPos = ftell(run->fp)) <= 0)
910         run->pointPos = (long) n;
911     fprintf(run->fp, "0       \n"); /* Save 8 spaces here. */
912 
913     /*fprintf(run->fp, "Command: version %s\n", ft_sim->version);*/
914     fprintf(run->fp, "Variables:\n");
915 
916     printf("No. of Data Columns : %d  \n", run->numData);
917 }
918 
919 
920 static int
guess_type(const char * name)921 guess_type(const char *name)
922 {
923     int type;
924 
925     if (substring("#branch", name))
926         type = SV_CURRENT;
927     else if (cieq(name, "time"))
928         type = SV_TIME;
929     else if ( cieq(name, "speedcheck"))
930         type = SV_TIME;
931     else if (cieq(name, "frequency"))
932         type = SV_FREQUENCY;
933     else if (ciprefix("inoise", name))
934         type = fixme_inoise_type;
935     else if (ciprefix("onoise", name))
936         type = fixme_onoise_type;
937     else if (cieq(name, "temp-sweep"))
938         type = SV_TEMP;
939     else if (cieq(name, "res-sweep"))
940         type = SV_RES;
941     else if (cieq(name, "i-sweep"))
942         type = SV_CURRENT;
943     else if ((*name == '@') && substring("[g", name)) /* token starting with [g */
944         type = SV_ADMITTANCE;
945     else if ((*name == '@') && substring("[c", name))
946         type = SV_CAPACITANCE;
947     else if ((*name == '@') && substring("[i", name))
948         type = SV_CURRENT;
949     else if ((*name == '@') && substring("[q", name))
950         type = SV_CHARGE;
951     else if ((*name == '@') && substring("[p]", name)) /* token is exactly [p] */
952         type = SV_POWER;
953     else
954         type = SV_VOLTAGE;
955 
956     return type;
957 }
958 
959 
960 static void
fileInit_pass2(runDesc * run)961 fileInit_pass2(runDesc *run)
962 {
963     int i, type;
964 
965     for (i = 0; i < run->numData; i++) {
966 
967         char *name = run->data[i].name;
968 
969         type = guess_type(name);
970 
971         if (type == SV_CURRENT) {
972             char *branch = strstr(name, "#branch");
973             if (branch)
974                 *branch = '\0';
975             fprintf(run->fp, "\t%d\ti(%s)\t%s", i, name, ft_typenames(type));
976             if (branch)
977                 *branch = '#';
978         } else if (type == SV_VOLTAGE) {
979             fprintf(run->fp, "\t%d\tv(%s)\t%s", i, name, ft_typenames(type));
980         } else {
981             fprintf(run->fp, "\t%d\t%s\t%s", i, name, ft_typenames(type));
982         }
983 
984         if (run->data[i].gtype == GRID_XLOG)
985             fprintf(run->fp, "\tgrid=3");
986 
987         fprintf(run->fp, "\n");
988     }
989 
990     fprintf(run->fp, "%s:\n", run->binary ? "Binary" : "Values");
991     fflush(run->fp);
992 
993     /*  Allocate Row buffer  */
994 
995     if (run->binary) {
996         rowbuflen = (size_t) (run->numData);
997         if (run->isComplex)
998             rowbuflen *= 2;
999         rowbuf = TMALLOC(double, rowbuflen);
1000     } else {
1001         rowbuflen = 0;
1002         rowbuf = NULL;
1003     }
1004 }
1005 
1006 
1007 static void
fileStartPoint(FILE * fp,bool bin,int num)1008 fileStartPoint(FILE *fp, bool bin, int num)
1009 {
1010     if (!bin)
1011         fprintf(fp, "%d\t", num - 1);
1012 
1013     /*  reset buffer pointer to zero  */
1014 
1015     column = 0;
1016 }
1017 
1018 
1019 static void
fileAddRealValue(FILE * fp,bool bin,double value)1020 fileAddRealValue(FILE *fp, bool bin, double value)
1021 {
1022     if (bin)
1023         rowbuf[column++] = value;
1024     else
1025         fprintf(fp, "\t%.*e\n", DOUBLE_PRECISION, value);
1026 }
1027 
1028 
1029 static void
fileAddComplexValue(FILE * fp,bool bin,IFcomplex value)1030 fileAddComplexValue(FILE *fp, bool bin, IFcomplex value)
1031 {
1032     if (bin) {
1033         rowbuf[column++] = value.real;
1034         rowbuf[column++] = value.imag;
1035     } else {
1036         fprintf(fp, "\t%.*e,%.*e\n", DOUBLE_PRECISION, value.real,
1037                 DOUBLE_PRECISION, value.imag);
1038     }
1039 }
1040 
1041 
1042 static void
fileEndPoint(FILE * fp,bool bin)1043 fileEndPoint(FILE *fp, bool bin)
1044 {
1045     /*  write row buffer to file  */
1046     /* otherwise the data has already been written */
1047 
1048     if (bin)
1049         fwrite(rowbuf, sizeof(double), rowbuflen, fp);
1050 }
1051 
1052 
1053 /* Here's the hack...  Run back and fill in the number of points. */
1054 
1055 static void
fileEnd(runDesc * run)1056 fileEnd(runDesc *run)
1057 {
1058     if (run->fp != stdout) {
1059         long place = ftell(run->fp);
1060         fseek(run->fp, run->pointPos, SEEK_SET);
1061         fprintf(run->fp, "%d", run->pointCount);
1062         fprintf(stdout, "\nNo. of Data Rows : %d\n", run->pointCount);
1063         fseek(run->fp, place, SEEK_SET);
1064     } else {
1065         /* Yet another hack-around */
1066         fprintf(stderr, "@@@ %ld %d\n", run->pointPos, run->pointCount);
1067     }
1068 
1069     fflush(run->fp);
1070 
1071     tfree(rowbuf);
1072 }
1073 
1074 
1075 /* The plot maintenance routines. */
1076 
1077 static void
plotInit(runDesc * run)1078 plotInit(runDesc *run)
1079 {
1080     struct plot *pl = plot_alloc(run->type);
1081     struct dvec *v;
1082     int i;
1083 
1084     pl->pl_title = copy(run->name);
1085     pl->pl_name = copy(run->type);
1086     pl->pl_date = copy(datestring());
1087     pl->pl_ndims = 0;
1088     plot_new(pl);
1089     plot_setcur(pl->pl_typename);
1090     run->runPlot = pl;
1091 
1092     /* This is a hack. */
1093     /* if any of them complex, make them all complex */
1094     run->isComplex = FALSE;
1095     for (i = 0; i < run->numData; i++)
1096         if (run->data[i].type == IF_COMPLEX)
1097             run->isComplex = TRUE;
1098 
1099     for (i = 0; i < run->numData; i++) {
1100         dataDesc *dd = &run->data[i];
1101         char *name;
1102 
1103         if (isdigit_c(dd->name[0]))
1104             name = tprintf("V(%s)", dd->name);
1105         else
1106             name = copy(dd->name);
1107 
1108         v = dvec_alloc(name,
1109                        guess_type(name),
1110                        run->isComplex
1111                        ? (VF_COMPLEX | VF_PERMANENT)
1112                        : (VF_REAL | VF_PERMANENT),
1113                        0, NULL);
1114 
1115         vec_new(v);
1116         dd->vec = v;
1117     }
1118 }
1119 
1120 /* prepare the vector length data for memory allocation
1121    If new, and tran or pss, length is TSTOP / TSTEP plus some margin.
1122    If allocated length is exceeded, check progress. When > 20% then extrapolate memory needed,
1123    if less than 20% then just double the size.
1124    If not tran or pss, return fixed value (1024) of memory to be added.
1125    */
1126 static inline int
vlength2delta(int len)1127 vlength2delta(int len)
1128 {
1129 #ifdef SHARED_MODULE
1130     if (savenone)
1131         /* We need just a vector length of 1 */
1132         return 1;
1133 #endif
1134     /* TSTOP / TSTEP */
1135     int points = ft_curckt->ci_ckt->CKTtimeListSize;
1136     /* transient and pss analysis (points > 0) upon start */
1137     if (len == 0 && points > 0) {
1138         /* number of timesteps plus some overhead */
1139         return points + 100;
1140     }
1141     /* transient and pss if original estimate is exceeded */
1142     else if (points > 0) {
1143         /* check where we are */
1144         double timerel = ft_curckt->ci_ckt->CKTtime / ft_curckt->ci_ckt->CKTfinalTime;
1145         /* return an estimate of the appropriate number of time points, if more than 20% of
1146            the anticipated total time has passed */
1147         if (timerel > 0.2)
1148             return (int)(len / timerel) - len + 1;
1149         /* If not, just double the available memory */
1150         else
1151             return len;
1152     }
1153     /* other analysis types that do not set CKTtimeListSize */
1154     else
1155         return 1024;
1156 }
1157 
1158 
1159 static void
plotAddRealValue(dataDesc * desc,double value)1160 plotAddRealValue(dataDesc *desc, double value)
1161 {
1162     struct dvec *v = desc->vec;
1163 
1164 #ifdef SHARED_MODULE
1165     if (savenone)
1166         /* always save new data to same location */
1167         v->v_length = 0;
1168 #endif
1169 
1170     if (v->v_length >= v->v_alloc_length)
1171         dvec_extend(v, v->v_length + vlength2delta(v->v_length));
1172 
1173     if (isreal(v)) {
1174         v->v_realdata[v->v_length] = value;
1175     } else {
1176         /* a real parading as a VF_COMPLEX */
1177         v->v_compdata[v->v_length].cx_real = value;
1178         v->v_compdata[v->v_length].cx_imag = 0.0;
1179     }
1180 
1181     v->v_length++;
1182     v->v_dims[0] = v->v_length; /* va, must be updated */
1183 }
1184 
1185 
1186 static void
plotAddComplexValue(dataDesc * desc,IFcomplex value)1187 plotAddComplexValue(dataDesc *desc, IFcomplex value)
1188 {
1189     struct dvec *v = desc->vec;
1190 
1191 #ifdef SHARED_MODULE
1192     if (savenone)
1193         v->v_length = 0;
1194 #endif
1195 
1196     if (v->v_length >= v->v_alloc_length)
1197         dvec_extend(v, v->v_length + vlength2delta(v->v_length));
1198 
1199     v->v_compdata[v->v_length].cx_real = value.real;
1200     v->v_compdata[v->v_length].cx_imag = value.imag;
1201 
1202     v->v_length++;
1203     v->v_dims[0] = v->v_length; /* va, must be updated */
1204 }
1205 
1206 
1207 static void
plotEnd(runDesc * run)1208 plotEnd(runDesc *run)
1209 {
1210     fprintf(stdout, "\nNo. of Data Rows : %d\n", run->pointCount);
1211 }
1212 
1213 
1214 /* ParseSpecial takes something of the form "@name[param,index]" and rips
1215  * out name, param, andstrchr.
1216  */
1217 
1218 static bool
parseSpecial(char * name,char * dev,char * param,char * ind)1219 parseSpecial(char *name, char *dev, char *param, char *ind)
1220 {
1221     char *s;
1222 
1223     *dev = *param = *ind = '\0';
1224 
1225     if (*name != '@')
1226         return FALSE;
1227     name++;
1228 
1229     s = dev;
1230     while (*name && (*name != '['))
1231         *s++ = *name++;
1232     *s = '\0';
1233 
1234     if (!*name)
1235         return TRUE;
1236     name++;
1237 
1238     s = param;
1239     while (*name && (*name != ',') && (*name != ']'))
1240         *s++ = *name++;
1241     *s = '\0';
1242 
1243     if (*name == ']')
1244         return (!name[1] ? TRUE : FALSE);
1245     else if (!*name)
1246         return FALSE;
1247     name++;
1248 
1249     s = ind;
1250     while (*name && (*name != ']'))
1251         *s++ = *name++;
1252     *s = '\0';
1253 
1254     if (*name && !name[1])
1255         return TRUE;
1256     else
1257         return FALSE;
1258 }
1259 
1260 
1261 /* This routine must match two names with or without a V() around them. */
1262 
1263 static bool
name_eq(char * n1,char * n2)1264 name_eq(char *n1, char *n2)
1265 {
1266     char buf1[BSIZE_SP], buf2[BSIZE_SP], *s;
1267 
1268     if ((s = strchr(n1, '(')) != NULL) {
1269         strcpy(buf1, s);
1270         if ((s = strchr(buf1, ')')) == NULL)
1271             return FALSE;
1272         *s = '\0';
1273         n1 = buf1;
1274     }
1275 
1276     if ((s = strchr(n2, '(')) != NULL) {
1277         strcpy(buf2, s);
1278         if ((s = strchr(buf2, ')')) == NULL)
1279             return FALSE;
1280         *s = '\0';
1281         n2 = buf2;
1282     }
1283 
1284     return (strcmp(n1, n2) ? FALSE : TRUE);
1285 }
1286 
1287 
1288 static bool
getSpecial(dataDesc * desc,runDesc * run,IFvalue * val)1289 getSpecial(dataDesc *desc, runDesc *run, IFvalue *val)
1290 {
1291     IFvalue selector;
1292     struct variable *vv;
1293 
1294     selector.iValue = desc->specIndex;
1295     if (INPaName(desc->specParamName, val, run->circuit, &desc->specType,
1296                  desc->specName, &desc->specFast, ft_sim, &desc->type,
1297                  &selector) == OK) {
1298         desc->type &= (IF_REAL | IF_COMPLEX);   /* mask out other bits */
1299         return TRUE;
1300     }
1301 
1302     if ((vv = if_getstat(run->circuit, &desc->name[1])) != NULL) {
1303         /* skip @ sign */
1304         desc->type = IF_REAL;
1305         if (vv->va_type == CP_REAL)
1306             val->rValue = vv->va_real;
1307         else if (vv->va_type == CP_NUM)
1308             val->rValue = vv->va_num;
1309         else if (vv->va_type == CP_BOOL)
1310             val->rValue = (vv->va_bool ? 1.0 : 0.0);
1311         else
1312             return FALSE; /* not a real */
1313         tfree(vv);
1314         return TRUE;
1315     }
1316 
1317     return FALSE;
1318 }
1319 
1320 
1321 static void
freeRun(runDesc * run)1322 freeRun(runDesc *run)
1323 {
1324     int i;
1325 
1326     for (i = 0; i < run->numData; i++) {
1327         tfree(run->data[i].name);
1328         tfree(run->data[i].specParamName);
1329     }
1330 
1331     tfree(run->data);
1332     tfree(run->type);
1333     tfree(run->name);
1334 
1335     tfree(run);
1336 }
1337 
1338 
1339 int
OUTstopnow(void)1340 OUTstopnow(void)
1341 {
1342     if (ft_intrpt || shouldstop) {
1343         ft_intrpt = shouldstop = FALSE;
1344         return (1);
1345     }
1346 
1347     return (0);
1348 }
1349 
1350 
1351 /* Print out error messages. */
1352 
1353 static struct mesg {
1354     char *string;
1355     long flag;
1356 } msgs[] = {
1357     { "Warning", ERR_WARNING } ,
1358     { "Fatal error", ERR_FATAL } ,
1359     { "Panic", ERR_PANIC } ,
1360     { "Note", ERR_INFO } ,
1361     { NULL, 0 }
1362 };
1363 
1364 
1365 void
OUTerror(int flags,char * format,IFuid * names)1366 OUTerror(int flags, char *format, IFuid *names)
1367 {
1368     struct mesg *m;
1369     char buf[BSIZE_SP], *s, *bptr;
1370     int nindex = 0;
1371 
1372     if ((flags == ERR_INFO) && cp_getvar("printinfo", CP_BOOL, NULL, 0))
1373         return;
1374 
1375     for (m = msgs; m->flag; m++)
1376         if (flags & m->flag)
1377             fprintf(cp_err, "%s: ", m->string);
1378 
1379     for (s = format, bptr = buf; *s; s++) {
1380         if (*s == '%' && (s == format || s[-1] != '%') && s[1] == 's') {
1381             if (names[nindex])
1382                 strcpy(bptr, names[nindex]);
1383             else
1384                 strcpy(bptr, "(null)");
1385             bptr += strlen(bptr);
1386             s++;
1387             nindex++;
1388         } else {
1389             *bptr++ = *s;
1390         }
1391     }
1392 
1393     *bptr = '\0';
1394     fprintf(cp_err, "%s\n", buf);
1395     fflush(cp_err);
1396 }
1397 
1398 
1399 void
OUTerrorf(int flags,const char * format,...)1400 OUTerrorf(int flags, const char *format, ...)
1401 {
1402     struct mesg *m;
1403     va_list args;
1404 
1405     if ((flags == ERR_INFO) && cp_getvar("printinfo", CP_BOOL, NULL, 0))
1406         return;
1407 
1408     for (m = msgs; m->flag; m++)
1409         if (flags & m->flag)
1410             fprintf(cp_err, "%s: ", m->string);
1411 
1412     va_start (args, format);
1413 
1414     vfprintf(cp_err, format, args);
1415     fputc('\n', cp_err);
1416 
1417     fflush(cp_err);
1418 
1419     va_end(args);
1420 }
1421 
1422 
1423 static int
InterpFileAdd(runDesc * run,IFvalue * refValue,IFvalue * valuePtr)1424 InterpFileAdd(runDesc *run, IFvalue *refValue, IFvalue *valuePtr)
1425 {
1426     int i;
1427     static double timeold = 0.0, timenew = 0.0, timestep = 0.0;
1428     bool nodata = FALSE;
1429     bool interpolatenow = FALSE;
1430 
1431     if (run->pointCount == 1) {
1432         fileInit_pass2(run);
1433         timestep = run->circuit->CKTinitTime + run->circuit->CKTstep;
1434     }
1435 
1436     if (run->refIndex != -1) {
1437         /*  Save first time step  */
1438         if (refValue->rValue == run->circuit->CKTinitTime) {
1439             timeold = refValue->rValue;
1440             fileStartPoint(run->fp, run->binary, run->pointCount);
1441             fileAddRealValue(run->fp, run->binary, run->circuit->CKTinitTime);
1442             interpolatenow = nodata = FALSE;
1443         }
1444         /*  Save last time step  */
1445         else if (refValue->rValue == run->circuit->CKTfinalTime) {
1446             timeold = refValue->rValue;
1447             fileStartPoint(run->fp, run->binary, run->pointCount);
1448             fileAddRealValue(run->fp, run->binary, run->circuit->CKTfinalTime);
1449             interpolatenow = nodata = FALSE;
1450         }
1451         /*  Save exact point  */
1452         else if (refValue->rValue == timestep) {
1453             timeold = refValue->rValue;
1454             fileStartPoint(run->fp, run->binary, run->pointCount);
1455             fileAddRealValue(run->fp, run->binary, timestep);
1456             timestep += run->circuit->CKTstep;
1457             interpolatenow = nodata = FALSE;
1458         }
1459         else if (refValue->rValue > timestep) {
1460             /* add the next time step value to the vector */
1461             fileStartPoint(run->fp, run->binary, run->pointCount);
1462             timenew = refValue->rValue;
1463             fileAddRealValue(run->fp, run->binary, timestep);
1464             timestep += run->circuit->CKTstep;
1465             nodata = FALSE;
1466             interpolatenow = TRUE;
1467         }
1468         else {
1469             /* Do not save this step */
1470             run->pointCount--;
1471             timeold = refValue->rValue;
1472             nodata = TRUE;
1473             interpolatenow = FALSE;
1474         }
1475 #ifndef HAS_WINGUI
1476         if (!orflag && !ft_norefprint) {
1477             currclock = clock();
1478             if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) {
1479                 fprintf(stderr, " Reference value : % 12.5e\r",
1480                         refValue->rValue);
1481                 lastclock = currclock;
1482             }
1483         }
1484 #endif
1485 
1486     }
1487 
1488     for (i = 0; i < run->numData; i++) {
1489         /* we've already printed reference vec first */
1490         if (run->data[i].outIndex == -1)
1491             continue;
1492 
1493 #ifdef TCL_MODULE
1494         blt_add(i, refValue ? refValue->rValue : NAN);
1495 #endif
1496 
1497         if (run->data[i].regular) {
1498         /*  Store value or interpolate and store or do not store any value to file */
1499             if (!interpolatenow && !nodata) {
1500                 /* store the first or last value */
1501                 valueold[i] = valuePtr->v.vec.rVec [run->data[i].outIndex];
1502                 fileAddRealValue(run->fp, run->binary, valueold[i]);
1503             }
1504             else if (interpolatenow) {
1505             /*  Interpolate time if actual time is greater than proposed next time step  */
1506                 double newval;
1507                 valuenew[i] = valuePtr->v.vec.rVec [run->data[i].outIndex];
1508                 newval = (timestep -  run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
1509                 fileAddRealValue(run->fp, run->binary, newval);
1510                 valueold[i] = valuenew[i];
1511             }
1512             else if (nodata)
1513                 /* Just keep the transient output value corresponding to timeold,
1514                     but do not store to file */
1515                 valueold[i] = valuePtr->v.vec.rVec [run->data[i].outIndex];
1516         } else {
1517             IFvalue val;
1518             /* should pre-check instance */
1519             if (!getSpecial(&run->data[i], run, &val)) {
1520 
1521                 /*  If this is the first data point, print a warning for any unrecognized
1522                     variables, since this has not already been checked  */
1523                 if (run->pointCount == 1)
1524                 fprintf(stderr, "Warning: unrecognized variable - %s\n",
1525                         run->data[i].name);
1526                 val.rValue = 0;
1527                 fileAddRealValue(run->fp, run->binary, val.rValue);
1528                 continue;
1529             }
1530             if (!interpolatenow && !nodata) {
1531                 /* store the first or last value */
1532                 valueold[i] = val.rValue;
1533                 fileAddRealValue(run->fp, run->binary, valueold[i]);
1534             }
1535             else if (interpolatenow) {
1536             /*  Interpolate time if actual time is greater than proposed next time step  */
1537                 double newval;
1538                 valuenew[i] = val.rValue;
1539                 newval = (timestep -  run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
1540                 fileAddRealValue(run->fp, run->binary, newval);
1541                 valueold[i] = valuenew[i];
1542             }
1543             else if (nodata)
1544                 /* Just keep the transient output value corresponding to timeold,
1545                     but do not store to file */
1546                 valueold[i] = val.rValue;
1547         }
1548 
1549 #ifdef TCL_MODULE
1550         blt_add(i, valuePtr->v.vec.rVec [run->data[i].outIndex]);
1551 #endif
1552 
1553     }
1554 
1555     fileEndPoint(run->fp, run->binary);
1556 
1557     /*  Check that the write to disk completed successfully, otherwise abort  */
1558     if (ferror(run->fp)) {
1559         fprintf(stderr, "Warning: rawfile write error !!\n");
1560         shouldstop = TRUE;
1561     }
1562 
1563     if (ft_bpcheck(run->runPlot, run->pointCount) == FALSE)
1564         shouldstop = TRUE;
1565 
1566 #ifdef TCL_MODULE
1567     Tcl_ExecutePerLoop();
1568 #elif defined SHARED_MODULE
1569     sh_ExecutePerLoop();
1570 #endif
1571     return(OK);
1572 }
1573 
1574 static int
InterpPlotAdd(runDesc * run,IFvalue * refValue,IFvalue * valuePtr)1575 InterpPlotAdd(runDesc *run, IFvalue *refValue, IFvalue *valuePtr)
1576 {
1577     int i, iscale = -1;
1578     static double timeold = 0.0, timenew = 0.0, timestep = 0.0;
1579     bool nodata = FALSE;
1580     bool interpolatenow = FALSE;
1581 
1582     if (run->pointCount == 1)
1583         timestep = run->circuit->CKTinitTime + run->circuit->CKTstep;
1584 
1585     /* find the scale vector */
1586     for (i = 0; i < run->numData; i++)
1587         if (run->data[i].outIndex == -1) {
1588             iscale = i;
1589             break;
1590         }
1591     if (iscale == -1)
1592         fprintf(stderr, "Error: no scale vector found\n");
1593 
1594 #ifdef TCL_MODULE
1595     /*Locks the blt vector to stop access*/
1596     blt_lockvec(iscale);
1597 #endif
1598 
1599     /*  Save first time step  */
1600     if (refValue->rValue == run->circuit->CKTinitTime) {
1601         timeold = refValue->rValue;
1602         plotAddRealValue(&run->data[iscale], refValue->rValue);
1603         interpolatenow = nodata = FALSE;
1604     }
1605     /*  Save last time step  */
1606     else if (refValue->rValue == run->circuit->CKTfinalTime) {
1607         timeold = refValue->rValue;
1608         plotAddRealValue(&run->data[iscale], run->circuit->CKTfinalTime);
1609         interpolatenow = nodata = FALSE;
1610     }
1611     /*  Save exact point  */
1612     else if (refValue->rValue == timestep) {
1613         timeold = refValue->rValue;
1614         plotAddRealValue(&run->data[iscale], timestep);
1615         timestep += run->circuit->CKTstep;
1616         interpolatenow = nodata = FALSE;
1617     }
1618     else if (refValue->rValue > timestep) {
1619         /* add the next time step value to the vector */
1620         timenew = refValue->rValue;
1621         plotAddRealValue(&run->data[iscale], timestep);
1622         timestep += run->circuit->CKTstep;
1623         nodata = FALSE;
1624         interpolatenow = TRUE;
1625     }
1626     else {
1627         /* Do not save this step */
1628         run->pointCount--;
1629         timeold = refValue->rValue;
1630         nodata = TRUE;
1631         interpolatenow = FALSE;
1632     }
1633 
1634 #ifdef TCL_MODULE
1635     /*relinks and unlocks vector*/
1636     blt_relink(iscale, (run->data[iscale]).vec);
1637 #endif
1638 
1639 #ifndef HAS_WINGUI
1640     if (!orflag && !ft_norefprint) {
1641         currclock = clock();
1642         if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) {
1643             fprintf(stderr, " Reference value : % 12.5e\r",
1644                     refValue->rValue);
1645             lastclock = currclock;
1646         }
1647     }
1648 #endif
1649 
1650     for (i = 0; i < run->numData; i++) {
1651         if (i == iscale)
1652             continue;
1653 
1654 #ifdef TCL_MODULE
1655         /*Locks the blt vector to stop access*/
1656         blt_lockvec(i);
1657 #endif
1658 
1659         if (run->data[i].regular) {
1660         /*  Store value or interpolate and store or do not store any value to file */
1661             if (!interpolatenow && !nodata) {
1662                 /* store the first or last value */
1663                 valueold[i] = valuePtr->v.vec.rVec [run->data[i].outIndex];
1664                 plotAddRealValue(&run->data[i], valueold[i]);
1665             }
1666             else if (interpolatenow) {
1667             /*  Interpolate time if actual time is greater than proposed next time step  */
1668                 double newval;
1669                 valuenew[i] = valuePtr->v.vec.rVec [run->data[i].outIndex];
1670                 newval = (timestep -  run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
1671                 plotAddRealValue(&run->data[i], newval);
1672                 valueold[i] = valuenew[i];
1673             }
1674             else if (nodata)
1675                 /* Just keep the transient output value corresponding to timeold,
1676                     but do not store to file */
1677                 valueold[i] = valuePtr->v.vec.rVec [run->data[i].outIndex];
1678         } else {
1679             IFvalue val;
1680             /* should pre-check instance */
1681             if (!getSpecial(&run->data[i], run, &val))
1682                 continue;
1683             if (!interpolatenow && !nodata) {
1684                 /* store the first or last value */
1685                 valueold[i] = val.rValue;
1686                 plotAddRealValue(&run->data[i], valueold[i]);
1687             }
1688             else if (interpolatenow) {
1689             /*  Interpolate time if actual time is greater than proposed next time step  */
1690                 double newval;
1691                 valuenew[i] = val.rValue;
1692                 newval = (timestep -  run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
1693                 plotAddRealValue(&run->data[i], newval);
1694                 valueold[i] = valuenew[i];
1695             }
1696             else if (nodata)
1697                 /* Just keep the transient output value corresponding to timeold,
1698                     but do not store to file */
1699                 valueold[i] = val.rValue;
1700         }
1701 
1702 #ifdef TCL_MODULE
1703         /*relinks and unlocks vector*/
1704         blt_relink(i, (run->data[i]).vec);
1705 #endif
1706 
1707     }
1708 
1709     gr_iplot(run->runPlot);
1710 
1711     if (ft_bpcheck(run->runPlot, run->pointCount) == FALSE)
1712         shouldstop = TRUE;
1713 
1714 #ifdef TCL_MODULE
1715     Tcl_ExecutePerLoop();
1716 #elif defined SHARED_MODULE
1717     sh_ExecutePerLoop();
1718 #endif
1719 
1720     return(OK);
1721 }
1722