1 #include "ngspice/ngspice.h"
2 #include "ngspice/ifsim.h"
3 #include "ngspice/gendefs.h"
4 #include "ngspice/cktdefs.h"
5 #include "ngspice/cpstd.h"
6 #include "ngspice/ftedefs.h"
7 #include "ngspice/fteext.h"
8 #include "ngspice/devdefs.h"
9 #include "ngspice/dgen.h"
10 #include "gens.h"
11 
12 
13 static void dgen_next(dgen **dgx);
14 
15 
16 void
wl_forall(wordlist * wl,void (* fn)(wordlist *,dgen *),dgen * data)17 wl_forall(wordlist *wl, void (*fn)(wordlist*, dgen*), dgen *data)
18 {
19     while (wl) {
20         fn (wl, data);
21         wl = wl->wl_next;
22     }
23 }
24 
25 
26 dgen *
dgen_init(CKTcircuit * ckt,wordlist * wl,int nomix,int flag,int model)27 dgen_init(CKTcircuit *ckt, wordlist *wl, int nomix, int flag, int model)
28 {
29     dgen  *dg, *dg_save;
30 
31     NG_IGNORE(nomix);
32 
33     dg = TMALLOC(dgen, 1);
34     dg->ckt = ckt;
35     dg->instance = NULL;
36     dg->model = NULL;
37     dg->dev_type_no = -1;
38     dg->dev_list = wl;
39     dg->flags = 0;
40     dg_save = dg; /* va: save, to avoid memory leak */
41 
42     if (model)
43         dg->flags = (DGEN_ALL & ~ DGEN_INSTANCE) | DGEN_INIT;
44     else
45         dg->flags = DGEN_ALL | DGEN_INIT;
46 
47     if (wl)
48         dg->flags |= flag;
49     else
50         dg->flags |= DGEN_DEFDEVS | flag;
51 
52     dgen_next(&dg);
53     /* va: it might be too much tests, but safer is better... */
54     if (dg != dg_save && dg == NULL && dg_save != NULL)
55         tfree(dg_save);
56 
57     return dg;
58 }
59 
60 
61 int
dgen_for_n(dgen * dg,int n,int (* fn)(dgen *,IFparm *,int),IFparm * data,int subindex)62 dgen_for_n(dgen *dg, int n, int (*fn) (dgen*, IFparm*, int), IFparm *data, int subindex)
63 {
64     dgen  dgx, *dgxp;
65     int   dnum, i, j, k;
66 
67     dgxp = &dgx;
68     memcpy(dgxp, dg, sizeof(dgx)); /* va: compatible pointer types */
69 
70     dnum = dgxp->dev_type_no;
71 
72     k = 0;
73     for (i = 0; dgxp && dgxp->dev_type_no == dnum && i < n; i++) {
74         /*printf("Loop at %d\n", i);*/
75         j = fn (dgxp, data, subindex);
76         if (j > k)
77             k = j;
78         dgen_next(&dgxp);
79     }
80 
81     return k - subindex;
82 }
83 
84 
85 void
dgen_nth_next(dgen ** p_dg,int n)86 dgen_nth_next(dgen **p_dg, int n)
87 {
88     int    i, dnum;
89     dgen  *dg_save = *p_dg; /* va: save, to avoid memory leak */
90 
91     dnum = (*p_dg)->dev_type_no;
92 
93     for (i = 0; *p_dg && (*p_dg)->dev_type_no == dnum && i < n; i++) {
94         dgen_next(p_dg);
95         /* va: it might be too much tests, but safer is better... */
96         if (*p_dg != dg_save && *p_dg == NULL && dg_save != NULL)
97             tfree(dg_save);
98     }
99 }
100 
101 
102 static void
dgen_next(dgen ** dgx)103 dgen_next(dgen **dgx)
104 {
105     int     done;
106     dgen    *dg;
107     char    *p;
108     int     need;
109     wordlist *w;
110     char    type, *subckt, *device, *model;
111     char    *Top_Level = "\001";
112     int     subckt_len;
113     int     head_match;
114     char    *word, *dev_name, *mod_name;
115 
116     dg = *dgx;
117     if (!dg)
118         return;
119 
120     /* Prime the "model only" or "device type only" iteration,
121      * required because the filtering (below) may request additional
122      * detail.
123      */
124     if (!(dg->flags & DGEN_INSTANCE)) {
125         if (!(dg->flags & DGEN_MODEL))
126             dg->model = NULL;
127         dg->instance = NULL;
128     }
129 
130     need = dg->flags;
131     done = 0;
132 
133     while (!done) {
134 
135         if (dg->instance) {
136             /* next instance */
137             dg->instance = dg->instance->GENnextInstance;
138         } else if (dg->model) {
139             dg->model = dg->model->GENnextModel;
140             if (dg->model)
141                 dg->instance = dg->model->GENinstances;
142         } else if (dg->dev_type_no < DEVmaxnum) {
143             dg->dev_type_no += 1;
144             if (dg->dev_type_no < DEVmaxnum) {
145                 dg->model = dg->ckt->CKThead[dg->dev_type_no];
146                 if (dg->model)
147                     dg->instance = dg->model->GENinstances;
148             } else {
149                 done = 2;
150                 break;
151             }
152         } else {
153             done = 2;
154             break;
155         }
156 
157         if (need & DGEN_INSTANCE && !dg->instance)
158             continue;
159         if (need & DGEN_MODEL && !dg->model)
160             continue;
161 
162         /* Filter */
163         if (!dg->dev_list) {
164             if ((dg->flags & DGEN_ALLDEVS) ||
165                 ((dg->flags & DGEN_DEFDEVS) &&
166                  (ft_sim->devices[dg->dev_type_no]->flags & DEV_DEFAULT)))
167             {
168                 done = 1;
169             } else {
170                 done = 0;
171             }
172             continue;
173         }
174 
175         done = 0;
176 
177         for (w = dg->dev_list; w && !done; w = w->wl_next) {
178 
179             /* assume a match (have to reset done every time
180              * through
181              */
182             done = 1;
183             word = w->wl_word;
184 
185             if (!word || !*word) {
186                 break;
187             }
188 
189             /* Break up word into type, subcircuit, model, device,
190              * must be nodestructive to "word"
191              */
192 
193             /* type */
194             if (*word == ':' || *word == '#')
195                 type = '\0';
196             else
197                 type = *word++;
198 
199             /* subcircuit */
200 
201             subckt = word;
202             /* look for last ":" or "#" in word */
203             for (p = word + strlen(word) /* do '\0' first time */;
204                  p != word && *p != ':' && *p != '#'; p--)
205             {
206                 ;
207             }
208 
209             if (*p != ':' && *p != '#') {
210                 /* No subcircuit name specified */
211                 subckt = NULL;
212                 subckt_len = 0;
213             } else {
214 
215                 if (p[-1] == ':') {
216                     head_match = 1;
217                     subckt_len = (int)(p - word) - 1;
218                 } else {
219                     head_match = 0;
220                     subckt_len = (int)(p - word);
221                 }
222 
223                 if (subckt_len == 0) {
224                     /* Top level only */
225                     if (head_match)
226                         subckt = NULL;
227                     else
228                         subckt = Top_Level;
229                 }
230                 word = p + 1;
231             }
232 
233             /* model or device */
234 
235             if (*p == '#') {
236                 model = word;
237                 device = NULL;
238             } else {
239                 model = NULL;
240                 device = word;
241             }
242 
243             /* Now compare */
244             if (dg->instance)
245                 dev_name = dg->instance->GENname;
246             else
247                 dev_name = NULL;
248 
249             if (dg->model)
250                 mod_name = dg->model->GENmodName;
251             else
252                 mod_name = NULL;
253 
254             if (type) {
255                 if (!dev_name) {
256                     done = 0;
257                     /*printf("No device.\n");*/
258                     need |= DGEN_MODEL;
259                     continue;
260                 } else if (type != *dev_name) {
261                     done = 0;
262                     /*printf("Wrong type.\n");*/
263                     /* Bleh ... plan breaks down here */
264                     /* need = DGEN_TYPE; */
265                     continue;
266                 }
267             }
268 
269             if (subckt == Top_Level) {
270                 if (dev_name && dev_name[1] == ':') {
271                     need |= DGEN_INSTANCE;
272                     done = 0;
273                     /*printf("Wrong level.\n");*/
274                     continue;
275                 }
276             } else if (subckt && (!dev_name || !ciprefix(subckt, dev_name + 1))) {
277                 need |= DGEN_INSTANCE;
278                 done = 0;
279                 /*printf("Wrong subckt.\n"); */
280                 continue;
281             }
282 
283             if (device && *device) {
284                 need |= DGEN_INSTANCE | DGEN_MODEL;
285                 if (!dev_name) {
286                     done = 0;
287                     /*printf("Didn't get dev name.\n");*/
288                     continue;
289                 } else if (strcmp(device, dev_name + 1 + subckt_len)) {
290                     done = 0;
291                     /*printf("Wrong name.\n");*/
292                     continue;
293                 }
294             } else if (model && *model) {
295                 if (strcmp(model, mod_name)) {
296                     done = 0;
297                     need |= DGEN_MODEL;
298                     /*printf("Wrong model name.\n");*/
299                     continue;
300                 }
301             }
302 
303             break;
304         }
305 
306     }
307 
308     if (done == 2)
309         *dgx = NULL;
310 }
311