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: 1985 Wayne A. Christopher
5          1992 Stephen R. Whiteley
6 ****************************************************************************/
7 
8 /*
9  * Spice-2 compatibility stuff for .plot, .print, .four, and .width.
10  */
11 
12 #include "spice.h"
13 #include "ftedefs.h"
14 #include "fteinp.h"
15 #include "spfteext.h"
16 
17 #ifdef __STDC__
18 static void fixdotplot(wordlist*);
19 static void fixdotprint(wordlist*);
20 static char *fixem(char*);
21 static bool setcplot(char*);
22 static wordlist *gettoks(char*);
23 #else
24 static void fixdotplot();
25 static void fixdotprint();
26 static char *fixem();
27 static bool setcplot();
28 static wordlist *gettoks();
29 #endif
30 
31 bool ft_acctprint = false;
32 bool ft_listprint = false;
33 bool ft_nodesprint = false;
34 bool ft_optsprint = false;
35 
36 
37 /* Extract all the .save lines */
38 
39 void
ft_dotsaves()40 ft_dotsaves()
41 {
42     wordlist *iline, *wl = NULL;
43     char *s;
44 
45     if (!ft_curckt) /* Shouldn't happen. */
46         return;
47 
48     for (iline = ft_curckt->ci_commands; iline; iline = iline->wl_next) {
49         if (ciprefix(".save", iline->wl_word)) {
50             s = iline->wl_word;
51             advtok(&s);
52             wl = wl_append(wl, gettoks(s));
53         }
54     }
55     if (wl) {
56         com_save(wl);
57         wl_free(wl);
58     }
59     /* If there aren't any .saves, all vectors will be saved,
60      * which is the default action for rawfiles when com_save()
61      * isn't called.
62      */
63     return;
64 }
65 
66 
67 /* Go through the dot lines given and make up a big "save" command with
68  * all the node names mentioned. Note that if a node is requested for
69  * one analysis, it is saved for all of them.
70  */
71 
72 void
ft_savedotargs()73 ft_savedotargs()
74 {
75     wordlist *w, *wl = NULL, *iline;
76     char *s;
77 
78     if (!ft_curckt) /* Shouldn't happen. */
79         return;
80 
81     for (iline = ft_curckt->ci_commands; iline; iline = iline->wl_next) {
82         s = iline->wl_word;
83         if (ciprefix(".print", s) || ciprefix(".plot", s) ||
84                 ciprefix(".four", s)) {
85             advtok(&s);
86             advtok(&s);
87             if (!(w = gettoks(s)))
88                 fprintf(cp_err, "Warning: no nodes given: %s\n",
89                     iline->wl_word);
90             wl = wl_append(wl, w);
91         }
92     }
93     if (wl) {
94         com_save(wl);
95         wl_free(wl);
96     }
97     fprintf(cp_err, "Warning: no .print, .plot, or .four lines in input.\n");
98 }
99 
100 
101 /* Execute the .whatever lines found in the deck, after we are done running.
102  * We'll be cheap and use cp_lexer to get the words.  This should make us
103  * spice-2 compatible.  If terse is true then there was a rawfile, so don't
104  * print lots of junk.
105  */
106 
107 void
ft_cktcoms(terse)108 ft_cktcoms(terse)
109 
110 bool terse;
111 {
112     wordlist *coms, *command, *cl;
113     char *plottype, *s;
114     struct dvec *v;
115     struct dvlist *dl0, *dl;
116     static wordlist twl = { "col", NULL, NULL } ;
117     int i;
118 
119     if (!ft_curckt)
120         return;
121     if (!ft_curckt->ci_commands)
122         goto nocmds;
123     coms = ft_curckt->ci_commands;
124     cp_interactive = false;
125 
126     out_init();
127 
128     /* Circuit name */
129     out_printf("Circuit: %s\nDate: %s\n\n", ft_curckt->ci_name,
130         datestring());
131     out_printf("\n");
132 
133     /* Listing */
134     if (ft_listprint) {
135         if (terse)
136             out_printf(".options: no listing, rawfile was generated.\n");
137         else
138             inp_list(cp_out, ft_curckt->ci_deck, ft_curckt->ci_options,
139                 LS_DECK);
140     }
141 
142     /* If there was a .op line, then we have to do the .op output. */
143     if (setcplot("op")) {
144         if (terse) {
145             out_printf("\nOP information in rawfile.\n");
146         }
147         else {
148             out_printf("\nOperating point information:\n\n");
149             out_printf("\tNode\tVoltage\n");
150             out_printf("\t----\t-------\n");
151 
152             v = vec_fromplot("all",plot_cur);
153             vec_sort(v);
154             dl0 = v->v_link2;
155 
156             for (dl = dl0; dl; dl = dl->dl_next) {
157                 v = dl->dl_dvec;
158                 if (!isreal(v)) {
159                     fprintf(cp_err,
160                 "Internal error: op vector %s not real\n", v->v_name);
161                     continue;
162                 }
163                 if (v->v_type == SV_VOLTAGE)
164                     out_printf("\t%s\t%s\n", v->v_name,
165                         printnum(v->v_realdata[0]));
166             }
167             out_printf("\n\tSource\tCurrent\n");
168             out_printf("\t------\t-------\n\n");
169             for (dl = dl0; dl; dl = dl->dl_next) {
170                 v = dl->dl_dvec;
171                 if (v->v_type == SV_CURRENT)
172                     out_printf("\t%s\t%s\n", v->v_name,
173                         printnum(v->v_realdata[0]));
174             }
175             out_printf("\n");
176         }
177     }
178 
179     if (setcplot("tf")) {
180         wordlist all;
181 
182         if (terse)
183             out_printf("TF information in rawfile.\n");
184         else {
185             out_printf("Transfer function information:\n");
186             all.wl_next = NULL;
187             all.wl_word = "all";
188             com_print(&all);
189             out_printf("\n");
190         }
191     }
192 
193     /* Now all the '.' lines */
194     while (coms) {
195         cl = command = cp_lexer(coms->wl_word);
196         if (!command)
197             goto bad;
198         if (eq(command->wl_word, ".width")) {
199             do {
200                 command = command->wl_next;
201             } while (command && !ciprefix("out", command->wl_word));
202             if (command) {
203                 s = strchr(command->wl_word, '=');
204                 if (!s || !s[1]) {
205                     fprintf(cp_err,
206                         "Error: bad line %s\n", coms->wl_word);
207                     coms = coms->wl_next;
208                     wl_free(cl);
209                     continue;
210                 }
211                 i = atoi(++s);
212                 cp_vset("width", VT_NUM, (char *) &i);
213             }
214         }
215         else if (eq(command->wl_word, ".print")) {
216             if (terse) {
217                 out_printf(
218                 "\n.print line ignored since rawfile was produced\n");
219             }
220             else {
221                 command = command->wl_next;
222                 if (!command) {
223                     fprintf(cp_err, "Error: bad line %s\n", coms->wl_word);
224                     coms = coms->wl_next;
225                     wl_free(cl);
226                     continue;
227                 }
228                 plottype = command->wl_word;
229                 command = command->wl_next;
230                 fixdotprint(command);
231                 twl.wl_next = command;
232                 if (setcplot(plottype))
233                     com_print(&twl);
234                 else
235                     fprintf(cp_err,
236                         "Error: no %s plot found\n", plottype);
237                 out_printf("\n\n");
238             }
239         }
240         else if (eq(command->wl_word, ".plot")) {
241             if (terse) {
242                 out_printf(
243                 "\n.plot line ignored since rawfile was produced\n");
244             }
245             else {
246                 command = command->wl_next;
247                 if (!command) {
248                     fprintf(cp_err, "Error: bad line %s\n", coms->wl_word);
249                     coms = coms->wl_next;
250                     wl_free(cl);
251                     continue;
252                 }
253                 plottype = command->wl_word;
254                 command = command->wl_next;
255                 fixdotplot(command);
256                 if (setcplot(plottype))
257                     com_asciiplot(command);
258                 else
259                     fprintf(cp_err,
260                         "Error: no %s plot found\n", plottype);
261                 out_printf("\n\n");
262             }
263         }
264         else if (ciprefix(".four", command->wl_word)) {
265             if (terse)
266                 out_printf(
267                     ".fourier line ignored since rawfile was produced.\n");
268             else if (setcplot("tran")) {
269                 com_fourier(command->wl_next);
270                 out_printf("\n\n");
271             }
272             else {
273                 out_printf(
274                     "No transient data available for fourier analysis");
275             }
276         }
277         else if (!eq(command->wl_word, ".save")
278             && !eq(command->wl_word, ".op")
279             && !eq(command->wl_word, ".tf"))
280             goto bad;
281         wl_free(cl);
282         coms = coms->wl_next;
283     }
284 
285 nocmds:
286     /* Now the node table */
287     if (ft_nodesprint)
288         ;
289 
290     /* The options */
291     if (ft_optsprint) {
292         fprintf(cp_err, "Options:\n\n");
293         cp_vprint();
294         (void) putc('\n', cp_out);
295     }
296 
297     /* And finally the accounting info. */
298     if (ft_acctprint) {
299         static wordlist ww = { "everything", NULL, NULL } ;
300         com_rusage(&ww);
301     }
302     else
303         com_rusage((wordlist *) NULL);
304 
305     out_printf("\n");
306     return;
307 
308 bad:
309     fprintf(cp_err, "Internal Error: ft_cktcoms: bad commands\n");
310     return;
311 }
312 
313 
314 /* These routines make sure that the arguments to .plot and .print in
315  * spice2 decks are acceptable to spice3. The things we look for are:
316  *  trailing (a,b) in .plot -> xlimit a b
317  *  vm(x) -> mag(v(x))
318  *  vp(x) -> ph(v(x))
319  *  v(x,0) -> v(x)
320  *  v(0,x) -> -v(x)
321  */
322 
323 static void
fixdotplot(wl)324 fixdotplot(wl)
325 
326 wordlist *wl;
327 {
328     char buf[BSIZE_SP], *s;
329     double *d, d1, d2;
330 
331     while (wl) {
332         wl->wl_word = fixem(wl->wl_word);
333 
334         /* Is this a trailing (a,b) ? Note that we require it to be
335          * one word.
336          */
337         if (!wl->wl_next && (*wl->wl_word == '(')) {
338             s = wl->wl_word + 1;
339             d = ft_numparse(&s, false);
340             if (*s != ',') {
341                 fprintf(cp_err, "Error: bad limits \"%s\"\n",
342                     wl->wl_word);
343                 return;
344             }
345             d1 = *d;
346             s++;
347             d = ft_numparse(&s, false);
348             if ((*s != ')') || s[1]) {
349                 fprintf(cp_err, "Error: bad limits \"%s\"\n",
350                     wl->wl_word);
351                 return;
352             }
353             d2 = *d;
354             tfree(wl->wl_word);
355             wl->wl_word = copy("xlimit");
356             wl->wl_next = alloc(struct wordlist);
357             wl->wl_next->wl_prev = wl;
358             wl = wl->wl_next;
359             (void) strcpy(buf, printnum(d1));
360             wl->wl_word = copy(buf);
361             wl->wl_next = alloc(struct wordlist);
362             wl->wl_next->wl_prev = wl;
363             wl = wl->wl_next;
364             (void) strcpy(buf, printnum(d2));
365             wl->wl_word = copy(buf);
366         }
367         wl = wl->wl_next;
368     }
369 }
370 
371 
372 static void
fixdotprint(wl)373 fixdotprint(wl)
374 
375 wordlist *wl;
376 {
377     while (wl) {
378         wl->wl_word = fixem(wl->wl_word);
379         wl = wl->wl_next;
380     }
381 }
382 
383 
384 static char *
fixem(string)385 fixem(string)
386 
387 char *string;
388 {
389     char buf[BSIZE_SP], *s, *t, *ss = string;
390 
391     if (ciprefix("v(", string) && strchr(string, ',')) {
392         for (s = string; *s && (*s != ','); s++)
393             ;
394         *s++ = '\0';
395         for (t = s; *t && (*t != ')'); t++)
396             ;
397         *t = '\0';
398         if (eq(s, "0"))
399             (void) sprintf(buf, "v(%s)", string + 2);
400         else if (eq(string + 2, "0"))
401             (void) sprintf(buf, "-v(%s)", s);
402         else
403             (void) sprintf(buf, "v(%s)-v(%s)", string + 2, s);
404         tfree(ss);
405         return (copy(buf));
406     }
407     if (ciprefix("vm(", string)) {
408         for (s = string; *s && (*s != ')'); s++)
409             ;
410         *s = '\0';
411         (void) sprintf(buf, "mag(v(%s))", string + 3);
412         tfree(ss);
413         return (copy(buf));
414     }
415     if (ciprefix("vp(", string)) {
416         for (s = string; *s && (*s != ')'); s++)
417             ;
418         *s = '\0';
419         (void) sprintf(buf, "ph(v(%s))", string + 3);
420         tfree(ss);
421         return (copy(buf));
422     }
423     if (ciprefix("vi(", string)) {
424         for (s = string; *s && (*s != ')'); s++)
425             ;
426         *s = '\0';
427         (void) sprintf(buf, "imag(v(%s))", string + 3);
428         tfree(ss);
429         return (copy(buf));
430     }
431     if (ciprefix("vr(", string)) {
432         for (s = string; *s && (*s != ')'); s++)
433             ;
434         *s = '\0';
435         (void) sprintf(buf, "real(v(%s))", string + 3);
436         tfree(ss);
437         return (copy(buf));
438     }
439     if (ciprefix("vdb(", string)) {
440         for (s = string; *s && (*s != ')'); s++)
441             ;
442         *s = '\0';
443         (void) sprintf(buf, "db(v(%s))", string + 4);
444         tfree(ss);
445         return (copy(buf));
446     }
447     if (ciprefix("i(", string)) {
448         for (s = string; *s && (*s != ')'); s++)
449             ;
450         *s = '\0';
451         string += 2;
452         (void) sprintf(buf, "%s#branch", string);
453         tfree(ss);
454         return (copy(buf));
455     }
456     return (string);
457 }
458 
459 
460 /* Don't bother with ccom strangeness here. */
461 
462 static bool
setcplot(name)463 setcplot(name)
464 
465 char *name;
466 {
467     struct plot *pl;
468 
469     for (pl = plot_list; pl; pl = pl->pl_next) {
470         if (ciprefix(name, pl->pl_typename)) {
471             plot_cur = pl;
472             return (true);
473         }
474     }
475     return (false);
476 }
477 
478 
479 static wordlist *
gettoks(s)480 gettoks(s)
481 
482 char *s;
483 {
484     char *t, *r, buf[64], buf1[BSIZE_SP];
485     wordlist *wl = NULL, *end = NULL;
486     bool iflag;
487 
488     while (copytok(buf1,&s)) {
489         t = buf1;
490         if (*t == '(') {
491             /* This is a (upper, lower) thing -- ignore. */
492             continue;
493         }
494         if (!strchr(t, '(')) {
495             ;
496         }
497         else if (!strchr(t, ',')) {
498             iflag = ((*t == 'i') || (*t == 'I')) ? true : false;
499             while (*t != '(')
500                 t++;
501             t++;
502             for (r = t; *r && *r != ')'; r++)
503                 ;
504             *r = '\0';
505             if (iflag) {
506                 (void) sprintf(buf, "%s#branch", t);
507                 t = buf;
508             }
509         }
510         else {
511             /* The painful case */
512             while (*t != '(')
513                 t++;
514             t++;
515             for (r = t; *r && *r != ','; r++)
516                 ;
517             *r = '\0';
518             if (end) {
519                 end->wl_next = alloc(struct wordlist);
520                 end->wl_next->wl_prev = end;
521                 end = end->wl_next;
522             }
523             else
524                 wl = end = alloc(struct wordlist);
525             end->wl_word = copy(t);
526             t = r + 1;
527             for (r = t; *r && *r != ')'; r++)
528                 ;
529             *r = '\0';
530         }
531         if (end) {
532             end->wl_next = alloc(struct wordlist);
533             end->wl_next->wl_prev = end;
534             end = end->wl_next;
535         }
536         else
537             wl = end = alloc(struct wordlist);
538         end->wl_word = copy(t);
539     }
540     return (wl);
541 }
542 
543