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