1 /**********
2 Copyright 1990 Regents of the University of California. All rights reserved.
3 Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
4 Modified: 2000 AlansFixes
5 **********/
6
7 /*
8 * Routines to query and alter devices.
9 */
10
11 #include "ngspice/ngspice.h"
12 #include "ngspice/gendefs.h"
13 #include "ngspice/cktdefs.h"
14 #include "ngspice/cpdefs.h"
15 #include "ngspice/ftedefs.h"
16 #include "ngspice/dgen.h"
17 #include "ngspice/sim.h"
18
19 #include "circuits.h"
20 #include "device.h"
21 #include "variable.h"
22 #include "com_commands.h"
23 #include "../misc/util.h" /* ngdirname() */
24
25 #include "gens.h" /* wl_forall */
26
27
28 static wordlist *devexpand(char *name);
29 static void all_show(wordlist *wl, int mode);
30 static void all_show_old(wordlist *wl, int mode);
31 static void com_alter_mod(wordlist *wl);
32 static void if_set_binned_model(CKTcircuit *, char *, char *, struct dvec *);
33
34
35 /*
36 * devhelp: lists available devices and information on parameters
37 * devhelp : shows all available devices
38 * devhelp devname : shows all parameters of that model/instance
39 * devhelp devname parname : shows parameter meaning
40 * Options: -csv (comma separated value for generating docs)
41 */
42
43 void
com_devhelp(wordlist * wl)44 com_devhelp(wordlist *wl)
45 {
46 /* Just a simple driver now */
47 devhelp(wl);
48 }
49
50
51 void
devhelp(wordlist * wl)52 devhelp(wordlist *wl)
53 {
54 int i, k = 0;
55 int devindex = -1, devInstParNo = 0, devModParNo = 0;
56 bool found = FALSE;
57 bool csv = FALSE;
58 wordlist *wlist;
59 IFparm *plist;
60
61 /*First copy the base pointer */
62 wlist = wl;
63
64 /* If there are no arguments output the list of available devices */
65 if (!wlist) {
66 out_init();
67 out_printf("\nDevices available in the simulator\n\n");
68 for (k = 0; k < ft_sim->numDevices; k++)
69 if (ft_sim->devices[k])
70 out_printf("%-*s:\t%s\n",
71 DEV_WIDTH, ft_sim->devices[k]->name,
72 ft_sim->devices[k]->description);
73 out_send("\n");
74 return;
75 }
76
77 /* The first argument must be the csv option or a device name */
78 if (wlist && wlist->wl_word && eq(wlist->wl_word, "-csv")) {
79 csv = TRUE;
80 if (wlist->wl_next)
81 wlist = wlist->wl_next;
82 else
83 return;
84 }
85
86 /* This argument, if exists, must be the device name */
87 if (wlist && wlist->wl_word) {
88 while (k < ft_sim->numDevices && !found) {
89 if (ft_sim->devices[k])
90 if (strcasecmp(ft_sim->devices[k]->name, wlist->wl_word) == 0) {
91 devindex = k;
92 if (ft_sim->devices[devindex]->numInstanceParms)
93 devInstParNo = *(ft_sim->devices[devindex]->numInstanceParms);
94 else
95 devInstParNo = 0;
96
97 if (ft_sim->devices[devindex]->numModelParms)
98 devModParNo = *(ft_sim->devices[devindex]->numModelParms);
99 else
100 devModParNo = 0;
101
102 wlist = wlist->wl_next;
103 found = TRUE;
104 }
105 k++;
106 }
107
108 if (!found) {
109 fprintf(cp_out, "Error: Device %s not found\n", wlist->wl_word);
110 return;
111 }
112 }
113
114 /* At this point, found is TRUE and we have found the device.
115 * Now we have to scan the model and instance parameters to print
116 * the string
117 */
118 found = FALSE;
119 if (wlist && wlist->wl_word) {
120 plist = ft_sim->devices[devindex]->modelParms;
121 for (i = 0; i < devModParNo; i++) { /* Scan model parameters first */
122 if (strcasecmp(plist[i].keyword, wlist->wl_word) == 0) {
123 found = TRUE;
124 out_init();
125 out_printf("Model Parameters\n");
126 if (csv)
127 out_printf("id#, Name, Dir, Description\n");
128 else
129 out_printf("%5s\t %-10s\t Dir\t Description\n", "id#", "Name");
130 printdesc(plist[i], csv);
131 out_send("\n");
132 }
133 }
134
135 if (!found) {
136 plist = ft_sim->devices[devindex]->instanceParms;
137 for (i = 0; i < devInstParNo; i++) { /* Scan instance parameters then */
138 if (strcasecmp(plist[i].keyword, wlist->wl_word) == 0) {
139 found = TRUE;
140 out_init();
141 out_printf("Instance Parameters\n");
142 if (csv)
143 out_printf("id#, Name, Dir, Description\n");
144 else
145 out_printf("%5s\t %-10s\t Dir\t Description\n", "id#", "Name");
146 printdesc(plist[i], csv);
147 out_send("\n");
148 }
149 }
150 }
151
152 if (!found)
153 fprintf(cp_out, "Error: Parameter %s not found\n", wlist->wl_word);
154 return;
155
156 }
157
158 /* No arguments - we want all the parameters*/
159 out_init();
160 out_printf("%s - %s\n\n", ft_sim->devices[devindex]->name, ft_sim->devices[devindex]->description);
161 out_printf("Model Parameters\n");
162 if (csv)
163 out_printf("id#, Name, Dir, Description\n");
164 else
165 out_printf("%5s\t %-10s\t Dir\t Description\n", "id#", "Name");
166
167 plist = ft_sim->devices[devindex]->modelParms;
168 for (i = 0; i < devModParNo; i++)
169 printdesc(plist[i], csv);
170 out_printf("\n");
171 out_printf("Instance Parameters\n");
172 if (csv)
173 out_printf("id#, Name, Dir, Description\n");
174 else
175 out_printf("%5s\t %-10s\t Dir\t Description\n", "id#", "Name");
176
177 plist = ft_sim->devices[devindex]->instanceParms;
178 for (i = 0; i < devInstParNo; i++)
179 printdesc(plist[i], csv);
180
181 out_send("\n");
182 }
183
184
185 /*
186 * Pretty print parameter descriptions
187 * This function prints description of device parameters
188 */
189
190 void
printdesc(IFparm p,bool csv)191 printdesc(IFparm p, bool csv)
192 {
193 char sep;
194 int spacer1, spacer2;
195
196 /* First we indentify the separator */
197 if (csv) {
198 sep = ',';
199 spacer1 = 0;
200 spacer2 = 0;
201 } else {
202 sep = '\t';
203 spacer1 = 5;
204 spacer2 = 10;
205 }
206
207 out_printf("%*d%c %-*s%c ", spacer1, p.id, sep, spacer2, p.keyword, sep);
208
209 if (p.dataType & IF_SET)
210 if (p.dataType & IF_ASK)
211 out_printf("inout%c ", sep);
212 else
213 out_printf("in%c ", sep);
214 else
215 out_printf("out%c ", sep);
216
217 if (p.description)
218 out_printf("%s\n", p.description);
219 else
220 out_printf("n.a.\n");
221 }
222
223
224 /*
225 * show: list device operating point info
226 * show
227 * show devs : params
228 * show devs : params ; devs : params
229 * show dev dev dev : param param param , dev dev : param param
230 * show t : param param param, t : param param
231 */
232
233 static int count;
234
235 void
com_showmod(wordlist * wl)236 com_showmod(wordlist *wl)
237 {
238 if (cp_getvar("altshow", CP_BOOL, NULL, 0))
239 all_show(wl, 1);
240 else
241 all_show_old(wl, 1);
242 }
243
244
245 void
com_show(wordlist * wl)246 com_show(wordlist *wl)
247 {
248 if (cp_getvar("altshow", CP_BOOL, NULL, 0))
249 all_show(wl, 0);
250 else
251 all_show_old(wl, 0);
252 }
253
254
255 static void
all_show(wordlist * wl,int mode)256 all_show(wordlist *wl, int mode)
257 {
258 wordlist *params, *nextgroup, *thisgroup;
259 wordlist *prev, *next, *w;
260 int screen_width;
261 dgen *dg;
262 int instances;
263 int i, j, n;
264 int param_flag, dev_flag;
265
266 if (!ft_curckt || !ft_curckt->ci_ckt) {
267 fprintf(cp_err, "Error: no circuit loaded\n");
268 return;
269 }
270
271 if (wl && wl->wl_word && eq(wl->wl_word, "-v")) {
272 old_show(wl->wl_next);
273 return;
274 }
275
276 if (!cp_getvar("width", CP_NUM, &screen_width, 0))
277 screen_width = DEF_WIDTH;
278 count = (screen_width - LEFT_WIDTH) / (DEV_WIDTH + 1);
279 count = 1;
280
281 n = 0;
282 do {
283 prev = NULL;
284 params = NULL;
285 nextgroup = NULL;
286 thisgroup = wl;
287 param_flag = 0;
288 dev_flag = 0;
289
290 /* find the parameter list and the nextgroup */
291 for (w = wl; w && !nextgroup; w = next) {
292 next = w->wl_next;
293
294 if (eq(w->wl_word, "*")) {
295 tfree(w->wl_word);
296 w->wl_word = copy("all");
297 }
298
299 if (eq(w->wl_word, "++") || eq(w->wl_word, "all")) {
300 if (params) {
301 param_flag = DGEN_ALLPARAMS;
302 if (prev)
303 prev->wl_next = w->wl_next;
304 else
305 params = next;
306 } else {
307 dev_flag = DGEN_ALLDEVS;
308 if (prev)
309 prev->wl_next = w->wl_next;
310 else
311 thisgroup = next;
312 }
313 /* w must not be freed here */
314 w = NULL;
315 } else if (eq(w->wl_word, "+")) {
316 if (params) {
317 param_flag = DGEN_DEFPARAMS;
318 if (prev)
319 prev->wl_next = w->wl_next;
320 else
321 params = next;
322 } else {
323 dev_flag = DGEN_DEFDEVS;
324 if (prev)
325 prev->wl_next = w->wl_next;
326 else
327 thisgroup = next;
328 }
329 /* w must not be freed here */
330 w = NULL;
331 } else if (eq(w->wl_word, ":")) {
332 /* w must not be freed here */
333 w = NULL;
334 if (!params) {
335 params = next;
336 if (prev)
337 prev->wl_next = NULL;
338 else
339 thisgroup = NULL;
340 } else {
341 if (prev)
342 prev->wl_next = next;
343 else
344 params = next;
345 }
346 } else if (eq(w->wl_word, ";") || eq(w->wl_word, ",")) {
347 nextgroup = next;
348 /* w must not be freed here */
349 w = NULL;
350 if (prev)
351 prev->wl_next = NULL;
352 break;
353 }
354 prev = w;
355 }
356
357 instances = 0;
358 for (dg = dgen_init(ft_curckt->ci_ckt, thisgroup, 1, dev_flag, mode);
359 dg; dgen_nth_next(&dg, count))
360 {
361 instances = 1;
362 if (dg->flags & DGEN_INSTANCE) {
363 instances = 2;
364 n += 1;
365
366 fprintf(cp_out, "%s:\n", dg->instance->GENname);
367 fprintf(cp_out, " %-19s= %s\n", "model", dg->model->GENmodName);
368
369 if (param_flag)
370 param_forall(dg, param_flag);
371 else if (!params)
372 param_forall(dg, DGEN_DEFPARAMS);
373
374 if (params)
375 wl_forall(params, listparam, dg);
376
377 } else if (ft_sim->devices[dg->dev_type_no]->numModelParms) {
378 fprintf(cp_out, " %s models (%s)\n",
379 ft_sim->devices[dg->dev_type_no]->name,
380 ft_sim->devices[dg->dev_type_no]->description);
381 n += 1;
382 i = 0;
383 do {
384 fprintf(cp_out, "%*s", LEFT_WIDTH, "model");
385 j = dgen_for_n(dg, count, printstr_m, NULL, i);
386 i += 1;
387 fprintf(cp_out, "\n");
388 } while (j);
389 fprintf(cp_out, "\n");
390
391 if (param_flag)
392 param_forall(dg, param_flag);
393 else if (!params)
394 param_forall(dg, DGEN_DEFPARAMS);
395
396 if (params)
397 wl_forall(params, listparam, dg);
398 fprintf(cp_out, "\n");
399 }
400 }
401
402 wl = nextgroup;
403
404 } while (wl);
405
406 if (!n) {
407 if (instances == 0)
408 printf("No matching instances or models\n");
409 else if (instances == 1)
410 printf("No matching models\n");
411 else
412 printf("No matching elements\n");
413 }
414 }
415
416
417 static void
all_show_old(wordlist * wl,int mode)418 all_show_old(wordlist *wl, int mode)
419 {
420 wordlist *params, *nextgroup, *thisgroup;
421 wordlist *prev, *next, *w;
422 int screen_width;
423 dgen *dg;
424 int instances;
425 int i, j, n;
426 int param_flag, dev_flag;
427
428 if (!ft_curckt || !ft_curckt->ci_ckt) {
429 fprintf(cp_err, "Error: no circuit loaded\n");
430 return;
431 }
432
433 if (wl && wl->wl_word && eq(wl->wl_word, "-v")) {
434 old_show(wl->wl_next);
435 return;
436 }
437
438 if (!cp_getvar("width", CP_NUM, &screen_width, 0))
439 screen_width = DEF_WIDTH;
440 count = (screen_width - LEFT_WIDTH) / (DEV_WIDTH + 1);
441
442 n = 0;
443 do {
444 prev = NULL;
445 params = NULL;
446 nextgroup = NULL;
447 thisgroup = wl;
448 param_flag = 0;
449 dev_flag = 0;
450
451 /* find the parameter list and the nextgroup */
452 for (w = wl; w && !nextgroup; w = next) {
453 next = w->wl_next;
454
455 if (eq(w->wl_word, "*")) {
456 tfree(w->wl_word);
457 w->wl_word = copy("all");
458 }
459
460 if (eq(w->wl_word, "++") || eq(w->wl_word, "all")) {
461 if (params) {
462 param_flag = DGEN_ALLPARAMS;
463 if (prev)
464 prev->wl_next = w->wl_next;
465 else
466 params = next;
467 } else {
468 dev_flag = DGEN_ALLDEVS;
469 if (prev)
470 prev->wl_next = w->wl_next;
471 else
472 thisgroup = next;
473 }
474 /* w must not be freed here */
475 w = NULL;
476 } else if (eq(w->wl_word, "+")) {
477 if (params) {
478 param_flag = DGEN_DEFPARAMS;
479 if (prev)
480 prev->wl_next = w->wl_next;
481 else
482 params = next;
483 } else {
484 dev_flag = DGEN_DEFDEVS;
485 if (prev)
486 prev->wl_next = w->wl_next;
487 else
488 thisgroup = next;
489 }
490 /* w must not be freed here */
491 w = NULL;
492 } else if (eq(w->wl_word, ":")) {
493 /* w must not be freed here */
494 w = NULL;
495 if (!params) {
496 params = next;
497 if (prev)
498 prev->wl_next = NULL;
499 else
500 thisgroup = NULL;
501 } else {
502 if (prev)
503 prev->wl_next = next;
504 else
505 params = next;
506 }
507 } else if (eq(w->wl_word, ";") || eq(w->wl_word, ",")) {
508 nextgroup = next;
509 /* w must not be freed here */
510 w = NULL;
511 if (prev)
512 prev->wl_next = NULL;
513 break;
514 }
515 prev = w;
516 }
517
518 instances = 0;
519 for (dg = dgen_init(ft_curckt->ci_ckt, thisgroup, 1, dev_flag, mode);
520 dg; dgen_nth_next(&dg, count))
521 {
522 instances = 1;
523 if (dg->flags & DGEN_INSTANCE) {
524 instances = 2;
525 fprintf(cp_out, " %s: %s\n",
526 ft_sim->devices[dg->dev_type_no]->name,
527 ft_sim->devices[dg->dev_type_no]->description);
528 n += 1;
529
530 i = 0;
531 do {
532 fprintf(cp_out, "%*s", LEFT_WIDTH, "device");
533 j = dgen_for_n(dg, count, printstr_n, NULL, i);
534 i += 1;
535 fprintf(cp_out, "\n");
536 } while (j);
537
538 if (ft_sim->devices[dg->dev_type_no]->numModelParms) {
539 i = 0;
540 do {
541 fprintf(cp_out, "%*s", LEFT_WIDTH, "model");
542 j = dgen_for_n(dg, count, printstr_m, NULL, i);
543 i += 1;
544 fprintf(cp_out, "\n");
545 } while (j);
546 }
547
548 if (param_flag)
549 param_forall_old(dg, param_flag);
550 else if (!params)
551 param_forall_old(dg, DGEN_DEFPARAMS);
552
553 if (params)
554 wl_forall(params, listparam, dg);
555 fprintf(cp_out, "\n");
556
557 } else if (ft_sim->devices[dg->dev_type_no]->numModelParms) {
558 fprintf(cp_out, " %s models (%s)\n",
559 ft_sim->devices[dg->dev_type_no]->name,
560 ft_sim->devices[dg->dev_type_no]->description);
561 n += 1;
562 i = 0;
563 do {
564 fprintf(cp_out, "%*s", LEFT_WIDTH, "model");
565 j = dgen_for_n(dg, count, printstr_m, NULL, i);
566 i += 1;
567 fprintf(cp_out, "\n");
568 } while (j);
569 fprintf(cp_out, "\n");
570
571 if (param_flag)
572 param_forall_old(dg, param_flag);
573 else if (!params)
574 param_forall_old(dg, DGEN_DEFPARAMS);
575
576 if (params)
577 wl_forall(params, listparam, dg);
578 fprintf(cp_out, "\n");
579 }
580 }
581
582 wl = nextgroup;
583
584 } while (wl);
585
586 if (!n) {
587 if (instances == 0)
588 printf("No matching instances or models\n");
589 else if (instances == 1)
590 printf("No matching models\n");
591 else
592 printf("No matching elements\n");
593 }
594 }
595
596
597 int
printstr_n(dgen * dg,IFparm * p,int i)598 printstr_n(dgen *dg, IFparm *p, int i)
599 {
600 NG_IGNORE(p);
601 NG_IGNORE(i);
602
603 if (dg->instance)
604 fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, dg->instance->GENname);
605 else
606 fprintf(cp_out, " %*s", DEV_WIDTH, "<\?\?\?\?\?\?\?>");
607 return 0;
608 }
609
610
611 int
printstr_m(dgen * dg,IFparm * p,int i)612 printstr_m(dgen *dg, IFparm *p, int i)
613 {
614 NG_IGNORE(p);
615 NG_IGNORE(i);
616
617 if (dg->model)
618 fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, dg->model->GENmodName);
619 else
620 fprintf(cp_out, " %*s", DEV_WIDTH, "<\?\?\?\?\?\?\?>");
621 return 0;
622 }
623
624
625 void
param_forall(dgen * dg,int flags)626 param_forall(dgen *dg, int flags)
627 {
628 int i, j, k;
629 int xcount;
630 IFparm *plist;
631
632 if (dg->flags & DGEN_INSTANCE) {
633 xcount = *ft_sim->devices[dg->dev_type_no]->numInstanceParms;
634 plist = ft_sim->devices[dg->dev_type_no]->instanceParms;
635 } else {
636 xcount = *ft_sim->devices[dg->dev_type_no]->numModelParms;
637 plist = ft_sim->devices[dg->dev_type_no]->modelParms;
638 }
639
640 for (i = 0; i < xcount; i++)
641 if ((plist[i].dataType & IF_ASK)
642 && !(plist[i].dataType & IF_REDUNDANT)
643 && ((plist[i].dataType & IF_SET) || dg->ckt->CKTrhsOld)
644 && (!(plist[i].dataType & IF_UNINTERESTING) || (flags == DGEN_ALLPARAMS)))
645 {
646 j = 0;
647 do {
648 fprintf(cp_out, " %-19s=", plist[i].keyword);
649
650 k = dgen_for_n(dg, count, printvals, (plist + i), j);
651 fprintf(cp_out, "\n");
652 j += 1;
653
654 } while (k);
655 }
656 }
657
658
659 void
param_forall_old(dgen * dg,int flags)660 param_forall_old(dgen *dg, int flags)
661 {
662 int i, j, k;
663 int xcount;
664 IFparm *plist;
665
666 if (dg->flags & DGEN_INSTANCE) {
667 xcount = *ft_sim->devices[dg->dev_type_no]->numInstanceParms;
668 plist = ft_sim->devices[dg->dev_type_no]->instanceParms;
669 } else {
670 xcount = *ft_sim->devices[dg->dev_type_no]->numModelParms;
671 plist = ft_sim->devices[dg->dev_type_no]->modelParms;
672 }
673
674 for (i = 0; i < xcount; i++)
675 if ((plist[i].dataType & IF_ASK)
676 && !(plist[i].dataType & IF_REDUNDANT)
677 && ((plist[i].dataType & IF_SET) || dg->ckt->CKTrhsOld)
678 && (!(plist[i].dataType & IF_UNINTERESTING) || (flags == DGEN_ALLPARAMS)))
679 {
680 j = 0;
681 do {
682 if (!j)
683 fprintf(cp_out, "%*.*s", LEFT_WIDTH, LEFT_WIDTH,
684 plist[i].keyword);
685 else
686 fprintf(cp_out, "%*.*s", LEFT_WIDTH, LEFT_WIDTH, " ");
687 k = dgen_for_n(dg, count, printvals_old, (plist + i), j);
688 fprintf(cp_out, "\n");
689 j += 1;
690 } while (k);
691 }
692 }
693
694
695 void
listparam(wordlist * p,dgen * dg)696 listparam(wordlist *p, dgen *dg)
697 {
698 int i, j, k, found;
699 int xcount;
700 IFparm *plist;
701
702 found = 0;
703
704 if (dg->flags & DGEN_INSTANCE) {
705 xcount = *ft_sim->devices[dg->dev_type_no]->numInstanceParms;
706 plist = ft_sim->devices[dg->dev_type_no]->instanceParms;
707 } else {
708 xcount = *ft_sim->devices[dg->dev_type_no]->numModelParms;
709 plist = ft_sim->devices[dg->dev_type_no]->modelParms;
710 }
711
712 for (i = 0; i < xcount; i++)
713 if (eqc(p->wl_word, plist[i].keyword) && (plist[i].dataType & IF_ASK)) {
714 found = 1;
715 break;
716 }
717
718 if (found) {
719 if (dg->ckt->CKTrhsOld ||
720 (plist[i].dataType & IF_SET))
721 {
722 j = 0;
723 do {
724 if (!j)
725 fprintf(cp_out, "%*.*s", LEFT_WIDTH, LEFT_WIDTH, p->wl_word);
726 else
727 fprintf(cp_out, "%*.*s", LEFT_WIDTH, LEFT_WIDTH, " ");
728 k = dgen_for_n(dg, count, printvals_old, (plist + i), j);
729 printf("\n");
730 j += 1;
731 } while (k > 0);
732 } else {
733 j = 0;
734 do {
735 if (!j)
736 fprintf(cp_out, "%*.*s", LEFT_WIDTH, LEFT_WIDTH, p->wl_word);
737 else
738 fprintf(cp_out, "%*s", LEFT_WIDTH, " ");
739 k = dgen_for_n(dg, count, bogus1, NULL, j);
740 fprintf(cp_out, "\n");
741 j += 1;
742 } while (k > 0);
743 }
744 } else {
745 j = 0;
746 do {
747 if (!j)
748 fprintf(cp_out, "%*.*s", LEFT_WIDTH, LEFT_WIDTH, p->wl_word);
749 else
750 fprintf(cp_out, "%*s", LEFT_WIDTH, " ");
751 k = dgen_for_n(dg, count, bogus2, NULL, j);
752 fprintf(cp_out, "\n");
753 j += 1;
754 } while (k > 0);
755 }
756 }
757
758
759 int
bogus1(dgen * dg,IFparm * p,int i)760 bogus1(dgen *dg, IFparm *p, int i)
761 {
762 NG_IGNORE(dg);
763 NG_IGNORE(p);
764 NG_IGNORE(i);
765
766 fprintf(cp_out, " %*s", DEV_WIDTH, "---------");
767 return 0;
768 }
769
770
771 int
bogus2(dgen * dg,IFparm * p,int i)772 bogus2(dgen *dg, IFparm *p, int i)
773 {
774 NG_IGNORE(dg);
775 NG_IGNORE(p);
776 NG_IGNORE(i);
777
778 fprintf(cp_out, " %*s", DEV_WIDTH, "?????????");
779 return 0;
780 }
781
782
783 int
printvals(dgen * dg,IFparm * p,int i)784 printvals(dgen *dg, IFparm *p, int i)
785 {
786 IFvalue val;
787 int n;
788
789 if (dg->flags & DGEN_INSTANCE)
790 ft_sim->askInstanceQuest
791 (ft_curckt->ci_ckt, dg->instance, p->id, &val, &val);
792 else
793 ft_sim->askModelQuest
794 (ft_curckt->ci_ckt, dg->model, p->id, &val, &val);
795
796 if (p->dataType & IF_VECTOR)
797 n = val.v.numValue;
798 else
799 n = 1;
800
801 if (((p->dataType & IF_VARTYPES) & ~IF_VECTOR) == IF_COMPLEX)
802 n *= 2;
803
804 if (i >= n) {
805 if (i == 0)
806 fprintf(cp_out, " -");
807 else
808 fprintf(cp_out, " ");
809 return 0;
810 }
811
812 if (p->dataType & IF_VECTOR) {
813 /* va: ' ' is no flag for %s */
814 switch ((p->dataType & IF_VARTYPES) & ~IF_VECTOR) {
815 case IF_FLAG:
816 fprintf(cp_out, " %d", val.v.vec.iVec[i]);
817 break;
818 case IF_INTEGER:
819 fprintf(cp_out, " %d", val.v.vec.iVec[i]);
820 break;
821 case IF_REAL:
822 fprintf(cp_out, " %.6g", val.v.vec.rVec[i]);
823 break;
824 case IF_COMPLEX:
825 if (!(i % 2))
826 fprintf(cp_out, " %.6g", val.v.vec.cVec[i / 2].real);
827 else
828 fprintf(cp_out, " %.6g", val.v.vec.cVec[i / 2].imag);
829 break;
830 case IF_STRING:
831 fprintf(cp_out, " %s", val.v.vec.sVec[i]);
832 break;
833 case IF_INSTANCE:
834 fprintf(cp_out, " %s", val.v.vec.uVec[i]);
835 break;
836 default:
837 fprintf(cp_out, " %s", " ******** ");
838 }
839 } else {
840 switch ((p->dataType & IF_VARTYPES) & ~IF_VECTOR) {
841 case IF_FLAG:
842 fprintf(cp_out, " %d", val.iValue);
843 break;
844 case IF_INTEGER:
845 fprintf(cp_out, " %d", val.iValue);
846 break;
847 case IF_REAL:
848 fprintf(cp_out, " %.6g", val.rValue);
849 break;
850 case IF_COMPLEX:
851 if (i % 2)
852 fprintf(cp_out, " %.6g", val.cValue.real);
853 else
854 fprintf(cp_out, " %.6g", val.cValue.imag);
855 break;
856 case IF_STRING:
857 fprintf(cp_out, " %s", val.sValue);
858 break;
859 case IF_INSTANCE:
860 fprintf(cp_out, " %s", val.uValue);
861 break;
862 default:
863 fprintf(cp_out, " %s", " ******** ");
864 }
865 }
866
867 return n - 1;
868 }
869
870
871 int
printvals_old(dgen * dg,IFparm * p,int i)872 printvals_old(dgen *dg, IFparm *p, int i)
873 {
874 IFvalue val;
875 int n, error;
876
877 if (dg->flags & DGEN_INSTANCE)
878 error = ft_sim->askInstanceQuest
879 (ft_curckt->ci_ckt, dg->instance, p->id, &val, &val);
880 else
881 error = ft_sim->askModelQuest
882 (ft_curckt->ci_ckt, dg->model, p->id, &val, &val);
883
884 if (p->dataType & IF_VECTOR)
885 n = val.v.numValue;
886 else
887 n = 1;
888
889 if (((p->dataType & IF_VARTYPES) & ~IF_VECTOR) == IF_COMPLEX)
890 n *= 2;
891
892 if (i >= n) {
893 if (i == 0)
894 fprintf(cp_out, " -");
895 else
896 fprintf(cp_out, " ");
897 return 0;
898 }
899
900 if (error) {
901 fprintf(cp_out, " <<NAN, error = %d>>", error);
902 } else if (p->dataType & IF_VECTOR) {
903 /* va: ' ' is no flag for %s */
904 switch ((p->dataType & IF_VARTYPES) & ~IF_VECTOR) {
905 case IF_FLAG:
906 fprintf(cp_out, " % *d", DEV_WIDTH, val.v.vec.iVec[i]);
907 break;
908 case IF_INTEGER:
909 fprintf(cp_out, " % *d", DEV_WIDTH, val.v.vec.iVec[i]);
910 break;
911 case IF_REAL:
912 fprintf(cp_out, " % *.6g", DEV_WIDTH, val.v.vec.rVec[i]);
913 break;
914 case IF_COMPLEX:
915 if (!(i % 2))
916 fprintf(cp_out, " % *.6g", DEV_WIDTH, val.v.vec.cVec[i / 2].real);
917 else
918 fprintf(cp_out, " % *.6g", DEV_WIDTH, val.v.vec.cVec[i / 2].imag);
919 break;
920 case IF_STRING:
921 fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, val.v.vec.sVec[i]);
922 break;
923 case IF_INSTANCE:
924 fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, val.v.vec.uVec[i]);
925 break;
926 default:
927 fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, " ******** ");
928 }
929 } else {
930 switch ((p->dataType & IF_VARTYPES) & ~IF_VECTOR) {
931 case IF_FLAG:
932 fprintf(cp_out, " % *d", DEV_WIDTH, val.iValue);
933 break;
934 case IF_INTEGER:
935 fprintf(cp_out, " % *d", DEV_WIDTH, val.iValue);
936 break;
937 case IF_REAL:
938 fprintf(cp_out, " % *.6g", DEV_WIDTH, val.rValue);
939 break;
940 case IF_COMPLEX:
941 if (i % 2)
942 fprintf(cp_out, " % *.6g", DEV_WIDTH, val.cValue.real);
943 else
944 fprintf(cp_out, " % *.6g", DEV_WIDTH, val.cValue.imag);
945 break;
946 case IF_STRING:
947 fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, val.sValue);
948 break;
949 case IF_INSTANCE:
950 fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, val.uValue);
951 break;
952 default:
953 fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, " ******** ");
954 }
955 }
956
957 return n - 1;
958 }
959
960
961 /*
962 * (old "show" command)
963 * Display various device parameters. The syntax of this command is
964 * show devicelist : parmlist
965 * where devicelist can be "all", the name of a device, a string like r*,
966 * which means all devices with names that begin with 'r', repeated one
967 * or more times. The parms are names of parameters that are (hopefully)
968 * valid for all the named devices, or "all".
969 */
970
971 void
old_show(wordlist * wl)972 old_show(wordlist *wl)
973 {
974 wordlist *devs, *parms, *tw, *ww;
975 struct variable *v;
976 char *nn;
977
978 devs = wl;
979 wl = wl_find(":", wl);
980 if (!wl) {
981 parms = NULL;
982 } else {
983 if (wl->wl_prev)
984 wl->wl_prev->wl_next = NULL;
985 parms = wl->wl_next;
986 if (parms)
987 parms->wl_prev = NULL;
988 }
989
990 /* Now expand the devicelist... */
991 for (tw = NULL; devs; devs = devs->wl_next) {
992 inp_casefix(devs->wl_word);
993 tw = wl_append(tw, devexpand(devs->wl_word));
994 }
995
996 devs = tw;
997 tw = wl_find("all", parms);
998 if (tw)
999 parms = NULL;
1000
1001 /* This is a crock... */
1002 if (!devs)
1003 devs = cp_cctowl(ft_curckt->ci_devices);
1004
1005 out_init();
1006
1007 while (devs) {
1008 out_printf("%s:\n", devs->wl_word);
1009 if (parms) {
1010 for (tw = parms; tw; tw = tw->wl_next) {
1011 nn = copy(devs->wl_word);
1012 v = if_getparam(ft_curckt->ci_ckt, &nn, tw->wl_word, 0, 0);
1013 if (!v)
1014 v = if_getparam(ft_curckt->ci_ckt, &nn, tw->wl_word, 0, 1);
1015 if (v) {
1016 out_printf("\t%s =", tw->wl_word);
1017 for (ww = cp_varwl(v); ww; ww = ww->wl_next)
1018 out_printf(" %s", ww->wl_word);
1019 out_send("\n");
1020 }
1021 }
1022 } else {
1023 nn = copy(devs->wl_word);
1024 v = if_getparam(ft_curckt->ci_ckt, &nn, "all", 0, 0);
1025 if (!v)
1026 v = if_getparam(ft_curckt->ci_ckt, &nn, "all", 0, 1);
1027 while (v) {
1028 out_printf("\t%s =", v->va_name);
1029 for (ww = cp_varwl(v); ww; ww = ww->wl_next)
1030 out_printf(" %s", ww->wl_word);
1031 out_send("\n");
1032 v = v->va_next;
1033 }
1034 }
1035 devs = devs->wl_next;
1036 }
1037 }
1038
1039
1040 /*
1041 * Alter a device parameter. The new syntax here is
1042 * alter @device[parameter] = expr
1043 * alter device = expr
1044 * alter device parameter = expr
1045 * expr must be real (complex isn't handled right now, integer is fine though,
1046 * but no strings ... for booleans, use 0/1).
1047 */
1048
1049 static void com_alter_common(wordlist *wl, int do_model);
1050
1051 void
com_alter(wordlist * wl)1052 com_alter(wordlist *wl)
1053 {
1054 if (!wl) {
1055 fprintf(cp_err, "usage: alter dev param = expression\n");
1056 fprintf(cp_err, " or alter @dev[param] = expression\n");
1057 fprintf(cp_err, " or alter dev = expression\n");
1058 return;
1059 }
1060
1061 com_alter_common(wl, 0);
1062 }
1063
1064
1065 void
com_altermod(wordlist * wl)1066 com_altermod(wordlist *wl)
1067 {
1068 wordlist *fileword;
1069 bool newfile = FALSE;
1070
1071 fileword = wl;
1072 while (fileword) {
1073 if (ciprefix("file", fileword->wl_word))
1074 newfile = TRUE;
1075 fileword = fileword->wl_next;
1076 }
1077
1078 if (newfile)
1079 com_alter_mod(wl);
1080 else
1081 com_alter_common(wl, 1);
1082 }
1083
1084
1085 static void
if_set_binned_model(CKTcircuit * ckt,char * devname,char * param,struct dvec * val)1086 if_set_binned_model(CKTcircuit *ckt, char *devname, char *param, struct dvec *val)
1087 {
1088 char *width_length;
1089 double w = 0.0, l = 0.0;
1090 struct variable *v;
1091
1092 v = if_getparam(ckt, &devname, "w", 0, 0);
1093 if (!v) {
1094 fprintf(cp_err, "Error: Can't access width instance parameter.\n");
1095 return;
1096 }
1097 w = v->va_V.vV_real;
1098 free_struct_variable(v);
1099
1100 v = if_getparam(ckt, &devname, "l", 0, 0);
1101 if (!v) {
1102 fprintf(cp_err, "Error: Can't access length instance parameter.\n");
1103 return;
1104 }
1105 l = v->va_V.vV_real;
1106 free_struct_variable(v);
1107
1108 if (param[0] == 'w')
1109 w = *val->v_realdata; /* overwrite the width with the alter param */
1110 else
1111 l = *val->v_realdata; /* overwrite the length with the alter param */
1112
1113 width_length = tprintf("w=%15.7e l=%15.7e", w, l);
1114
1115 if_setparam_model(ft_curckt->ci_ckt, &devname, width_length);
1116 FREE(width_length);
1117 }
1118
1119
1120 static void
com_alter_common(wordlist * wl,int do_model)1121 com_alter_common(wordlist *wl, int do_model)
1122 {
1123 wordlist *wl_head = wl;
1124 wordlist *eqword, *words;
1125 char *dev, *param;
1126 struct dvec *dv;
1127 struct pnode *names;
1128
1129 int i;
1130
1131 if (!ft_curckt) {
1132 fprintf(cp_err, "Error: no circuit loaded\n");
1133 return;
1134 }
1135
1136 /*
1137 * when the assignment operator '=' is embedded in a wl_word
1138 * then split the word into several words
1139 *
1140 * Spaces around the '=' sign have to be removed. This is provided
1141 * by inp_remove_excess_ws(). But take care if command is entered manually!
1142 */
1143 for (; wl; wl = wl->wl_next) {
1144 char *argument = wl->wl_word;
1145 char *eqptr = strchr(argument, '=');
1146 if (eqptr) {
1147 if (strlen(argument) > 1) {
1148 wordlist *wn = NULL;
1149 if (eqptr[1])
1150 wn = wl_cons(copy(eqptr + 1), wn);
1151 wn = wl_cons(copy("="), wn);
1152 if (eqptr > argument)
1153 wn = wl_cons(copy_substring(argument, eqptr), wn);
1154 wl_splice(wl, wn);
1155 if (wl_head == wl)
1156 wl_head = wn;
1157 }
1158 break;
1159 }
1160 }
1161
1162 if (!wl) {
1163 /* no equal sign found, probably a pre3f4 input format
1164 * 'alter device value'
1165 * 'alter device parameter value'
1166 * are supported,
1167 * 'alter device parameter value parameter value [ parameter value ]'
1168 * with multiple param value pairs are not supported!
1169 */
1170 wordlist *wlin = wl_head;
1171 int wlen = wl_length(wlin);
1172 int maxelem = 3;
1173 /* Return the last element of wlin */
1174 wlin = wl_nthelem(100, wlin); /* no more than 100 vector elements */
1175
1176 if (eq(wlin->wl_word, "]")) /* we have a vector */
1177 for (i = 0; i < 100; i++) { /* no more than 100 vector elements */
1178 wlin = wlin->wl_prev;
1179 maxelem++;
1180 if (eq(wlin->wl_word, "["))
1181 break;
1182 if (wlin->wl_prev == NULL) {
1183 fprintf(cp_err, "Error: '[' is missing.\n");
1184 fprintf(cp_err, "Cannot alter parameters.\n");
1185 return;
1186 }
1187 }
1188
1189 if (wlen > maxelem) {
1190 fprintf(cp_err, "Error: Only a single param - value pair supported.\n");
1191 fprintf(cp_err, "Cannot alter parameters.\n");
1192 return;
1193 }
1194 /* add the '=' */
1195 wlin = wlin->wl_prev;
1196 wlin = wl_append(wlin, wl_cons(copy("="), wl_chop_rest(wlin)));
1197 }
1198
1199 wl = wl_head;
1200
1201 /* Everything is ready, parsing of the wordlist starts here. */
1202 eqword = wl_find("=", wl);
1203 if (!eqword || !eqword->wl_next) {
1204 fprintf(cp_err, "Error: no assignment found.\n");
1205 fprintf(cp_err, "Cannot alter parameters.\n");
1206 return;
1207 }
1208
1209 /*
1210 * device parameter = expr
1211 * device = expr
1212 * @dev[param] = expr
1213 */
1214
1215 dev = NULL;
1216 param = NULL;
1217 words = wl;
1218 while (words != eqword) {
1219 char *p = words->wl_word;
1220 if (param) {
1221 fprintf(cp_err, "Warning: excess parameter name \"%s\" ignored.\n", p);
1222 } else if (dev) {
1223 param = words->wl_word;
1224 } else if (*p == '@' || *p == '#') {
1225 dev = p + 1;
1226 p = strchr(p, '[');
1227 if (p) {
1228 *p++ = '\0';
1229 param = p;
1230 p = strchr(p, ']');
1231 if (p)
1232 *p = '\0';
1233 }
1234 } else {
1235 dev = p;
1236 }
1237 words = words->wl_next;
1238 }
1239
1240 if (!dev) {
1241 fprintf(cp_err, "Error: no model or device name provided.\n");
1242 fprintf(cp_err, "Cannot alter parameters.\n");
1243 return;
1244 }
1245
1246 /* in case the altermod command comes from commandline or
1247 over shared library we have to provide lowercase */
1248 strtolower(param);
1249 strtolower(dev);
1250
1251 words = eqword->wl_next;
1252 /* skip next line if words is a vector */
1253 if (!eq(words->wl_word, "["))
1254 names = ft_getpnames(words, FALSE);
1255 else
1256 names = NULL;
1257
1258 if (!names) {
1259 /* Put this to try to resolve the case of
1260 * alter @vin[pulse] = [ 0 5 10n 10n 10n 50n 100n ]
1261 */
1262 char *xsbuf, *rem_xsbuf;
1263
1264 double *list;
1265 double tmp;
1266 int error;
1267 /* move beyond '[' to allow INPevaluate() */
1268 if (eq(words->wl_word, "["))
1269 words = words->wl_next;
1270 xsbuf = rem_xsbuf = wl_flatten(words);
1271 /* fprintf(cp_err, "Chain converted %s \n", xsbuf); */
1272
1273 for (i = 0, list = NULL;;) {
1274 tmp = INPevaluate(&xsbuf, &error, 1);
1275 if (error)
1276 break;
1277 /* printf(" returning vector value %g\n", tmp); */
1278 list = TREALLOC(double, list, i + 1);
1279 list[i++] = tmp;
1280 }
1281
1282 if (i < 1) {
1283 fprintf(cp_err, "Error: cannot evaluate new parameter value.\n");
1284 return;
1285 }
1286
1287 dv = dvec_alloc(copy("real vector"),
1288 SV_NOTYPE,
1289 VF_REAL,
1290 i, list);
1291 if (!dv)
1292 return;
1293
1294 /* Here I was, to change the inclusion in the circuit.
1295 * will have to revise that dv is right for its insertion.
1296 */
1297 if_setparam(ft_curckt->ci_ckt, &dev, param, dv, do_model);
1298
1299 tfree(rem_xsbuf);
1300 vec_free(dv);
1301 return;
1302 }
1303
1304 dv = ft_evaluate(names);
1305 if (!dv)
1306 goto done;
1307
1308 if (dv->v_length < 1) {
1309 fprintf(cp_err, "Error: cannot evaluate new parameter value.\n");
1310 goto done;
1311 }
1312
1313 /* If we want alter the geometry of a MOS device
1314 we have to ensure that we are in the valid model bin. */
1315 if ((dev[0] == 'm') && (eq(param, "w") || eq(param, "l")))
1316 if_set_binned_model(ft_curckt->ci_ckt, dev, param, dv);
1317
1318 if_setparam(ft_curckt->ci_ckt, &dev, param, dv, do_model);
1319
1320 done:
1321 /* va: garbage collection for dv, if pnode names is no simple value */
1322 if (names && !names->pn_value && dv)
1323 vec_free(dv);
1324 free_pnode(names); /* free also dv, if pnode names is simple value */
1325 }
1326
1327
1328 /* Given a device name, possibly with wildcards, return the matches. */
1329
1330 static wordlist *
devexpand(char * name)1331 devexpand(char *name)
1332 {
1333 wordlist *wl, *devices;
1334
1335 if (strchr(name, '*') || strchr(name, '[') || strchr(name, '?')) {
1336 devices = cp_cctowl(ft_curckt->ci_devices);
1337 for (wl = NULL; devices; devices = devices->wl_next)
1338 if (!strcmp(name, devices->wl_word))
1339 wl = wl_cons(devices->wl_word, wl);
1340 } else if (cieq(name, "all")) {
1341 wl = cp_cctowl(ft_curckt->ci_devices);
1342 } else {
1343 wl = wl_cons(name, NULL);
1344 }
1345
1346 wl_sort(wl);
1347 return wl;
1348 }
1349
1350
1351 /* altermod mod_1 [mod_nn] file=modelparam.mod
1352 load model file and overwrite models mod_1 till mod_nn with
1353 all new parameters (limited to 16 models) */
1354
1355 static void
com_alter_mod(wordlist * wl)1356 com_alter_mod(wordlist *wl)
1357 {
1358 #define MODLIM 16 /* max number of models */
1359 FILE *modfile;
1360 char *modellist[MODLIM] = {NULL}, *modellines[MODLIM] = {NULL}, *newmodelname, *newmodelline;
1361 char *filename = NULL, *eqword, *input, *modelline = NULL, *inptoken;
1362 int modno = 0, molineno = 0, i, j;
1363 wordlist *newcommand;
1364 struct card *modeldeck, *tmpdeck;
1365 char *readmode = "r";
1366 char **arglist;
1367 bool modelfound = FALSE;
1368 int ij[MODLIM];
1369
1370 /* initialize */
1371 for (i = 0; i < MODLIM; i++)
1372 ij[i] = -1;
1373
1374 /* read all model names */
1375 while (!ciprefix("file", wl->wl_word)) {
1376 if (modno == MODLIM) {
1377 fprintf(cp_err, "Error: too many model names in altermod command\n");
1378 controlled_exit(1);
1379 }
1380 modellist[modno] = copy(wl->wl_word);
1381 modno++;
1382 wl = wl->wl_next;
1383 }
1384 input = wl_flatten(wl);
1385 /* get the file name */
1386 eqword = strchr(input, '=');
1387 if (eqword) {
1388 eqword++;
1389 while (*eqword == ' ')
1390 eqword++;
1391 if (*eqword == '\0') {
1392 fprintf(cp_err, "Error: no filename given\n");
1393 controlled_exit(1);
1394 }
1395 filename = copy(eqword);
1396 } else {
1397 eqword = strstr(input, "file");
1398 eqword += 4;
1399 while (*eqword == ' ')
1400 eqword++;
1401 if (*eqword == '\0') {
1402 fprintf(cp_err, "Error: no filename given\n");
1403 controlled_exit(1);
1404 }
1405 filename = copy(eqword);
1406 }
1407
1408 modfile = inp_pathopen(filename, readmode);
1409
1410 if (modfile == NULL) {
1411 fprintf(cp_err, "Warning: Could not open file %s, altermod ignored\n", filename);
1412 tfree(input);
1413 tfree(filename);
1414 return;
1415 }
1416 {
1417 char *dir_name = ngdirname(filename);
1418 modeldeck = inp_readall(modfile, dir_name, 0, 0, NULL);
1419 tfree(dir_name);
1420 }
1421 tfree(input);
1422 tfree(filename);
1423 /* get all lines starting with *model */
1424 for (tmpdeck = modeldeck; tmpdeck; tmpdeck = tmpdeck->nextcard)
1425 /* We are looking for *model because the input paerser has
1426 invalidated all unused models by replacing '.' by '*'. */
1427 if (ciprefix("*model", tmpdeck->line)) {
1428 if (molineno == MODLIM) {
1429 fprintf(cp_err, "Error: more than %d models in deck, rest ignored\n", molineno);
1430 break;
1431 }
1432 modellines[molineno] = tmpdeck->line;
1433 molineno++;
1434 }
1435 /* Check if all models named in altermod command are to be found in input deck.
1436 Exit if not successfull */
1437 for (i = 0; i < modno; i++) {
1438 for (j = 0; j < molineno; j++) {
1439 newmodelline = modellines[j];
1440 /* get model name from model line */
1441 inptoken = gettok(&newmodelline); /* *model */
1442 tfree(inptoken);
1443 newmodelname = gettok(&newmodelline); /* modelname */
1444 if (cieq(newmodelname, modellist[i])) {
1445 modelfound = TRUE;
1446 tfree(newmodelname);
1447 break;
1448 }
1449 tfree(newmodelname);
1450 }
1451 if (modelfound) {
1452 modelfound = FALSE;
1453 ij[i] = j; /* model in altermod, found in model line */
1454 continue;
1455 } else {
1456 fprintf(cp_err, "Error: could not find model %s in input deck\n", modellist[i]);
1457 controlled_exit(1);
1458 }
1459 }
1460 /* read the model line, generate the altermod commands as a wordlist,
1461 and call com_alter_common() */
1462 arglist = TMALLOC(char *, 4);
1463 arglist[0] = copy("altermod");
1464 arglist[3] = NULL;
1465 /* for each model name of altermod command */
1466 for (i = 0; i < modno; i++) {
1467 /* model name */
1468 arglist[1] = copy(modellist[i]);
1469 /* parse model line from deck */
1470 modelline = modellines[ij[i]];
1471 inptoken = gettok(&modelline); /* skip *model */
1472 tfree(inptoken);
1473 inptoken = gettok(&modelline); /* skip modelname */
1474 tfree(inptoken);
1475 inptoken = gettok(&modelline); /* skip model type */
1476 tfree(inptoken);
1477 while ((inptoken = gettok_node(&modelline)) != NULL) {
1478 /* exclude level, version and mfg */
1479 if (ciprefix("version", inptoken) || ciprefix("level", inptoken) ||
1480 ciprefix("mfg", inptoken)) {
1481 tfree(inptoken);
1482 continue;
1483 }
1484 arglist[2] = inptoken;
1485 /* create a new wordlist from array arglist */
1486 newcommand = wl_build((const char * const *) arglist);
1487 com_alter_common(newcommand->wl_next, 1);
1488 wl_free(newcommand);
1489 tfree(inptoken);
1490 }
1491 tfree(arglist[1]);
1492 }
1493 tfree(arglist[0]);
1494 tfree(arglist[3]);
1495 }
1496
1497
1498 #ifdef HAVE_TSEARCH
1499
1500 #include <search.h>
1501
1502 static int
check_ifparm_compare(const void * a,const void * b)1503 check_ifparm_compare(const void *a, const void *b)
1504 {
1505 IFparm *pa = (IFparm *) a;
1506 IFparm *pb = (IFparm *) b;
1507 return pa->id - pb->id;
1508 }
1509
1510
1511 static void
check_ifparm_freenode(void * node)1512 check_ifparm_freenode(void *node)
1513 {
1514 NG_IGNORE(node);
1515 }
1516
1517
1518 static void
check_ifparm(IFdevice * device,int instance_flag)1519 check_ifparm(IFdevice *device, int instance_flag)
1520 {
1521 int i, xcount;
1522 IFparm *plist;
1523
1524 if (instance_flag) {
1525 plist = device->instanceParms;
1526 if (!plist)
1527 return;
1528 fprintf(stderr, " checking %s instanceParams\n", device->name);
1529 xcount = *device->numInstanceParms;
1530 } else {
1531 plist = device->modelParms;
1532 if (!plist)
1533 return;
1534 fprintf(stderr, " checking %s modelParams\n", device->name);
1535 xcount = *device->numModelParms;
1536 }
1537
1538 void *root = NULL;
1539
1540 for (i = 0; i < xcount; i++) {
1541
1542 IFparm *psearch = *(IFparm **) tsearch(plist + i, &root,
1543 check_ifparm_compare);
1544
1545 int type_err = (psearch->dataType ^ plist[i].dataType) & ~IF_REDUNDANT;
1546 if (type_err)
1547 fprintf(stderr,
1548 " ERROR, dataType mismatch \"%s\" \"%s\" %08x\n",
1549 psearch->keyword, plist[i].keyword, type_err);
1550
1551 if ((plist[i].dataType & IF_REDUNDANT) &&
1552 (i == 0 || plist[i-1].id != plist[i].id)) {
1553 fprintf(stderr,
1554 "ERROR, alias \"%s\" has non matching predecessor \"%s\"\n",
1555 plist[i].keyword, plist[i-1].keyword);
1556 }
1557
1558 if (i == 0)
1559 continue;
1560
1561 if (plist[i-1].id != plist[i].id) {
1562 if (psearch != plist + i)
1563 fprintf(stderr,
1564 "ERROR: non neighbored duplicate id: \"%s\" \"%s\"\n",
1565 psearch->keyword, plist[i].keyword);
1566 } else if (!(plist[i].dataType & IF_REDUNDANT)) {
1567 fprintf(stderr,
1568 "ERROR: non R duplicate id: \"%s\" \"%s\"\n",
1569 plist[i-1].keyword, plist[i].keyword);
1570 }
1571 }
1572
1573 #ifdef HAVE_TDESTROY
1574 tdestroy (root, check_ifparm_freenode);
1575 #endif
1576 }
1577
1578
1579 void
com_check_ifparm(wordlist * wl)1580 com_check_ifparm(wordlist *wl)
1581 {
1582 NG_IGNORE(wl);
1583
1584 int k;
1585
1586 for (k = 0; k < ft_sim->numDevices; k++)
1587 if (ft_sim->devices[k]) {
1588 check_ifparm(ft_sim->devices[k], 0);
1589 check_ifparm(ft_sim->devices[k], 1);
1590 }
1591 }
1592
1593 #endif
1594