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