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, Norbert Jeske
5 1992 Stephen R. Whiteley
6 ****************************************************************************/
7
8 /*
9 * Expand subcircuits. This is very spice-dependent.
10 */
11
12 #include "spice.h"
13 #include "ftedefs.h"
14 #include "fteinp.h"
15 #include "kwords.h"
16 #include "spfteext.h"
17
18
19 #ifdef __STDC__
20 static struct line *doit(struct line*);
21 static bool translate(struct line*,char*,char*,char*,char*,char*);
22 static void finishLine(char*,char*,char*);
23 static bool settrans(char*,char*,char*,char*);
24 static bool aredups(void);
25 static char *gettrans(char*);
26 static void numrefs(char*,int*,int*);
27 static bool modtranslate(struct line*,char*);
28 static void devmodtranslate(struct line*,char*);
29 static void looksubmod(char**,char*,char*);
30 #else
31 static struct line *doit();
32 static bool translate();
33 static void finishLine();
34 static bool settrans();
35 static bool aredups();
36 static char *gettrans();
37 static void numrefs();
38 static bool modtranslate();
39 static void devmodtranslate();
40 static void looksubmod();
41 #endif
42
43 struct subs {
44 char *su_name; /* The name. */
45 char *su_args; /* The arguments, space seperated. */
46 int su_numargs;
47 struct line *su_def; /* The deck that is to be substituted. */
48 struct subs *su_next;
49 } ;
50
51 static struct tab {
52 char *t_old;
53 char *t_new;
54 } table[512]; /* That had better be enough. */
55
56
57 /* Expand all subcircuits in the deck. This handles imbedded .subckt
58 * definitions. The variables substart, subend, and subinvoke can be used
59 * to redefine the controls used. The syntax is invariant though.
60 * NOTE: the deck must be passed without the title card.
61 * What we do is as follows: first make one pass through the circuit
62 * and collect all of the subcircuits. Then, whenever a card that starts
63 * with 'x' is found, copy the subcircuit associated with that name and
64 * splice it in. A few of the problems: the nodes in the spliced-in
65 * stuff must be unique, so when we copy it, append "subcktname:" to
66 * each node. If we are in a nested subcircuit, use foo:bar:...:node.
67 * Then we have to systematically change all references to the renamed
68 * nodes. On top of that, we have to know how many args BJT's have,
69 * so we have to keep track of model names.
70 */
71
72 static wordlist *modnames, *submod;
73 static struct subs *subs;
74 static bool nobjthack = false;
75
76 static char start[32], sbend[32], invoke[32], model[32];
77
78
79 struct line *
inp_subcktexpand(deck)80 inp_subcktexpand(deck)
81
82 struct line *deck;
83 {
84 struct line *ll, *c;
85 char *s;
86 extern char *kw_substart, *kw_subend, *kw_subinvoke, *kw_modelcard;
87 extern char *kw_nobjthack;
88
89 if (!cp_getvar(kw_substart, VT_STRING, start))
90 (void) strcpy(start, ".subckt");
91 if (!cp_getvar(kw_subend, VT_STRING, sbend))
92 (void) strcpy(sbend, ".ends");
93 if (!cp_getvar(kw_subinvoke, VT_STRING, invoke))
94 (void) strcpy(invoke, "X");
95 if (!cp_getvar(kw_modelcard, VT_STRING, model))
96 (void) strcpy(model, ".model");
97 (void) cp_getvar(kw_nobjthack, VT_BOOL, (char *) &nobjthack);
98
99 /* Let's do a few cleanup things first... Get rid of ( ) around node
100 * lists...
101 */
102 for (c = deck; c; c = c->li_next) {
103 if (prefix(start, c->li_line)) {
104 for (s = c->li_line; *s && (*s != '('); s++)
105 ;
106 if (*s) {
107 while (s[0] && (s[1] != ')')) {
108 s[0] = s[1];
109 s++;
110 }
111 while (s[1]) {
112 s[0] = s[2];
113 s++;
114 }
115 }
116 }
117 else {
118 for (s = c->li_line; *s && !isspace(*s); s++)
119 ;
120 while (isspace(*s))
121 s++;
122 if (*s == '(') {
123 while (s[0] && (s[1] != ')')) {
124 s[0] = s[1];
125 s++;
126 }
127 while (s[1]) {
128 s[0] = s[2];
129 s++;
130 }
131 }
132 }
133 }
134
135 ll = doit(deck);
136
137 /* Now check to see if there are still subckt instances undefined... */
138 if (ll) {
139 for (c = ll; c; c = c->li_next)
140 if (ciprefix(invoke, c->li_line)) {
141 fprintf(cp_err, "Error: unknown subckt: %s\n",
142 c->li_line);
143 ll = NULL;
144 }
145 }
146
147 return (ll);
148 }
149
150
151 #define MAXNEST 21
152
153 static struct line *
doit(deck)154 doit(deck)
155
156 struct line *deck;
157 {
158 struct line *c, *last, *lc, *lcc;
159 struct subs *sss;
160 char *s, *t, *tt, *scname, *subname;
161 int nest, numpasses = MAXNEST, i;
162 bool gotone;
163 wordlist *wl;
164 wordlist *tmodnames = modnames;
165 wordlist *tsubmod = submod;
166 struct subs *ts = subs;
167
168 /* Save all the old stuff... */
169 modnames = NULL;
170 subs = NULL;
171 submod = NULL;
172
173 /* Extract all the .subckts */
174 for (last = deck, lc = NULL; last; ) {
175 if (prefix(sbend, last->li_line)) {
176 fprintf(cp_err, "Error: misplaced %s card: %s\n", sbend,
177 last->li_line);
178 deck = NULL;
179 goto cleanup;
180 }
181 else if (prefix(start, last->li_line)) {
182 if (last->li_next == NULL) {
183 fprintf(cp_err, "Error: no %s card.\n", sbend);
184 deck = NULL;
185 goto cleanup;
186 }
187 gotone = false;
188 lcc = NULL;
189 for (nest = 0, c = last->li_next; c; lcc = c,c = c->li_next) {
190 if (prefix(sbend, c->li_line)) {
191 if (!nest)
192 break;
193 else {
194 nest--;
195 continue;
196 }
197 }
198 else if (prefix(start, c->li_line))
199 nest++;
200 }
201 if (!c) {
202 fprintf(cp_err, "Error: no %s card.\n", sbend);
203 deck = NULL;
204 goto cleanup;
205 }
206 if (lcc)
207 lcc->li_next = NULL;
208 else
209 last->li_next = NULL;
210
211 sss = alloc(struct subs);
212 if (lc)
213 lc->li_next = c->li_next;
214 else
215 deck = c->li_next;
216
217 sss->su_def = last->li_next;
218 s = last->li_line;
219 advtok(&s);
220 sss->su_name = gettok(&s);
221 sss->su_args = copy(s);
222 for (sss->su_numargs = 0, i = 0; s[i]; ) {
223 while (isspace(s[i]))
224 i++;
225 if (s[i]) {
226 sss->su_numargs++;
227 while (s[i] && !isspace(s[i]))
228 i++;
229 }
230 }
231 sss->su_next = subs;
232 subs = sss;
233
234 last->li_next = NULL;
235 inp_deckfree(last);
236
237 last = c->li_next;
238
239 c->li_next = NULL;
240 inp_deckfree(c);
241 }
242 else {
243 lc = last;
244 last = last->li_next;
245 }
246 }
247
248 /* Expand sub-subcircuits. */
249 for (sss = subs; sss; sss = sss->su_next)
250 if (sss->su_def) {
251 if (!(sss->su_def = doit(sss->su_def))) {
252 deck = NULL;
253 goto cleanup;
254 }
255 }
256
257 /* Get all the model names so we can deal with BJT's. */
258 for (c = deck; c; c = c->li_next)
259 if (prefix(model, c->li_line)) {
260 s = c->li_line;
261 advtok(&s);
262 wl = alloc(struct wordlist);
263 wl->wl_next = modnames;
264 if (modnames)
265 modnames->wl_prev = wl;
266 modnames = wl;
267 wl->wl_word = gettok(&s);
268 }
269
270 /* Now do the replacements. */
271 do {
272 gotone = false;
273 for (c = deck, lc = NULL; c; ) {
274 if (ciprefix(invoke, c->li_line)) {
275 char *tmpscname;
276 gotone = true;
277 t = s = copy(c->li_line);
278 tmpscname = scname = gettok(&s);
279 scname += strlen(invoke);
280 while ((*scname == ' ') || (*scname == '\t') ||
281 (*scname == ':'))
282 scname++;
283 while(*s)
284 s++;
285 s--;
286 while ((*s == ' ') || (*s == '\t'))
287 *s-- = '\0';
288 while ((*s != ' ') && (*s != '\t'))
289 s--;
290 s++;
291 for (sss = subs; sss; sss = sss->su_next)
292 if (eq(sss->su_name, s))
293 break;
294
295 /* Don't complain -- this might be an
296 * instance of a subckt that is defined above.
297 */
298 if (!sss) {
299 lc = c;
300 c = c->li_next;
301 txfree(tmpscname);
302 txfree(t);
303 continue;
304 }
305
306 if (!sss->su_def) {
307 /* null subccircuit, just clip out
308 * invocation and ignore
309 */
310 if (lc)
311 lc->li_next = c->li_next;
312 else
313 deck = c->li_next;
314
315 c->li_next = NULL;
316 inp_deckfree(c);
317
318 if (lc)
319 c = lc->li_next;
320 else
321 c = deck;
322
323 txfree(tmpscname);
324 txfree(t);
325 fprintf(cp_err,
326 "Warning: empty subcircuit %s referenced, ignored\n",
327 sss->su_name);
328 continue;
329 }
330
331 /* Now we have to replace this card with the
332 * macro definition.
333 */
334 subname = copy(sss->su_name);
335
336 lcc = inp_deckcopy(sss->su_def);
337
338 /* Change the names of the models... */
339 if (modtranslate(lcc, scname))
340 devmodtranslate(lcc, scname);
341
342 s = sss->su_args;
343 tt = t;
344 advtok(&t); /* Throw out the name. */
345
346 if (translate(lcc, s, t, scname, subname, c->li_line)) {
347 txfree(tmpscname);
348 tfree(subname);
349 txfree(tt);
350 deck = NULL;
351 goto cleanup;
352 }
353
354 txfree(tmpscname);
355 tfree(subname);
356 txfree(tt);
357
358 /* Now splice the decks together. */
359 if (lc)
360 lc->li_next = lcc;
361 else
362 deck = lcc;
363 while (lcc->li_next != NULL)
364 lcc = lcc->li_next;
365 lcc->li_next = c->li_next;
366
367 c->li_next = NULL;
368 inp_deckfree(c);
369 c = lcc->li_next;
370 lc = lcc;
371 }
372 else {
373 lc = c;
374 c = c->li_next;
375 }
376 }
377 } while (numpasses-- && gotone);
378
379 if (!numpasses) {
380 fprintf(cp_err, "Error: infinite subckt recursion\n");
381 deck = NULL;
382 }
383
384 cleanup:
385 wl_free(modnames);
386 wl_free(submod);
387 for (sss = subs; sss; sss = subs) {
388 subs = sss->su_next;
389 txfree(sss->su_name);
390 txfree(sss->su_args);
391 inp_deckfree(sss->su_def);
392 txfree((char*)sss);
393 }
394 subs = ts;
395 modnames = tmodnames;
396 submod = tsubmod;
397 return (deck);
398 }
399
400
401 static bool
translate(deck,formal,actual,scname,subname,instr)402 translate(deck, formal, actual, scname, subname, instr)
403
404 /* Translate all of the device names and node names in the deck. They are
405 * pre-pended with subname:, unless they are in the formal list, in which
406 * case they are replaced with the corresponding entry in the actual list.
407 * The one special case is node 0 -- this is always ground and we don't
408 * touch it.
409 */
410 struct line *deck;
411 char *formal, *actual, *scname, *subname, *instr;
412 {
413 struct line *c;
414 char *buffer, *name, *s, *t, ch;
415 int nnodes, ndevs, i;
416 char *tmpname;
417 bool retval = false;
418
419 if (settrans(formal, actual, subname, instr)) {
420 retval = true;
421 goto cleanup;
422 }
423
424 for (c = deck; c; c = c->li_next) {
425 /* Rename the device. */
426 ch = *c->li_line;
427 if (ch == '.' || ch == '*' || ch == '\0')
428 /* Nothing any good here. */
429 continue;
430
431 s = c->li_line;
432 tmpname = name = gettok(&s);
433 if (!name)
434 continue;
435 if (!*name) {
436 txfree(name);
437 continue;
438 }
439 ch = *name;
440 buffer = tmalloc(1000);
441 name++;
442 if (*name == ':')
443 name++;
444 if (*name)
445 (void) sprintf(buffer, "%c:%s:%s ", ch, scname, name);
446 else
447 (void) sprintf(buffer, "%c:%s ", ch, scname);
448 txfree(tmpname);
449
450 numrefs(c->li_line,&nnodes,&ndevs);
451 while (nnodes-- > 0) {
452 name = gettok(&s);
453 if (name == NULL) {
454 fprintf(cp_err, "Warning: too few nodes: %s\n", c->li_line);
455 retval = true;
456 txfree(name);
457 goto cleanup;
458 }
459 t = gettrans(name);
460 if (t)
461 (void) sprintf(buffer + strlen(buffer), "%s ", t);
462 else
463 (void) sprintf(buffer + strlen(buffer),
464 "%s:%s ", scname, name);
465 txfree(name);
466 }
467 while (ndevs-- > 0) {
468 tmpname = name = gettok(&s);
469 if (name == NULL) {
470 fprintf(cp_err, "Warning: too few devs: %s\n", c->li_line);
471 retval = true;
472 goto cleanup;
473 }
474 ch = *name;
475 name++;
476 if (*name == ':')
477 name++;
478 if (*name)
479 (void) sprintf(buffer + strlen(buffer),
480 "%c:%s:%s ", ch, scname, name);
481 else
482 (void) sprintf(buffer + strlen(buffer),
483 "%c:%s ", ch, scname);
484 txfree(tmpname);
485 }
486 /* Now scan through the line for v(something) and
487 * i(something)...
488 */
489 finishLine(buffer + strlen(buffer), s, scname);
490 txfree(c->li_line);
491 c->li_line = copy(buffer);
492 txfree(buffer);
493 }
494 cleanup:
495 for (i = 0; i < 512; i++) {
496 if (table[i].t_old == NULL) {
497 tfree(table[i].t_new);
498 break;
499 }
500 tfree(table[i].t_old);
501 tfree(table[i].t_new);
502 }
503 return retval;
504 }
505
506
507 static void
finishLine(dst,src,scname)508 finishLine(dst, src, scname)
509
510 char *dst;
511 char *src;
512 char *scname;
513 {
514 char buf[4 * BSIZE_SP], which;
515 char *s;
516 int i;
517 int lastwasalpha;
518
519 lastwasalpha = 0;
520 while (*src) {
521 /* Find the next instance of "<non-alpha>[vi]<opt spaces>(" in
522 * this string.
523 */
524 if (((*src != 'v') && (*src != 'V') &&
525 (*src != 'i') && (*src != 'I')) ||
526 lastwasalpha) {
527 lastwasalpha = isalpha(*src);
528 *dst++ = *src++;
529 continue;
530 }
531 for (s = src + 1; *s && isspace(*s); s++)
532 ;
533 if (!*s || (*s != '(')) {
534 lastwasalpha = isalpha(*src);
535 *dst++ = *src++;
536 continue;
537 }
538 lastwasalpha = 0;
539 which = *dst++ = *src;
540 src = s;
541 *dst++ = *src++;
542 while (isspace(*src))
543 src++;
544 for (i = 0;
545 *src && !isspace(*src) && *src != ',' && (*src != ')'); i++) {
546 buf[i] = *src++;
547 }
548 buf[i] = '\0';
549
550 if ((which == 'v') || (which == 'V'))
551 s = gettrans(buf);
552 else
553 s = NULL;
554
555 if (s) {
556 while (*s)
557 *dst++ = *s++;
558 }
559 else {
560 /*
561 * i(vname) -> i(v:subckt:name)
562 * i(v:other:name) -> i(v:subckt:other:name)
563 */
564 if (buf[0] == 'v' || buf[0] == 'V') {
565 *dst++ = buf[0];
566 *dst++ = ':';
567 i = 1;
568 }
569 else {
570 i = 0;
571 }
572 for (s = scname; *s; )
573 *dst++ = *s++;
574 *dst++ = ':';
575 for (s = buf + i; *s; )
576 *dst++ = *s++;
577 }
578
579 /* translate the reference node, as in the "2" in "v(4,2)" */
580
581 if ((which == 'v') || (which == 'V')) {
582 while (*src && (isspace(*src) || *src == ',')) {
583 src++;
584 }
585 if (*src && *src != ')') {
586 for (i = 0; *src && !isspace(*src) && (*src != ')'); i++)
587 buf[i] = *src++;
588 buf[i] = '\0';
589 s = gettrans(buf);
590 *dst++ = ',';
591 if (s) {
592 while (*s)
593 *dst++ = *s++;
594 }
595 else {
596 for (s = scname; *s; )
597 *dst++ = *s++;
598 *dst++ = ':';
599 for (s = buf; *s; )
600 *dst++ = *s++;
601 }
602 }
603 }
604 }
605 return;
606 }
607
608
609 static bool
settrans(formal,actual,subname,instr)610 settrans(formal, actual, subname, instr)
611
612 char *formal, *actual, *subname, *instr;
613 {
614 int i;
615
616 for (i = 0; ; i++) {
617 table[i].t_old = gettok(&formal);
618 table[i].t_new = gettok(&actual);
619
620 if (table[i].t_new == NULL) {
621 fprintf(cp_err, "Error: too many params: %s\n", instr);
622 return (true); /* Too few formal / too many actual */
623 }
624 if (table[i].t_old == NULL) {
625 if (eq(table[i].t_new, subname))
626 break;
627 else {
628 fprintf(cp_err, "Error: too few params: %s\n", instr);
629 return (true); /* Too few actual / too many formal */
630 }
631 }
632 }
633 if (aredups()) {
634 fprintf(cp_err,
635 "Error: duplicate nodes given in subckt %s\n",subname);
636 return (true);
637 }
638 return (false);
639 }
640
641
642 static bool
aredups()643 aredups()
644
645 {
646 int i, j;
647 char *s;
648
649 for (i = 0; table[i].t_old; i++) {
650 s = table[i].t_old;
651 for (j = i+1; table[j].t_old; j++) {
652 if (eq(s,table[j].t_old))
653 return (true);
654 }
655 }
656 return (false);
657 }
658
659
660 static char *
gettrans(name)661 gettrans(name)
662
663 char *name;
664 {
665 int i;
666
667 if (eq(name, "0"))
668 return (name);
669 for (i = 0; table[i].t_old; i++)
670 if (eq(table[i].t_old, name))
671 return (table[i].t_new);
672 return (NULL);
673 }
674
675
676 static void
numrefs(name,terms,devs)677 numrefs(name,terms,devs)
678
679 char *name;
680 int *terms, *devs;
681 {
682 char c;
683 struct subs *sss;
684 char *s, *t, buf[4 * BSIZE_SP];
685 wordlist *wl;
686 int n, i, soft;
687
688 while (*name && isspace(*name))
689 name++;
690
691 c = (isupper(*name) ? tolower(*name) : *name);
692
693 (void) strncpy(buf, name, sizeof(buf));
694 s = buf;
695 if (c == 'x') { /* Handle this ourselves. */
696 while(*s)
697 s++;
698 s--;
699 while ((*s == ' ') || (*s == '\t'))
700 *s-- = '\0';
701 while ((*s != ' ') && (*s != '\t'))
702 s--;
703 s++;
704 for (sss = subs; sss; sss = sss->su_next)
705 if (eq(sss->su_name, s))
706 break;
707 if (!sss) {
708 *terms = 0;
709 *devs = 0;
710 fprintf(cp_err, "Error: no such subcircuit: %s\n", s);
711 return;
712 }
713 *terms = sss->su_numargs;
714 *devs = 0;
715 return;
716 }
717
718 (void)INPnumRefs(c,&n,devs,&soft,NULL);
719 if (isalpha(c) && n == 0 && *devs == 0)
720 fprintf(cp_err, "Warning: unknown device key: %c\n", c);
721
722 if (!soft) {
723 *terms = n;
724 return;
725 }
726 for (s = buf, i = 0; *s && (i < n); i++)
727 advtok(&s);
728 if (i == n-1) {
729 *terms = n-1;
730 return;
731 }
732 else if (i < n) {
733 fprintf(cp_err, "Error: too few nodes for %s\n", name);
734 *terms = 0;
735 return;
736 }
737 /* Now, is this a model? */
738 t = gettok(&s);
739 for (wl = modnames; wl; wl = wl->wl_next) {
740 if (eq(t, wl->wl_word)) {
741 txfree(t);
742 *terms = n-1;
743 return;
744 }
745 }
746 txfree(t);
747 *terms = n;
748 return;
749 }
750
751
752 static bool
modtranslate(deck,subname)753 modtranslate(deck, subname)
754
755 struct line *deck;
756 char *subname;
757 {
758 struct line *c;
759 char *buffer, *name, *t;
760 wordlist *wl, *wlsub;
761 bool gotone;
762
763 gotone = false;
764 for (c = deck; c; c = c->li_next) {
765 if (prefix(model, c->li_line)) {
766 gotone = true;
767 t = c->li_line;
768 name = gettok(&t);
769 buffer = tmalloc(strlen(name) + strlen(t) +
770 strlen(subname) + 4);
771 (void) sprintf(buffer, "%s ",name);
772 txfree(name);
773 name = gettok(&t);
774 wlsub = alloc(struct wordlist);
775 wlsub->wl_next = submod;
776 if (submod)
777 submod->wl_prev = wlsub;
778 submod = wlsub;
779 wlsub->wl_word = name;
780 (void) sprintf(buffer + strlen(buffer), "%s:%s ",
781 subname, name);
782 (void) strcat(buffer, t);
783 txfree(c->li_line);
784 c->li_line = buffer;
785 t = c->li_line;
786 advtok(&t);
787 wl = alloc(struct wordlist);
788 wl->wl_next = modnames;
789 if (modnames)
790 modnames->wl_prev = wl;
791 modnames = wl;
792 wl->wl_word = gettok(&t);
793 }
794 }
795 return (gotone);
796 }
797
798
799 static void
devmodtranslate(deck,subname)800 devmodtranslate(deck, subname)
801
802 struct line *deck;
803 char *subname;
804 {
805 struct line *s;
806 char *buffer, *name, *t, c;
807 int terms, devs, soft, hasmod;
808
809 for (s = deck; s; s = s->li_next) {
810 t = s->li_line;
811 while (*t && isspace(*t))
812 t++;
813 c = isupper(*t) ? tolower(*t) : *t;
814
815 INPnumRefs(c,&terms,&devs,&soft,&hasmod);
816 if (!hasmod)
817 continue;
818
819 buffer = tmalloc(strlen(t) + strlen(subname) + 4);
820
821 terms += devs + 1;
822 if (soft) terms--;
823 *buffer = '\0';
824 while (terms--)
825 copytok1(buffer + strlen(buffer),&t);
826
827 looksubmod(&t,buffer,subname);
828 if (soft)
829 looksubmod(&t,buffer,subname);
830 (void) strcat(buffer, t);
831 txfree(s->li_line);
832 s->li_line = buffer;
833 }
834 }
835
836
837 static void
looksubmod(t,buffer,subname)838 looksubmod(t,buffer,subname)
839
840 char **t, *buffer, *subname;
841 {
842 wordlist *wlsub;
843 char *name;
844 bool found = false;;
845
846 if (**t == '\0') return;
847 name = gettok(t);
848 /* Now, is this a subcircuit model? */
849 for (wlsub = submod; wlsub; wlsub = wlsub->wl_next)
850 if (eq(name, wlsub->wl_word)) {
851 (void) sprintf(buffer + strlen(buffer), "%s:%s ", subname, name);
852 found = true;
853 break;
854 }
855 if (!found)
856 (void) sprintf(buffer + strlen(buffer), "%s ", name);
857 txfree(name);
858 }
859
860
861
862
863
864
865
866