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: 1992 Stephen R. Whiteley
5 ****************************************************************************/
6 
7 /*
8  * Routines for operating range and related analysis
9  */
10 
11 #include "spice.h"
12 #include "ftedefs.h"
13 #include "fteinp.h"
14 #include "spfteext.h"
15 #include "ftegraph.h"
16 #include "plotext.h"
17 #include "outdata.h"
18 #include "util.h"
19 #include "iferrmsg.h"
20 
21 
22 static FILE *Op;            /* output file pointer          */
23 static int graphid;         /* graph id if plotting         */
24 static bool batchmode;      /* if true, no user prompts     */
25 static bool no_output;      /* supress output recording     */
26 static struct sOUTcontrol *OUTcntrl;
27                             /* structure to control output  */
28 
29 struct control {
30     double delta1;
31     double delta2;
32     int step1;
33     int step2;
34     double val1;
35     double val2;
36     int iterno;    /* number iterations for extrema seeking */
37 };
38 
39 struct sLOOPprms {
40     double start[2];      /* starting parameter value */
41     double stop[2];       /* ending parameter value */
42     double step[2];       /* step size */
43     double state[2];      /* internal values saved */
44     int dims[3];          /* dimensions of output vector */
45     int nestLevel;        /* number of levels of nesting */
46     int nestSave;         /* iteration state during pause */
47     char *rundesc;        /* save rundesc */
48     int inprogress;       /* not done yet */
49 };
50 
51 #ifdef __STDC__
52 static bool parse_var(struct sLOOPprms *,wordlist**);
53 static void pr_parms(void);
54 static void checkloop(wordlist*);
55 static void set_opvec(int);
56 static int  mainloop(struct control*);
57 static int  do_it(int,int,double,double);
58 static int  findext(int,double*,double,double);
59 static void check_end(void);
60 static bool read_check_control_file(FILE*,char*);
61 static bool check_evaluate(void);
62 static void execblock(char*);
63 static void modify(double,double);
64 static void setvec(double,double);
65 static FILE *df_open(void);
66 static void df_close(FILE*);
67 #else
68 static bool parse_var();
69 static void pr_parms();
70 static void checkloop();
71 static void set_opvec();
72 static int  mainloop();
73 static int  do_it();
74 static int  findext();
75 static void check_end();
76 static bool read_check_control_file();
77 static bool check_evaluate();
78 static void execblock();
79 static void modify();
80 static void setvec();
81 static FILE *df_open();
82 static void df_close();
83 #endif
84 
85 
86 void
com_check(wl)87 com_check(wl)
88 
89 wordlist *wl;
90 {
91     int i, step1, step2;
92     struct dvec *d;
93     char buf[BSIZE_SP];
94     char *c, *hdr;
95     wordlist *ww, *wn;
96     struct circ *ct;
97     struct plot *pl;
98     extern char *kw_mplot_cur;
99 
100     batchmode = true;
101 
102     if (!ft_curckt || !ft_curckt->ci_ckt) {
103         (void) fprintf(cp_err,"Error: no circuit loaded.\n");
104         return;
105     }
106     if (!ft_curckt->ci_contblk) {
107         (void) fprintf(cp_err,"Error: no bound codeblock.\n");
108         return;
109     }
110     if (!cp_isblockdef(ft_curckt->ci_contblk)) {
111         (void) fprintf(cp_err,"Error: codeblock %s not found.\n",
112             ft_curckt->ci_contblk);
113         return;
114     }
115     for (ct = ft_circuits; ct; ct = ct->ci_next)
116         ct->ci_inprogress = false;
117     ft_intrpt = false;
118 
119     pl = plot_alloc("range");
120     plot_new(pl);
121     plot_setcur(pl->pl_typename);
122 
123     /* margin analysis creates two codeblocks:
124      * #_name and ##name.  ##name is the header block, which is
125      * executed after the plot is created.  #_name is the bound
126      * codeblock.
127      */
128 
129     hdr = copy(ft_curckt->ci_contblk);
130     hdr[1] = '#';
131     if (cp_isblockdef(hdr))
132         execblock(hdr);
133     txfree(hdr);
134 
135     ww = cp_lexer("checkFAIL = 0");
136     com_let(ww);
137     wl_free(ww);
138 
139     if (wl) {
140         wl = wl_copy(wl);
141         for (ww = wl; wl; wl = wn) {
142             wn = wl->wl_next;
143             if (wl->wl_word[0] == '-' && wl->wl_word[1] == 'v') {
144                 if (wl->wl_prev)
145                     wl->wl_prev->wl_next = wl->wl_next;
146                 if (wl->wl_next)
147                     wl->wl_next->wl_prev = wl->wl_prev;
148                 if (ww == wl)
149                     ww = wl->wl_next;
150                 txfree(wl->wl_word);
151                 txfree((char*)wl);
152                 batchmode = false;
153             }
154         }
155         wl = ww;
156     }
157 
158     /* analysis specification */
159     if (!wl || !wl->wl_word || *wl->wl_word == '\0') {
160         wn = GetAnalysisFromDeck();
161         if (wn == NULL) {
162             (void) fprintf(cp_err,
163                 "Error: no or more than one analysis specified\n");
164             wl_free(wl);
165             com_destroy(NULL);
166             return;
167         }
168         wl_free(wl);
169         wl = wn;
170     }
171     for (c = wl->wl_word; *c; c++)
172         if (isupper(*c)) *c = tolower(*c);
173 
174     Op = (FILE*)NULL;
175     step1 = step2 = 0;
176     if ((d = vec_get("checkSTP1")) != NULL)
177         step1 = (int) *d->v_realdata;
178     if ((d = vec_get("checkSTP2")) != NULL)
179         step2 = (int) *d->v_realdata;
180     if (step1 || step2) {
181         if ((Op = df_open()) == NULL) {
182             (void) fprintf(cp_err,"Error: Can't open data output file\n");
183             wl_free(wl);
184             com_destroy(NULL);
185             return;
186         }
187     }
188     if ((d = vec_get("checkPNTS")) == NULL) {
189         (void) fprintf(cp_err,"Error: check variable checkPNTS not set\n");
190         com_destroy(NULL);
191         return;
192     }
193 
194     OUTcntrl = (struct sOUTcontrol *)OUTcntrlInit();
195     OUTcntrl->out_evaluate = check_evaluate;
196     OUTcntrl->out_end      = check_end;
197     OUTcntrl->out_max      = d->v_length;
198     OUTcntrl->out_points   = d->v_realdata;
199 
200     /* make sure an "exact" point is recognized */
201     for (i = 0; i < d->v_length; i++)
202         d->v_realdata[i] *= .9999;
203 
204     if (!batchmode)
205         pr_parms();
206 
207     checkloop(wl);
208 
209     df_close(Op);
210     if (OUTcntrl->out_destroy)
211         (*OUTcntrl->out_destroy)();
212     wl_free(wl);
213     mp_done(graphid);
214 
215     *buf = '\0';
216     (void)cp_getvar(kw_mplot_cur,VT_STRING,buf);
217     if (!batchmode && Op && *buf)
218         (void) fprintf(cp_out,
219         "Operating range analysis complete.  Data in file %s.\n",buf);
220     Op = NULL;
221 }
222 
223 
224 void
com_loop(wl)225 com_loop(wl)
226 
227 wordlist *wl;
228 {
229     static struct sLOOPprms loop;
230     double tt;
231     int i;
232     int error;
233     int count;
234     bool firsttime;
235     char *c, *task;
236 
237 
238     if (ft_curckt->ci_inprogress && loop.inprogress) {
239         i = loop.nestSave;
240         firsttime = false;
241         OUTcntrl->out_rundesc = loop.rundesc;
242         OUTcntrl->out_keepplot = true;
243         loop.inprogress = false;
244         task = ft_curckt->ci_curTask;
245         goto didpause;
246     }
247     else {
248         /* reset static variables */
249         error = parse_var(&loop,&wl);
250         if (error) {
251             fprintf(cp_err,"Syntax error\n");
252             return;
253         }
254         /* analysis specification */
255         if (!wl || !wl->wl_word || *wl->wl_word == '\0') {
256             wl = GetAnalysisFromDeck();
257             if (wl == NULL) {
258                 (void) fprintf(cp_err,
259                     "Error: no or more than one analysis specified\n");
260                 return;
261             }
262         }
263         for (c = wl->wl_word; *c; c++)
264             if (isupper(*c)) *c = tolower(*c);
265 
266         OUTcntrl = (struct sOUTcontrol *)OUTcntrlInit();
267         OUTcntrl->out_keepplot = true;
268         for (i = 0; i <= loop.nestLevel; i++)
269             loop.state[i] = loop.start[i];
270         i = 0;
271         firsttime = true;
272     }
273 
274     for (;;) {
275 
276         tt = loop.state[i] - loop.stop[i];
277 
278         if ((loop.step[i] > 0 && tt > 1e-8) ||
279             (loop.step[i] < 0 && tt < 1e-8) ||
280             loop.step[i] == 0) {
281 
282             i++;
283             if (i > loop.nestLevel)
284                 break;
285             loop.dims[0]++;
286             if (loop.dims[2] <= 1) {
287                 OUTsetDims(OUTcntrl->out_rundesc,loop.dims,2);
288             }
289         }
290         else {
291             if (!loop.dims[0])
292                 loop.dims[1]++;
293 
294             while (i > 0) {
295                 i--;
296                 loop.state[i] = loop.start[i];
297             }
298 
299             modify(loop.state[0],loop.state[1]);
300             if (ft_curckt->ci_specTask) {
301                 task = ft_curckt->ci_specTask;
302                 ft_curckt->ci_specTask = NULL;
303                 com_rset((wordlist*)NULL);
304                 ft_curckt->ci_specTask = task;
305             }
306             else {
307                 com_rset((wordlist*)NULL);
308                 task = ft_curckt->ci_defTask;
309 
310             }
311             ft_curckt->ci_curTask = task;
312 didpause:
313 
314             if (firsttime) {
315                 count = 0;
316                 error = if_run(wl->wl_word, wl->wl_next);
317                 firsttime = false;
318             }
319             else {
320                 count = plot_cur->pl_scale->v_length;
321                 error = (*(ft_sim->doAnalyses))
322                     (ft_curckt->ci_ckt, 1, task);
323             }
324             if (error) {
325                 if (error == E_PAUSE) {
326                     loop.nestSave = i;
327                     loop.rundesc = OUTcntrl->out_rundesc;
328                     OUTcntrl->out_rundesc = NULL;
329                     loop.inprogress = true;
330                 }
331                 gr_end_iplot();
332                 if (OUTcntrl->out_destroy)
333                     (*OUTcntrl->out_destroy)();
334                 return;
335             }
336 
337             /* store block size in dims[] */
338             loop.dims[2] = plot_cur->pl_scale->v_length - count;
339 
340             if (loop.dims[2] > 1) {
341 
342                 if (loop.dims[0])
343                     OUTsetDims(OUTcntrl->out_rundesc,loop.dims,3);
344                 else
345                     OUTsetDims(OUTcntrl->out_rundesc,loop.dims+1,2);
346             }
347         }
348         loop.state[i] += loop.step[i];
349     }
350 
351     gr_end_iplot();
352     ft_curckt->ci_inprogress = false;
353     if (OUTcntrl->out_destroy)
354         (*OUTcntrl->out_destroy)();
355 
356     return;
357 }
358 
359 
360 static bool
parse_var(loop,wl)361 parse_var(loop,wl)
362 
363 struct sLOOPprms *loop;
364 wordlist **wl;
365 {
366     char *line;
367     int error;
368     double tmp;
369     double INPevaluate();
370 
371     loop->start[0]   = 0;
372     loop->stop[0]    = 0;
373     loop->step[0]    = 0;
374     loop->start[1]   = 0;
375     loop->stop[1]    = 0;
376     loop->step[1]    = 0;
377     loop->nestLevel  = 0;
378     loop->dims[0]    = 0;
379     loop->dims[1]    = 0;
380     loop->dims[2]    = 0;
381     loop->nestSave   = 0;
382     loop->inprogress = 0;
383 
384     if (wl == NULL || *wl == NULL)
385         return (true);
386     line = (*wl)->wl_word;
387     tmp = INPevaluate(&line,&error,1);  /* start1 */
388     if (error == 0)
389         loop->start[0] = tmp;
390     else
391         return (error);
392     loop->nestLevel = 0;
393 
394     *wl = (*wl)->wl_next;
395     if (!*wl) {
396         loop->stop[0] = loop->start[0];
397         loop->step[0] = 0;
398         return (false);
399     }
400 
401     line = (*wl)->wl_word;
402     tmp = INPevaluate(&line,&error,1);  /* stop1 */
403     if (error == 0)
404         loop->stop[0] = tmp;
405     else {
406         loop->stop[0] = loop->start[0];
407         loop->step[0] = 0;
408         return (false);
409     }
410 
411     (*wl) = (*wl)->wl_next;
412     if (!*wl) {
413         loop->step[0] = loop->stop[0] - loop->start[0];
414         return (false);
415     }
416 
417     line = (*wl)->wl_word;
418     tmp = INPevaluate(&line,&error,1);  /* step1 */
419     if (error == 0)
420         loop->step[0] = tmp;
421     else {
422         loop->step[0] = loop->stop[0] - loop->start[0];
423         return (false);
424     }
425 
426     (*wl) = (*wl)->wl_next;
427     if (!*wl) {
428         return (false);
429     }
430 
431     line = (*wl)->wl_word;
432     tmp = INPevaluate(&line,&error,1);  /* start2 */
433     if (error == 0)
434         loop->start[1] = tmp;
435     else {
436         return (false);
437     }
438     loop->nestLevel = 1;
439 
440     (*wl) = (*wl)->wl_next;
441     if (!*wl) {
442         loop->stop[1] = loop->start[1];
443         loop->step[1] = 0;
444         return (false);
445     }
446 
447     line = (*wl)->wl_word;
448     tmp = INPevaluate(&line,&error,1);  /* stop2 */
449     if (error == 0)
450         loop->start[1] = tmp;
451     else {
452         loop->stop[1] = loop->start[1];
453         loop->step[1] = 0;
454         return (false);
455     }
456 
457     (*wl) = (*wl)->wl_next;
458     if (!*wl) {
459         loop->step[1] = loop->stop[1] - loop->start[1];
460         return (false);
461     }
462 
463     line = (*wl)->wl_word;
464     tmp = INPevaluate(&line,&error,1);  /* step2 */
465     if (error == 0)
466         loop->start[1] = tmp;
467     else {
468         loop->step[1] = loop->stop[1] - loop->start[1];
469         return (false);
470     }
471     (*wl) = (*wl)->wl_next;
472     return (false);
473 }
474 
475 
476 void
ft_check(wl,infile)477 ft_check(wl,infile)
478 
479 wordlist *wl;
480 FILE *infile;
481 {
482     FILE *fp;
483     struct line *deck;
484     wordlist *ww;
485     char *filename = NULL;
486     char *cblock;
487 
488     if (currentgraph && currentgraph->graphtype == GR_SCED) {
489         ShowPrompt("Exit sced to run operating range analysis.");
490         return;
491     }
492 
493     out_init(); /* this might not have been called before, needed
494                  * for inp_dodeck()
495                  */
496 
497     if (infile != NULL) {
498         /* file sourced */
499         fp = infile;
500         if (wl && wl->wl_word && *wl->wl_word) {
501             filename = wl->wl_word;
502             wl = wl->wl_next;
503         }
504     }
505 
506     else {
507         if (!wl || !wl->wl_word || *wl->wl_word == '\0') {
508             fp = cp_in;
509         }
510         else {
511             filename = wl->wl_word;
512             wl = wl->wl_next;
513             if ((fp = fopen(filename,"r")) == NULL) {
514                 (void) fprintf(cp_err,"Error: can't open source file\n");
515                 return;
516             }
517         }
518     }
519 
520     if (filename && *filename) {
521         cblock = tmalloc(strlen(filename) + 3);
522         sprintf(cblock,"#_%s",filename);
523     }
524     else
525         cblock = copy("#_");
526 
527 
528     if (read_check_control_file(fp,cblock)) {
529         (void) fclose(fp);
530         return;
531     }
532     inp_readall(fp,&deck,NULL);
533     if (fp != cp_in)
534         (void) fclose(fp);
535 
536     ww = cp_lexer("set value1=0.0 value2=0.0");
537     com_set(ww);
538     wl_free(ww);
539     inp_spdeck(deck,filename);
540     ft_curckt->ci_contblk = cblock;
541 
542     if (ft_batchmode) {
543         /* run the analysis and free */
544         com_check((wordlist*)NULL);
545         if_cktclear();
546     }
547 }
548 
549 
550 static void
pr_parms()551 pr_parms()
552 
553 {
554     int step1, step2, iterno;
555     double val1, delta1, val2, delta2;
556     struct dvec *d;
557     extern char *kw_checkiterate;
558 
559     val1 = 0;
560     step1 = 0;
561     delta1 = 0;
562     val2 = 0;
563     step2 = 0;
564     delta2 = 0;
565     iterno = 0;
566 
567     if ((d = vec_get("checkDEL1")) != NULL)
568         delta1 = *d->v_realdata;
569     if ((d = vec_get("checkVAL1")) != NULL)
570         val1 = *d->v_realdata;
571     if ((d = vec_get("checkDEL2")) != NULL)
572         delta2 = *d->v_realdata;
573     if ((d = vec_get("checkVAL2")) != NULL)
574         val2 = *d->v_realdata;
575     if ((d = vec_get("checkSTP1")) != NULL)
576         step1 = (int) *d->v_realdata;
577     if ((d = vec_get("checkSTP2")) != NULL)
578         step2 = (int) *d->v_realdata;
579     (void) cp_getvar(kw_checkiterate,VT_NUM,(char*)&iterno);
580 
581     out_printf(
582 "Substitution for value1:\n\
583     value: %g\n\
584     delta: %g\n\
585     steps: %d\n\n",val1,delta1,step1);
586 
587     out_printf(
588 "Substitution for value2:\n\
589     value: %g\n\
590     delta: %g\n\
591     steps: %d\n\n",val2,delta2,step2);
592 
593     out_printf("checkiterate is set to %d\n\n",iterno);
594 }
595 
596 
597 static void
checkloop(cmdwl)598 checkloop(cmdwl)
599 
600 wordlist *cmdwl;
601 {
602     struct dvec *d;
603     struct control cntrl;
604     double value1, value2;
605     char *apology = "Sorry, margin analysis can't be resumed in this version.\n";
606     extern char *kw_checkiterate;
607 
608     OUTcntrl->out_check = true;
609     OUTcntrl->out_keepplot = true;
610     OUTcntrl->out_usecurplot = true;
611 
612     cntrl.val1 = 0;
613     cntrl.step1 = 0;
614     cntrl.delta1 = 0;
615     cntrl.val2 = 0;
616     cntrl.step2 = 0;
617     cntrl.delta2 = 0;
618     cntrl.iterno = 0;
619 
620     if ((d = vec_get("checkDEL1")) != NULL)
621         cntrl.delta1 = *d->v_realdata;
622     if ((d = vec_get("checkVAL1")) != NULL)
623         cntrl.val1 = *d->v_realdata;
624     if ((d = vec_get("checkDEL2")) != NULL)
625         cntrl.delta2 = *d->v_realdata;
626     if ((d = vec_get("checkVAL2")) != NULL)
627         cntrl.val2 = *d->v_realdata;
628     if ((d = vec_get("checkSTP1")) != NULL)
629         cntrl.step1 = (int) *d->v_realdata;
630     if ((d = vec_get("checkSTP2")) != NULL)
631         cntrl.step2 = (int) *d->v_realdata;
632 
633     value1 = cntrl.val1 - cntrl.step1 * cntrl.delta1;
634     value2 = cntrl.val2 - cntrl.step2 * cntrl.delta2;
635     modify(value1,value2);
636     com_rset((wordlist*)NULL);
637     graphid = (mp_init(2*cntrl.step1+1,2*cntrl.step2+1,
638         value1, cntrl.val1+cntrl.step1*cntrl.delta1,
639         value2, cntrl.val2+cntrl.step2*cntrl.delta2));
640 
641     if (!graphid && !batchmode)
642         (void) fprintf(cp_out,"%d %d %g %g\n",
643             -cntrl.step1,-cntrl.step2,value1,value2);
644 
645     if (Op)
646         (void) fprintf(Op,"%d %d %g %g\n",
647             -cntrl.step1,-cntrl.step2,value1,value2);
648 
649     mp_where(graphid,-cntrl.step1,-cntrl.step2);
650 
651 
652     /* run the analysis */
653     (void)cp_getvar(kw_checkiterate,VT_NUM,(char*)&cntrl.iterno);
654     if (cntrl.iterno < 0 || cntrl.iterno > 10) {
655         cntrl.iterno = 0;
656         (void)fprintf(cp_err,
657             "Warning: bad value for checkiterate, ignored.\n");
658     }
659     set_opvec(cntrl.step2);
660 
661     (void) if_run(cmdwl->wl_word, cmdwl->wl_next);
662 
663     if (OUTcntrl->out_check == 0) { /* user interrupt */
664         (void) fprintf(cp_err,apology);
665         return;
666     }
667 
668     if (mainloop(&cntrl))
669         (void) fprintf(cp_err,apology);
670 }
671 
672 
673 static void
set_opvec(n)674 set_opvec(n)
675 
676 /* create vectors for operating range exterma (value 2) */
677 int n;
678 {
679     char buf[BSIZE_SP];
680     bool temp;
681 
682     temp = cp_interactive;
683     cp_interactive = false;
684     cp_pushcontrol();
685     sprintf(buf,"unlet oplo; let oplo[%d]=0",2*n);
686     cp_evloop(buf);
687     sprintf(buf,"unlet ophi; let ophi[%d]=0",2*n);
688     cp_evloop(buf);
689     cp_popcontrol();
690     cp_interactive = temp;
691 }
692 
693 
694 static int
mainloop(cntrl)695 mainloop(cntrl)
696 
697 struct control *cntrl;
698 {
699     int i, j, last;
700     int num1, num2;
701     double value1, value2, delta;
702     char *flags, *rowflags;
703     struct dvec *d;
704 
705     if (cntrl->step1 == 0 && cntrl->step2 == 0) {
706         /* new feature - find the operating range of value1 */
707 
708         if (cntrl->iterno == 0)
709             return (false);
710         if (OUTcntrl->out_fail) {
711             /* center point bad */
712             (void) fprintf(cp_err,
713                 "Error: central point bad, range not found.\n");
714             return (false);
715         }
716         value2 = cntrl->val2;
717         value1 = cntrl->val1;
718         delta = .5*value1;
719         for (i = 0; i < 10; i++) {
720             value1 += delta;
721             no_output = true;
722             do_it(0,0,value1,value2);
723             no_output = false;
724             if (OUTcntrl->out_fail) {
725                 value1 -= delta;
726                 if (findext(cntrl->iterno,&value1,value2,-delta))
727                     goto quit;
728                 if ((d = vec_get("ophi")) != NULL)
729                     d->v_realdata[0] = value1;
730                 break;
731             }
732         }
733         if (i == 10) {
734             (void) fprintf(cp_err,"Warning: could not find upper limit.\n");
735             if ((d = vec_get("ophi")) != NULL)
736                 d->v_realdata[0] = value1;
737         }
738         value1 = cntrl->val1;
739         delta = .49*value1;
740         for (i = 0; i < 2; i++) {
741             value1 -= delta;
742             no_output = true;
743             do_it(0,0,value1,value2);
744             no_output = false;
745             if (OUTcntrl->out_fail) {
746                 value1 += delta;
747                 if (findext(cntrl->iterno,&value1,value2,delta))
748                     goto quit;
749                 if ((d = vec_get("oplo")) != NULL)
750                     d->v_realdata[0] = value1;
751                 break;
752             }
753         }
754         if (i == 2) {
755             (void) fprintf(cp_err,"Warning: could not find lower limit.\n");
756             if ((d = vec_get("oplo")) != NULL)
757                 d->v_realdata[0] = value1;
758         }
759         return (false);
760     }
761 
762     num1 = 2*cntrl->step1 + 1;
763     num2 = 2*cntrl->step2 + 1;
764     flags = tmalloc(num1*num2);
765     /* fill in the first point */
766     *flags = 1 + OUTcntrl->out_fail;
767 
768     /* Find the range along the rows. */
769     for (j = -cntrl->step2; j <= cntrl->step2; j++) {
770         value2 = cntrl->val2 + j*cntrl->delta2;
771 
772         rowflags = flags + (j + cntrl->step2)*num1;
773         for (last = i = -cntrl->step1; i <= cntrl->step1; i++,rowflags++) {
774             if (*rowflags == 2) continue;
775             if (*rowflags == 1) break;
776             value1 = cntrl->val1 + i*cntrl->delta1;
777             *rowflags = do_it(i,j,value1,value2);
778             if (OUTcntrl->out_check == 0) /* user interrupt */
779                 goto quit;
780             last = i;
781             if (!OUTcntrl->out_fail) break;
782         }
783         if (!OUTcntrl->out_fail && i != -cntrl->step1) {
784             if (findext(cntrl->iterno,&value1,value2,cntrl->delta1))
785                 goto quit;
786             if ((d = vec_get("oplo")) != NULL)
787                 d->v_realdata[j+cntrl->step2] = value1;
788         }
789 
790         rowflags = flags + (j + cntrl->step2 + 1)*num1 - 1;
791         for (i = cntrl->step1; i > last; i--,rowflags--) {
792             if (*rowflags == 2) continue;
793             if (*rowflags == 1) break;
794             value1 = cntrl->val1 + i*cntrl->delta1;
795             *rowflags = do_it(i,j,value1,value2);
796             if (OUTcntrl->out_check == 0) /* user interrupt */
797                 goto quit;
798             if (!OUTcntrl->out_fail) break;
799         }
800         if (!OUTcntrl->out_fail && i != cntrl->step1) {
801             if (findext(cntrl->iterno,&value1,value2,-cntrl->delta1))
802                 goto quit;
803             if ((d = vec_get("ophi")) != NULL)
804                 d->v_realdata[j+cntrl->step2] = value1;
805         }
806     }
807 
808     /* Now check the columns, fill in any missing points.
809      * Do this for column height > 3 only.
810      */
811     if (cntrl->step2 > 1) {
812         for (i = -cntrl->step1; i <= cntrl->step1; i++) {
813             value1 = cntrl->val1 + i*cntrl->delta1;
814 
815             rowflags = flags + i + cntrl->step1;
816             for (last = j = -cntrl->step2; j <= cntrl->step2;
817                     j++,rowflags += num1) {
818                 if (*rowflags == 2) continue;
819                 if (*rowflags == 1) break;
820                 value2 = cntrl->val2 + j*cntrl->delta2;
821                 *rowflags = do_it(i,j,value1,value2);
822                 if (OUTcntrl->out_check == 0) /* user interrupt */
823                     goto quit;
824                 last = j;
825                 if (!OUTcntrl->out_fail) break;
826             }
827 
828             rowflags = flags + i + cntrl->step1 + 2*cntrl->step2*num1;
829             for (j = cntrl->step2; j > last; j--,rowflags -= num1) {
830                 if (*rowflags == 2) continue;
831                 if (*rowflags == 1) break;
832                 value2 = cntrl->val2 + j*cntrl->delta2;
833                 *rowflags = do_it(i,j,value1,value2);
834                 if (OUTcntrl->out_check == 0) /* user interrupt */
835                     goto quit;
836                 if (!OUTcntrl->out_fail) break;
837             }
838         }
839     }
840     txfree(flags);
841     return (false);
842 quit:
843     txfree(flags);
844     return (true);
845 }
846 
847 
848 static int
do_it(i,j,value1,value2)849 do_it(i,j,value1,value2)
850 
851 int i,j;
852 double value1,value2;
853 {
854     char *task;
855 
856     modify(value1,value2);
857     if (!no_output) {
858         if (mp_where(graphid,i,j) && !batchmode)
859             (void) fprintf(cp_out,"%d %d %g %g\n",i,j,value1,value2);
860         if (Op)
861             (void) fprintf(Op,"%d %d %g %g\n",i,j,value1,value2);
862     }
863     if (ft_curckt->ci_specTask) {
864         task = ft_curckt->ci_specTask;
865         ft_curckt->ci_specTask = NULL;
866         com_rset((wordlist*)NULL);
867         ft_curckt->ci_specTask = task;
868     }
869     else {
870         com_rset((wordlist*)NULL);
871         task = ft_curckt->ci_defTask;
872     }
873 
874     ft_curckt->ci_curTask = task;
875     (void)(*(ft_sim->doAnalyses))(ft_curckt->ci_ckt, 1,task);
876     return (OUTcntrl->out_fail + 1);
877 }
878 
879 
880 static int
findext(iterno,value1,value2,delta)881 findext(iterno,value1,value2,delta)
882 
883 /* Iterate to the edge of the operating region along row */
884 int iterno;
885 double *value1,value2,delta;
886 {
887     char *task;
888 
889     delta *= .5;
890     *value1 -= delta;
891 
892     no_output = true;
893     while (iterno--) {
894         modify(*value1,value2);
895 
896         if (ft_curckt->ci_specTask) {
897             task = ft_curckt->ci_specTask;
898             ft_curckt->ci_specTask = NULL;
899             com_rset((wordlist*)NULL);
900             ft_curckt->ci_specTask = task;
901         }
902         else {
903             com_rset((wordlist*)NULL);
904             task = ft_curckt->ci_defTask;
905         }
906 
907         ft_curckt->ci_curTask = task;
908         (void) (*(ft_sim->doAnalyses))(ft_curckt->ci_ckt, 1, task);
909 
910         if (OUTcntrl->out_check == 0) { /* user interrupt */
911             no_output = false;
912             return (true);
913         }
914 
915         delta *= .5;
916         if (!OUTcntrl->out_fail)
917             *value1 -= delta;
918         else
919             *value1 += delta;
920     }
921     no_output = false;
922     return (false);
923 }
924 
925 
926 static void
check_end()927 check_end()
928 {
929     if (no_output)
930         return;
931     if (mp_mark(graphid,!OUTcntrl->out_fail) && !batchmode)
932         (void) fprintf(cp_out,OUTcntrl->out_fail ? " fail\n\n" : " pass\n\n");
933     if (Op)
934         (void) fprintf(Op,OUTcntrl->out_fail ? "\tfail\n" : "\tpass\n");
935 }
936 
937 
938 static int
read_check_control_file(fp,blname)939 read_check_control_file(fp,blname)
940 
941 FILE *fp;
942 char *blname;
943 {
944     char *buf;
945     wordlist *chklst = NULL, *ckl;
946     wordlist *hdrlst = NULL, *hdl;
947     bool begin = false;
948 
949     while ((buf = readline(fp)) != NULL) {
950         if (*buf == '#') {
951             txfree(buf);
952             continue;
953         }
954         if (prefix(".control",buf)) {
955             begin = true;
956             txfree(buf);
957             continue;
958         }
959         if (prefix(".endc",buf)) {
960             if (!begin)
961                 (void) fprintf(cp_err,"Warning: no .control line found\n");
962             txfree(buf);
963             break;
964         }
965         *strchr(buf,'\n') = '\0';
966         if (!*buf) {
967             txfree(buf);
968             continue;
969         }
970         if (!begin) {
971             if (!hdrlst)
972                 hdrlst = hdl = alloc(wordlist);
973             else {
974                 hdl->wl_next = alloc(wordlist);
975                 hdl = hdl->wl_next;
976             }
977             hdl->wl_word = buf;
978             continue;
979         }
980         if (!chklst)
981             chklst = ckl = alloc(wordlist);
982         else {
983             ckl->wl_next = alloc(wordlist);
984             ckl = ckl->wl_next;
985         }
986         ckl->wl_word = buf;
987     }
988     cp_addblock(blname,chklst);
989     blname[1] = '#';
990     cp_addblock(blname,hdrlst);
991     blname[1] = '_';
992     wl_free(chklst);
993     wl_free(hdrlst);
994     return (false);
995 }
996 
997 
998 static bool
check_evaluate()999 check_evaluate()
1000 {
1001     struct dvec *d;
1002     char *blname;
1003 
1004     blname = ft_curckt->ci_contblk;
1005     if (!blname)
1006         return (true);
1007 
1008     execblock(blname);
1009     d = vec_get("checkFAIL");
1010 
1011     /* checkFAIL is true if failed */
1012     return ((int) *d->v_realdata ? true : false);
1013 }
1014 
1015 
1016 static void
execblock(blname)1017 execblock(blname)
1018 
1019 char *blname;
1020 {
1021     bool temp;
1022     FILE *lastin, *lastout, *lasterr;
1023 
1024     temp = cp_interactive;
1025     cp_interactive = false;
1026     lastin = cp_curin;
1027     lastout = cp_curout;
1028     lasterr = cp_curerr;
1029     cp_curin = cp_in;
1030     cp_curout = cp_out;
1031     cp_curerr = cp_err;
1032 
1033     cp_execcontrol(blname);
1034 
1035     cp_curin = lastin;
1036     cp_curout = lastout;
1037     cp_curerr = lasterr;
1038     cp_interactive = temp;
1039 }
1040 
1041 
1042 static void
modify(value1,value2)1043 modify(value1,value2)
1044 
1045 double value1,value2;
1046 {
1047     char buf[BSIZE_SP];
1048     wordlist *wl;
1049 
1050     sprintf(buf,"set value1=%g value2=%g",value1,value2);
1051     wl = cp_lexer(buf);
1052     com_set(wl);
1053     wl_free(wl);
1054     setvec(value1,value2);
1055 }
1056 
1057 
1058 static void
setvec(v1,v2)1059 setvec(v1,v2)
1060 
1061 double v1,v2;
1062 {
1063     struct dvec *d, *n1, *n2;
1064     int i, len;
1065 
1066     d = vec_get("value");
1067     if (d == NULL)
1068         return;
1069     if (!isreal(d))
1070         return;
1071     n1 = vec_get("checkN1");
1072     n2 = vec_get("checkN2");
1073     if (n1 == NULL && n2 == NULL)
1074         return;
1075     len = d->v_length;
1076     if (n1) {
1077         i = (int)n1->v_realdata[0];
1078         if (i < 0 || i >= len)
1079             return;
1080         d->v_realdata[i] = v1;
1081     }
1082     if (n2) {
1083         i = (int)n2->v_realdata[0];
1084         if (i < 0 || i >= len)
1085             return;
1086         d->v_realdata[i] = v2;
1087     }
1088 }
1089 
1090 
1091 
1092 static FILE *
df_open()1093 df_open()
1094 
1095 /* open the data output file for writing.  name: xxxxx.dnn , where
1096  * xxxxx is the base of the circuit file name, or "check" if no
1097  * current file name.  nn is 00 - 99.
1098  * If successful, set the variable "mplot_cur" to the file name.
1099  */
1100 {
1101     FILE *fp, *fopen();
1102     char buf[128], buf1[128], *s;
1103     wordlist *wl;
1104     int i;
1105 
1106     if (ft_servermode) {
1107         wl = cp_lexer("set mplot_cur=mplot");
1108         com_set(wl);
1109         wl_free(wl);
1110         return (cp_out);
1111     }
1112 
1113     if (ft_curckt->ci_filename)
1114         sprintf(buf,ft_curckt->ci_filename);
1115     else
1116         strcpy(buf,"check");
1117     if ((s = strrchr(buf,DIR_TERM)) != NULL)
1118         s++;
1119     else
1120         s = buf;
1121     strcpy(buf1,s);
1122 
1123     if ((s = strrchr(buf1,'.')) != NULL)
1124         *s = '\0';
1125     strcat(buf1,".d00");
1126     s = strchr(buf1,'.') + 2;
1127     for (i = 1; i < 100; i++) {
1128         if (access(buf1,0)) break;
1129         *s = i/10 + '0';
1130         *(s+1) = i%10 + '0';
1131     }
1132     if (i == 100)
1133         return (NULL);
1134     fp = fopen(buf1,"w");
1135     if (!fp) {
1136         perror(buf1);
1137         return (NULL);
1138     }
1139 
1140     sprintf(buf,"set mplot_cur=%s",buf1);
1141     wl = cp_lexer(buf);
1142     com_set(wl);
1143     wl_free(wl);
1144 
1145     return (fp);
1146 }
1147 
1148 
1149 static void
df_close(fp)1150 df_close(fp)
1151 
1152 FILE *fp;
1153 {
1154     if (fp && fp != cp_out)
1155         (void) fclose(fp);
1156 }
1157